Skip to content

Commit b2f6ac7

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(planetscale): address integration validation findings
1 parent 5bd4b67 commit b2f6ac7

8 files changed

Lines changed: 168 additions & 91 deletions

File tree

‎apps/docs/content/docs/integrations/planetscale.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ Create a branch
183183
| `restorePoint` | string | No | Restore from a point-in-time recovery timestamp \(e.g. 2023-01-01T00:00:00Z\). Available only for PostgreSQL databases. |
184184
| `replicas` | number | No | For PostgreSQL backup restores and point-in-time recovery, the number of additional replicas from 0 to 8, subject to the target cluster size. 0 creates a single-node branch. If omitted, the target cluster size's minimum is used. |
185185
| `seedData` | string | No | If provided, restores the last successful backup's schema and data to the new branch. Must have `restore_production_branch_backup\(s\)` or `restore_backup\(s\)` access to do this, in addition to Data Branching™ being enabled for the branch. |
186-
| `clusterSize` | string | No | The database cluster size. Required if a backup_id is provided \(unless keyspace_cluster_sizes covers every keyspace\), optional otherwise. Options: PS_10, PS_20, PS_40, ..., PS_2800 |
186+
| `clusterSize` | string | No | The database cluster size. Required when backupId is provided, optional otherwise. Options: PS_10, PS_20, PS_40, ..., PS_2800 |
187187
| `majorVersion` | string | No | For PostgreSQL and Neki databases, the PostgreSQL major version to use for the branch. Defaults to the major version of the parent branch if it exists or the database's default branch major version. Ignored for branches restored from backups. |
188188

189189
#### Output

‎apps/sim/blocks/blocks/planetscale.ts‎

Lines changed: 119 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { PlanetScaleIcon } from '@/components/icons'
22
import { AuthMode, type BlockConfig, type BlockMeta, IntegrationType } from '@/blocks/types'
3-
import { PLANETSCALE_BLOCK_OUTPUTS } from '@/tools/planetscale/types'
43

54
function optionalBoolean(value: unknown): boolean | undefined {
65
if (value === undefined || value === null || value === '') return undefined
@@ -387,6 +386,13 @@ export const PlanetScaleBlock: BlockConfig = {
387386
condition: { field: 'operation', value: ['create_branch'] },
388387
required: false,
389388
mode: 'advanced',
389+
wandConfig: {
390+
enabled: true,
391+
generationType: 'timestamp',
392+
prompt:
393+
'Convert the described date and time to an ISO 8601 UTC timestamp such as 2023-01-01T00:00:00Z. Preserve existing workflow or environment references unchanged. Return ONLY the timestamp or reference.',
394+
placeholder: 'Describe the date and time',
395+
},
390396
},
391397
{
392398
id: 'replicas',
@@ -414,7 +420,7 @@ export const PlanetScaleBlock: BlockConfig = {
414420
type: 'short-input',
415421
condition: { field: 'operation', value: ['create_branch'] },
416422
required: false,
417-
mode: 'advanced',
423+
placeholder: 'Required for backup restores, e.g. PS_10',
418424
},
419425
{
420426
id: 'majorVersion',
@@ -545,6 +551,13 @@ export const PlanetScaleBlock: BlockConfig = {
545551
condition: { field: 'operation', value: ['list_backups'] },
546552
required: false,
547553
mode: 'advanced',
554+
wandConfig: {
555+
enabled: true,
556+
generationType: 'timestamp',
557+
prompt:
558+
'Convert the described date and time to an ISO 8601 UTC timestamp such as 2023-01-01T00:00:00Z. Preserve existing workflow or environment references unchanged. Return ONLY the timestamp or reference.',
559+
placeholder: 'Describe the date and time',
560+
},
548561
},
549562
{
550563
id: 'to',
@@ -553,6 +566,13 @@ export const PlanetScaleBlock: BlockConfig = {
553566
condition: { field: 'operation', value: ['list_backups'] },
554567
required: false,
555568
mode: 'advanced',
569+
wandConfig: {
570+
enabled: true,
571+
generationType: 'timestamp',
572+
prompt:
573+
'Convert the described date and time to an ISO 8601 UTC timestamp such as 2023-01-01T00:00:00Z. Preserve existing workflow or environment references unchanged. Return ONLY the timestamp or reference.',
574+
placeholder: 'Describe the date and time',
575+
},
556576
},
557577
{
558578
id: 'runningAt',
@@ -561,6 +581,13 @@ export const PlanetScaleBlock: BlockConfig = {
561581
condition: { field: 'operation', value: ['list_backups', 'list_deploy_requests'] },
562582
required: false,
563583
mode: 'advanced',
584+
wandConfig: {
585+
enabled: true,
586+
generationType: 'timestamp',
587+
prompt:
588+
'Convert the described time interval to two ISO 8601 UTC timestamps separated by .., such as 2023-01-01T00:00:00Z..2023-01-31T23:59:59Z. Preserve existing workflow or environment references unchanged. Return ONLY the start..end interval or reference.',
589+
placeholder: 'Describe the time interval',
590+
},
564591
},
565592
{
566593
id: 'retentionUnit',
@@ -635,6 +662,13 @@ export const PlanetScaleBlock: BlockConfig = {
635662
condition: { field: 'operation', value: ['list_deploy_requests'] },
636663
required: false,
637664
mode: 'advanced',
665+
wandConfig: {
666+
enabled: true,
667+
generationType: 'timestamp',
668+
prompt:
669+
'Convert the described time interval to two ISO 8601 UTC timestamps separated by .., such as 2023-01-01T00:00:00Z..2023-01-31T23:59:59Z. Preserve existing workflow or environment references unchanged. Return ONLY the start..end interval or reference.',
670+
placeholder: 'Describe the time interval',
671+
},
638672
},
639673
{
640674
id: 'notes',
@@ -760,7 +794,7 @@ export const PlanetScaleBlock: BlockConfig = {
760794
serviceTokenId: { type: 'string', description: 'Service token ID' },
761795
serviceToken: { type: 'string', description: 'Service token secret' },
762796
organization: { type: 'string', description: 'PlanetScale organization slug' },
763-
q: { type: 'string', description: 'Search branches by name' },
797+
q: { type: 'string', description: 'Search databases or branches by name' },
764798
page: {
765799
type: 'number',
766800
description: 'If provided, specifies the page offset of returned results',
@@ -779,7 +813,7 @@ export const PlanetScaleBlock: BlockConfig = {
779813
description: 'Filter branches by safe migrations (DDL protection)',
780814
},
781815
order: { type: 'string', description: 'Order branches by created_at time' },
782-
name: { type: 'string', description: 'Name for the backup' },
816+
name: { type: 'string', description: 'Name for the new branch or backup' },
783817
deletionProtected: {
784818
type: 'boolean',
785819
description: 'Whether deletion protection is enabled for the branch',
@@ -813,7 +847,7 @@ export const PlanetScaleBlock: BlockConfig = {
813847
clusterSize: {
814848
type: 'string',
815849
description:
816-
'The database cluster size. Required if a backup_id is provided (unless keyspace_cluster_sizes covers every keyspace), optional otherwise. Options: PS_10, PS_20, PS_40, ..., PS_2800',
850+
'The database cluster size. Required when backupId is provided, optional otherwise. Options: PS_10, PS_20, PS_40, ..., PS_2800',
817851
},
818852
majorVersion: {
819853
type: 'string',
@@ -842,7 +876,7 @@ export const PlanetScaleBlock: BlockConfig = {
842876
runningAt: {
843877
type: 'string',
844878
description:
845-
'Filter deploy requests by the date they were running. (e.g. 2023-01-01T00:00:00Z..2023-01-31T23:59:59Z)',
879+
'Filter backups or deploy requests by when they were running. (e.g. 2023-01-01T00:00:00Z..2023-01-31T23:59:59Z)',
846880
},
847881
retentionUnit: { type: 'string', description: 'Unit for the retention period of the backup' },
848882
retentionValue: {
@@ -936,7 +970,82 @@ export const PlanetScaleBlock: BlockConfig = {
936970
}),
937971
},
938972
},
939-
outputs: PLANETSCALE_BLOCK_OUTPUTS,
973+
outputs: {
974+
databases: {
975+
type: 'array',
976+
description:
977+
'Databases (id, name, kind, state, ready, defaultBranch, branchesCount, deletionProtected, requireApprovalForDeploy, createdAt, updatedAt, htmlUrl)',
978+
condition: { field: 'operation', value: ['list_databases'] },
979+
},
980+
database: {
981+
type: 'json',
982+
description:
983+
'Database (id, name, kind, state, ready, defaultBranch, branchesCount, deletionProtected, requireApprovalForDeploy, createdAt, updatedAt, htmlUrl)',
984+
condition: { field: 'operation', value: ['get_database'] },
985+
},
986+
branches: {
987+
type: 'array',
988+
description:
989+
'Branches (id, name, kind, state, ready, production, safeMigrations, deletionProtected, parentBranch, createdAt, updatedAt, htmlUrl)',
990+
condition: { field: 'operation', value: ['list_branches'] },
991+
},
992+
branch: {
993+
type: 'json',
994+
description:
995+
'Branch (id, name, kind, state, ready, production, safeMigrations, deletionProtected, parentBranch, createdAt, updatedAt, htmlUrl)',
996+
condition: { field: 'operation', value: ['get_branch', 'create_branch'] },
997+
},
998+
deleted: {
999+
type: 'boolean',
1000+
description: 'Whether the selected branch was deleted',
1001+
condition: { field: 'operation', value: ['delete_branch'] },
1002+
},
1003+
backups: {
1004+
type: 'array',
1005+
description:
1006+
'Backups (id, name, state, size, estimatedStorageCost, protected, createdAt, updatedAt, startedAt, completedAt, expiresAt)',
1007+
condition: { field: 'operation', value: ['list_backups'] },
1008+
},
1009+
backup: {
1010+
type: 'json',
1011+
description:
1012+
'Backup (id, name, state, size, estimatedStorageCost, protected, createdAt, updatedAt, startedAt, completedAt, expiresAt)',
1013+
condition: { field: 'operation', value: ['get_backup', 'create_backup'] },
1014+
},
1015+
deployRequests: {
1016+
type: 'array',
1017+
description:
1018+
'Vitess deploy requests (id, number, branch, intoBranch, state, deploymentState, approved, numComments, notes, createdAt, updatedAt, closedAt, deployedAt, htmlUrl)',
1019+
condition: { field: 'operation', value: ['list_deploy_requests'] },
1020+
},
1021+
deployRequest: {
1022+
type: 'json',
1023+
description:
1024+
'Vitess deploy request (id, number, branch, intoBranch, state, deploymentState, approved, numComments, notes, createdAt, updatedAt, closedAt, deployedAt, htmlUrl)',
1025+
condition: {
1026+
field: 'operation',
1027+
value: [
1028+
'get_deploy_request',
1029+
'create_deploy_request',
1030+
'queue_deploy_request',
1031+
'close_deploy_request',
1032+
],
1033+
},
1034+
},
1035+
review: {
1036+
type: 'json',
1037+
description: 'Deploy-request review (id, state, body, createdAt, updatedAt)',
1038+
condition: { field: 'operation', value: ['review_deploy_request'] },
1039+
},
1040+
pagination: {
1041+
type: 'json',
1042+
description: 'Pagination (currentPage, perPage, nextPage, totalCount, totalPages)',
1043+
condition: {
1044+
field: 'operation',
1045+
value: ['list_databases', 'list_branches', 'list_backups', 'list_deploy_requests'],
1046+
},
1047+
},
1048+
},
9401049
}
9411050
export const PlanetScaleBlockMeta = {
9421051
tags: ['cloud', 'ci-cd', 'automation'],
@@ -959,6 +1068,7 @@ export const PlanetScaleBlockMeta = {
9591068
modules: ['workflows'],
9601069
category: 'engineering',
9611070
tags: ['automation'],
1071+
alsoIntegrations: ['github'],
9621072
},
9631073
{
9641074
icon: PlanetScaleIcon,
@@ -986,6 +1096,7 @@ export const PlanetScaleBlockMeta = {
9861096
modules: ['workflows', 'scheduled'],
9871097
category: 'engineering',
9881098
tags: ['automation'],
1099+
alsoIntegrations: ['mysql', 'postgresql'],
9891100
},
9901101
{
9911102
icon: PlanetScaleIcon,
@@ -1004,6 +1115,7 @@ export const PlanetScaleBlockMeta = {
10041115
modules: ['workflows', 'scheduled'],
10051116
category: 'engineering',
10061117
tags: ['automation'],
1118+
alsoIntegrations: ['slack'],
10071119
},
10081120
{
10091121
icon: PlanetScaleIcon,

‎apps/sim/blocks/registry-maps.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,9 +618,9 @@ export const BLOCK_REGISTRY: Record<string, BlockConfig> = {
618618
persona: PersonaBlock,
619619
pi: PiBlock,
620620
pinecone: PineconeBlock,
621-
planetscale: PlanetScaleBlock,
622621
pipedrive: PipedriveBlock,
623622
pitchbook: PitchBookBlock,
623+
planetscale: PlanetScaleBlock,
624624
polymarket: PolymarketBlock,
625625
postgresql: PostgreSQLBlock,
626626
posthog: PostHogBlock,
@@ -950,9 +950,9 @@ export const BLOCK_META_REGISTRY: Record<string, BlockMeta> = {
950950
perplexity: PerplexityBlockMeta,
951951
persona: PersonaBlockMeta,
952952
pinecone: PineconeBlockMeta,
953-
planetscale: PlanetScaleBlockMeta,
954953
pipedrive: PipedriveBlockMeta,
955954
pitchbook: PitchBookBlockMeta,
955+
planetscale: PlanetScaleBlockMeta,
956956
polymarket: PolymarketBlockMeta,
957957
postgresql: PostgreSQLBlockMeta,
958958
posthog: PostHogBlockMeta,

‎apps/sim/tools/generated/tool-metadata.ts‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { planetScaleCreateBranchTool } from '@/tools/planetscale/create-branch'
3+
4+
describe('PlanetScale backup restores', () => {
5+
it.each([undefined, '', ' '])('rejects a restore without a cluster size: %j', (clusterSize) => {
6+
expect(() =>
7+
planetScaleCreateBranchTool.request.body!({
8+
serviceTokenId: 'test-id',
9+
serviceToken: 'test-secret',
10+
organization: 'example',
11+
database: 'test-db',
12+
name: 'restore-drill',
13+
backupId: 'backup-id',
14+
clusterSize,
15+
})
16+
).toThrow('clusterSize is required when restoring a backup')
17+
})
18+
})

‎apps/sim/tools/planetscale/create-branch.ts‎

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export const planetScaleCreateBranchTool: ToolConfig<
109109
required: false,
110110
visibility: 'user-or-llm',
111111
description:
112-
'The database cluster size. Required if a backup_id is provided (unless keyspace_cluster_sizes covers every keyspace), optional otherwise. Options: PS_10, PS_20, PS_40, ..., PS_2800',
112+
'The database cluster size. Required when backupId is provided, optional otherwise. Options: PS_10, PS_20, PS_40, ..., PS_2800',
113113
},
114114
majorVersion: {
115115
type: 'string',
@@ -127,22 +127,28 @@ export const planetScaleCreateBranchTool: ToolConfig<
127127
),
128128
method: 'POST',
129129
headers: planetScaleHeaders,
130-
body: (params) =>
131-
planetScaleBody({
130+
body: (params) => {
131+
const backupId = optionalPlanetScaleString(params.backupId, 'backupId')?.trim() || undefined
132+
const clusterSize =
133+
optionalPlanetScaleString(params.clusterSize, 'clusterSize')?.trim() || undefined
134+
if (backupId && !clusterSize)
135+
throw new Error('clusterSize is required when restoring a backup')
136+
return planetScaleBody({
132137
name: params.name,
133138
deletion_protected: optionalPlanetScaleBoolean(
134139
params.deletionProtected,
135140
'deletionProtected'
136141
),
137142
parent_branch: optionalPlanetScaleString(params.parentBranch, 'parentBranch'),
138-
backup_id: optionalPlanetScaleString(params.backupId, 'backupId'),
143+
backup_id: backupId,
139144
region: optionalPlanetScaleString(params.region, 'region'),
140145
restore_point: optionalPlanetScaleString(params.restorePoint, 'restorePoint'),
141146
replicas: optionalPlanetScaleInteger(params.replicas, 'replicas', 0, 8),
142147
seed_data: optionalPlanetScaleEnum(params.seedData, 'seedData', ['last_successful_backup']),
143-
cluster_size: optionalPlanetScaleString(params.clusterSize, 'clusterSize'),
148+
cluster_size: clusterSize,
144149
major_version: optionalPlanetScaleString(params.majorVersion, 'majorVersion'),
145-
}),
150+
})
151+
},
146152
},
147153
transformResponse: async (response) => ({
148154
success: true,

‎apps/sim/tools/planetscale/types.ts‎

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -363,62 +363,3 @@ export interface PlanetScaleCloseDeployRequestParams {
363363
export interface PlanetScaleToolResponse<T extends Record<string, unknown>> extends ToolResponse {
364364
output: T
365365
}
366-
367-
export const PLANETSCALE_BLOCK_OUTPUTS = {
368-
databases: {
369-
type: 'array',
370-
description: 'databases',
371-
items: { type: 'object', properties: PLANETSCALE_DATABASE_OUTPUT_PROPERTIES },
372-
optional: true,
373-
},
374-
database: {
375-
type: 'json',
376-
description: 'Database details',
377-
properties: PLANETSCALE_DATABASE_OUTPUT_PROPERTIES,
378-
optional: true,
379-
},
380-
branches: {
381-
type: 'array',
382-
description: 'branches',
383-
items: { type: 'object', properties: PLANETSCALE_BRANCH_OUTPUT_PROPERTIES },
384-
optional: true,
385-
},
386-
branch: {
387-
type: 'json',
388-
description: 'Branch details',
389-
properties: PLANETSCALE_BRANCH_OUTPUT_PROPERTIES,
390-
optional: true,
391-
},
392-
deleted: { type: 'boolean', description: 'Whether the branch was deleted', optional: true },
393-
backups: {
394-
type: 'array',
395-
description: 'backups',
396-
items: { type: 'object', properties: PLANETSCALE_BACKUP_OUTPUT_PROPERTIES },
397-
optional: true,
398-
},
399-
backup: {
400-
type: 'json',
401-
description: 'Backup details',
402-
properties: PLANETSCALE_BACKUP_OUTPUT_PROPERTIES,
403-
optional: true,
404-
},
405-
deployRequests: {
406-
type: 'array',
407-
description: 'deployRequests',
408-
items: { type: 'object', properties: PLANETSCALE_DEPLOYREQUEST_OUTPUT_PROPERTIES },
409-
optional: true,
410-
},
411-
deployRequest: {
412-
type: 'json',
413-
description: 'DeployRequest details',
414-
properties: PLANETSCALE_DEPLOYREQUEST_OUTPUT_PROPERTIES,
415-
optional: true,
416-
},
417-
review: {
418-
type: 'json',
419-
description: 'Review details',
420-
properties: PLANETSCALE_REVIEW_OUTPUT_PROPERTIES,
421-
optional: true,
422-
},
423-
pagination: { ...PLANETSCALE_PAGINATION_OUTPUT, optional: true },
424-
} satisfies Record<string, OutputProperty>

0 commit comments

Comments
 (0)