@noimosai/platform-mcp 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +17 -48
  2. package/bin/noimos-platform-mcp.mjs +4 -5
  3. package/dist/cli/cli.js +567 -0
  4. package/dist/cli/command-help.js +395 -0
  5. package/dist/cli/download.js +72 -0
  6. package/dist/cli/index.js +3 -0
  7. package/dist/cli/input-error.js +48 -0
  8. package/dist/cli/local-agents.js +199 -0
  9. package/dist/cli/mcp-supervisor.js +136 -0
  10. package/dist/cli/noimos-cli.js +72 -0
  11. package/dist/cli/project-archive.js +27 -0
  12. package/dist/cli/project-files.js +25 -0
  13. package/dist/cli/project-sync.js +259 -0
  14. package/dist/cli/setup-lock.js +1 -0
  15. package/dist/cli/setup.js +347 -0
  16. package/dist/cli/skills.js +142 -0
  17. package/dist/cli/team-harness-targets.js +337 -0
  18. package/dist/cli/team-harness.js +1562 -0
  19. package/dist/cli/team-resources.js +222 -0
  20. package/dist/cli/team-skills.js +457 -0
  21. package/dist/cli/update-bootstrap.js +437 -0
  22. package/dist/cli/update-release.js +212 -0
  23. package/dist/cli/version.js +1 -0
  24. package/dist/cli/wallet.js +85 -0
  25. package/dist/client/agent-run.js +1425 -0
  26. package/dist/client/browser.js +905 -0
  27. package/dist/client/distribution.js +2 -0
  28. package/dist/client/evm-wallet.js +214 -0
  29. package/dist/client/execution-context.js +14 -0
  30. package/dist/client/failure-recovery.js +128 -0
  31. package/dist/client/index.js +4 -225
  32. package/dist/client/local-input.js +33 -12
  33. package/dist/client/local-profile-lock.js +52 -0
  34. package/dist/client/local-profile.js +181 -0
  35. package/dist/client/local-projects.js +131 -0
  36. package/dist/client/local-setup.js +93 -0
  37. package/dist/client/realtime-voice.js +184 -0
  38. package/dist/client/tool-name-hints.js +48 -0
  39. package/dist/client/wallet-access.js +214 -0
  40. package/dist/mcp/agent-server.js +345 -0
  41. package/dist/mcp/context.js +86 -0
  42. package/dist/mcp/host-schema.js +76 -0
  43. package/dist/mcp/icon.js +1 -0
  44. package/dist/mcp/instructions.js +26 -0
  45. package/dist/mcp/local-projects.js +42 -0
  46. package/dist/mcp/local-upload.js +7 -13
  47. package/dist/mcp/noimos-runtime.js +18 -0
  48. package/dist/mcp/noimos-server.js +38 -0
  49. package/dist/mcp/operations.js +40 -0
  50. package/dist/mcp/parallel-result.js +17 -0
  51. package/dist/mcp/project-sync.js +105 -0
  52. package/dist/mcp/results-reply.js +15 -0
  53. package/dist/mcp/runtime.js +65 -11
  54. package/dist/mcp/server.js +382 -40
  55. package/dist/mcp/team-skill.js +63 -0
  56. package/dist/mcp/update-notice.js +75 -0
  57. package/dist/mcp/version.js +1 -0
  58. package/dist/schema/accountRequestMethods.js +1 -0
  59. package/dist/schema/boundedBody.js +30 -0
  60. package/dist/schema/cronValidator.js +150 -0
  61. package/dist/schema/platformApiKey.js +14 -0
  62. package/dist/schema/platformAppAuth.js +11 -0
  63. package/dist/schema/platformBillingConstants.js +4 -0
  64. package/dist/schema/platformCapabilityFamilies.js +293 -0
  65. package/dist/schema/platformConnectionCatalog.js +39 -0
  66. package/dist/schema/platformConnectionPolicy.js +33 -0
  67. package/dist/schema/platformCustomTools.js +148 -0
  68. package/dist/schema/platformEndUserApi.js +62 -0
  69. package/dist/schema/platformFunding.js +10 -0
  70. package/dist/schema/platformHttpConstraints.js +12 -0
  71. package/dist/schema/platformLocalSetup.js +25 -0
  72. package/dist/schema/platformMcpTools.js +7 -0
  73. package/dist/schema/platformMetaTools.js +63 -0
  74. package/dist/schema/platformMonitorSchedule.js +123 -0
  75. package/dist/schema/platformMonitors.js +159 -0
  76. package/dist/schema/platformOAuth.js +13 -0
  77. package/dist/schema/platformProjectPermissions.js +33 -0
  78. package/dist/schema/platformPublicExecution.js +202 -21
  79. package/dist/schema/platformRoutes.js +122 -0
  80. package/dist/schema/platformSkills.js +11 -0
  81. package/dist/schema/platformTeamSecretName.js +3 -0
  82. package/dist/schema/platformTeamSkillSlug.js +1 -0
  83. package/dist/schema/platformTeamSkills.js +302 -0
  84. package/dist/schema/platformToolAccess.js +62 -0
  85. package/dist/schema/platformTriggers.js +153 -0
  86. package/dist/schema/platformWorkflows.js +100 -0
  87. package/dist/schema/scheduleTimeZone.js +15 -0
  88. package/dist/schema/toolDiscovery.js +71 -0
  89. package/dist/schema/toolInputRepair.js +122 -0
  90. package/dist/schema/toolResultContext.js +51 -0
  91. package/dist/schema/untrustedContent.js +35 -0
  92. package/npm-shrinkwrap.json +73 -0
  93. package/package.json +5 -3
@@ -0,0 +1,159 @@
1
+ import { z } from "zod";
2
+ import { projectScopeSchema, platformJsonObjectSchema, platformMicrosSchema } from "./platformPublicExecution.js";
3
+ import { platformMonitorCronSchema, platformMonitorIntervalSchema, platformMonitorTimeZoneSchema } from "./platformMonitorSchedule.js";
4
+ export { PLATFORM_MONITOR_INTERVALS, platformMonitorIntervalSchema } from "./platformMonitorSchedule.js";
5
+ export const PLATFORM_MONITOR_LIMITS = {
6
+ perProject: 25,
7
+ nameChars: 80,
8
+ eventsPage: 100,
9
+ eventItemBytes: 8_192,
10
+ snapshotItems: 500,
11
+ retentionDays: 30,
12
+ popularMinimumOrganizations: 3,
13
+ popularPage: 50,
14
+ };
15
+ export const PLATFORM_MONITOR_DESTINATION_LIMITS = {
16
+ perMonitor: 5,
17
+ emailRecipients: 5,
18
+ labelChars: 80,
19
+ urlChars: 512,
20
+ digestEvents: 10,
21
+ };
22
+ export const PLATFORM_MONITOR_EMAIL_PRICE_MICROS = 900;
23
+ export const platformMonitorDestinationKindSchema = z.enum(["webhook", "slack", "discord", "email"]);
24
+ const httpsUrl = (value) => {
25
+ try {
26
+ const url = new URL(value);
27
+ return url.protocol === "https:" && !url.username && !url.password && url.hash === "" ? url : null;
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ };
33
+ export const isPlatformWebhookUrl = (value) => {
34
+ const url = httpsUrl(value);
35
+ return Boolean(url && url.port === "");
36
+ };
37
+ export const isPlatformSlackWebhookUrl = (value) => {
38
+ const url = httpsUrl(value);
39
+ return Boolean(url && url.hostname === "hooks.slack.com" && url.port === "" && url.search === "" && /^\/services\/[A-Za-z0-9]+\/[A-Za-z0-9]+\/[A-Za-z0-9]+$/.test(url.pathname));
40
+ };
41
+ export const isPlatformDiscordWebhookUrl = (value) => {
42
+ const url = httpsUrl(value);
43
+ return Boolean(url && ["discord.com", "discordapp.com"].includes(url.hostname) && url.port === "" && url.search === "" &&
44
+ /^\/api(\/v\d{1,2})?\/webhooks\/\d{1,25}\/[A-Za-z0-9_-]{1,200}$/.test(url.pathname));
45
+ };
46
+ const destinationUrl = z.string().trim().max(PLATFORM_MONITOR_DESTINATION_LIMITS.urlChars);
47
+ const destinationLabel = z.string().trim().max(PLATFORM_MONITOR_DESTINATION_LIMITS.labelChars).default("");
48
+ const memberId = z.string().min(1).max(64);
49
+ export const platformMonitorDestinationInputSchema = z.discriminatedUnion("kind", [
50
+ z.object({ kind: z.literal("webhook"), label: destinationLabel, url: destinationUrl.refine(isPlatformWebhookUrl, "platform_monitor_destination_url_invalid") }).strict(),
51
+ z.object({ kind: z.literal("slack"), label: destinationLabel, url: destinationUrl.refine(isPlatformSlackWebhookUrl, "platform_monitor_destination_url_invalid") }).strict(),
52
+ z.object({ kind: z.literal("discord"), label: destinationLabel, url: destinationUrl.refine(isPlatformDiscordWebhookUrl, "platform_monitor_destination_url_invalid") }).strict(),
53
+ z.object({ kind: z.literal("email"), label: destinationLabel,
54
+ memberIds: z.array(memberId).min(1).max(PLATFORM_MONITOR_DESTINATION_LIMITS.emailRecipients) }).strict(),
55
+ ]);
56
+ export const platformMonitorDestinationSchema = z.object({
57
+ id: z.string().regex(/^dst_[A-Za-z0-9_-]{1,100}$/),
58
+ kind: platformMonitorDestinationKindSchema,
59
+ label: z.string(),
60
+ target: z.string(),
61
+ memberIds: z.array(z.string()),
62
+ createdAt: z.string(),
63
+ lastDeliveredAt: z.string().nullable(),
64
+ lastStatus: z.enum(["ok", "failed"]).nullable(),
65
+ lastError: z.string().nullable(),
66
+ signingSecret: z.string().optional(),
67
+ });
68
+ export const platformMonitorRecipientSchema = z.object({ memberId, email: z.string(), name: z.string() });
69
+ const toolName = z.string().regex(/^[a-z][a-z0-9_]{1,63}$/);
70
+ export const PLATFORM_MONITOR_ID = /^mon_[A-Za-z0-9_-]{1,100}$/;
71
+ const monitorId = z.string().regex(PLATFORM_MONITOR_ID);
72
+ export const platformMonitorCreateSchema = z.object({
73
+ tool: toolName,
74
+ arguments: platformJsonObjectSchema.default({}),
75
+ provider: z.string().trim().max(64).default(""),
76
+ interval: platformMonitorIntervalSchema.optional().describe("Run every 15m, 1h (default) or 1d. Omit when using cron."),
77
+ cron: platformMonitorCronSchema.optional().describe("5-field cron for fixed times, at least 15 minutes between runs, for example '0 9 * * 1-5' (weekdays 09:00). Omit when using interval."),
78
+ timeZone: platformMonitorTimeZoneSchema.optional().describe("IANA time zone the cron is read in, for example Asia/Tokyo; UTC when omitted. Only with cron."),
79
+ name: z.string().trim().max(PLATFORM_MONITOR_LIMITS.nameChars).default(""),
80
+ maximumChargeMicrosPerRun: platformMicrosSchema.default(0),
81
+ destinations: z.array(platformMonitorDestinationInputSchema).max(PLATFORM_MONITOR_DESTINATION_LIMITS.perMonitor).default([]),
82
+ }).strict();
83
+ export const platformMonitorPoolSchema = z.object({
84
+ chargeCeilingMicros: platformMicrosSchema,
85
+ members: z.number().int().min(0),
86
+ shareMicros: platformMicrosSchema,
87
+ });
88
+ export const platformMonitorQuoteSchema = platformMonitorCreateSchema.pick({ tool: true, arguments: true, provider: true, interval: true, cron: true, timeZone: true }).strict();
89
+ export const platformMonitorQuoteResultSchema = platformMonitorPoolSchema.extend({
90
+ joined: z.boolean(),
91
+ payers: z.number().int().min(1),
92
+ });
93
+ export const platformMonitorResumeSchema = z.object({ maximumChargeMicrosPerRun: platformMicrosSchema.optional() }).strict();
94
+ export const platformMonitorSchema = z.object({
95
+ id: monitorId,
96
+ name: z.string(),
97
+ tool: toolName,
98
+ provider: z.string(),
99
+ arguments: platformJsonObjectSchema,
100
+ interval: platformMonitorIntervalSchema.nullable(),
101
+ cron: z.string().nullable().default(null),
102
+ timeZone: z.string().nullable().default(null),
103
+ subscribers: z.number().int().min(1),
104
+ lastCheckedAt: z.string().nullable(),
105
+ lastChangedAt: z.string().nullable(),
106
+ nextCheckAt: z.string().nullable(),
107
+ lastError: z.string().nullable(),
108
+ createdAt: z.string(),
109
+ maximumChargeMicrosPerRun: platformMicrosSchema,
110
+ pool: platformMonitorPoolSchema,
111
+ status: z.enum(["active", "suspended"]),
112
+ suspendedReason: z.string().nullable(),
113
+ destinations: z.array(platformMonitorDestinationSchema).default([]),
114
+ });
115
+ const changeValue = z.union([z.string(), z.number(), z.boolean(), z.null()]);
116
+ export const platformMonitorEventSchema = z.object({
117
+ id: z.string().regex(/^\d{1,20}$/),
118
+ monitorId: monitorId,
119
+ kind: z.enum(["added", "changed", "removed"]),
120
+ itemKey: z.string(),
121
+ title: z.string(),
122
+ url: z.string(),
123
+ item: platformJsonObjectSchema,
124
+ changes: z.array(z.object({ field: z.string(), before: changeValue, after: changeValue })),
125
+ detectedAt: z.string(),
126
+ });
127
+ export const platformMonitorEventsQuerySchema = z.object({
128
+ after: z.string().regex(/^\d{1,20}$/).optional(),
129
+ limit: z.coerce.number().int().min(1).max(PLATFORM_MONITOR_LIMITS.eventsPage).default(50),
130
+ }).strict();
131
+ export const platformMonitorEventsSchema = z.object({ events: z.array(platformMonitorEventSchema), nextAfter: z.string().nullable() });
132
+ export const platformPopularMonitorSchema = z.object({
133
+ tool: toolName, provider: z.string(), arguments: platformJsonObjectSchema,
134
+ interval: platformMonitorIntervalSchema.nullable(), cron: z.string().nullable().default(null), timeZone: z.string().nullable().default(null),
135
+ organizations: z.number().int().min(1),
136
+ chargeCeilingMicros: platformMicrosSchema,
137
+ });
138
+ export const platformMonitorableToolSchema = z.object({ name: toolName, provider: z.string(), chargeCeilingMicros: platformMicrosSchema });
139
+ export function platformMonitorWire(monitor) {
140
+ const { cron, timeZone, destinations, ...rest } = monitor;
141
+ return { ...rest, ...(cron == null ? {} : { cron }), ...(timeZone == null ? {} : { timeZone }), ...(destinations?.length ? { destinations } : {}) };
142
+ }
143
+ export const platformMonitorContracts = {
144
+ listDeveloperMonitors: { input: projectScopeSchema.strict(), output: z.object({ monitors: z.array(platformMonitorSchema) }).strict() },
145
+ createDeveloperMonitor: { input: projectScopeSchema.extend({ monitor: platformMonitorCreateSchema }).strict(), output: z.object({ monitor: platformMonitorSchema }).strict() },
146
+ deleteDeveloperMonitor: { input: projectScopeSchema.extend({ monitorId }).strict(), output: z.object({ success: z.literal(true) }).strict() },
147
+ quoteDeveloperMonitor: { input: projectScopeSchema.extend({ monitor: platformMonitorQuoteSchema }).strict(), output: z.object({ quote: platformMonitorQuoteResultSchema }).strict() },
148
+ resumeDeveloperMonitor: { input: projectScopeSchema.extend({ monitorId }).merge(platformMonitorResumeSchema).strict(), output: z.object({ monitor: platformMonitorSchema }).strict() },
149
+ listDeveloperMonitorEvents: {
150
+ input: projectScopeSchema.extend({ monitorId: monitorId.optional(), after: platformMonitorEventsQuerySchema.shape.after,
151
+ limit: z.number().int().min(1).max(PLATFORM_MONITOR_LIMITS.eventsPage).default(50) }).strict(),
152
+ output: platformMonitorEventsSchema,
153
+ },
154
+ addDeveloperMonitorDestination: { input: projectScopeSchema.extend({ monitorId, destination: platformMonitorDestinationInputSchema }).strict(), output: z.object({ monitor: platformMonitorSchema }).strict() },
155
+ removeDeveloperMonitorDestination: { input: projectScopeSchema.extend({ monitorId, destinationId: platformMonitorDestinationSchema.shape.id }).strict(), output: z.object({ monitor: platformMonitorSchema }).strict() },
156
+ listDeveloperMonitorRecipients: { input: projectScopeSchema.strict(), output: z.object({ recipients: z.array(platformMonitorRecipientSchema) }).strict() },
157
+ listPopularMonitors: { input: projectScopeSchema.strict(), output: z.object({ monitors: z.array(platformPopularMonitorSchema) }).strict() },
158
+ listMonitorableTools: { input: projectScopeSchema.strict(), output: z.object({ tools: z.array(platformMonitorableToolSchema) }).strict() },
159
+ };
@@ -0,0 +1,13 @@
1
+ import { z } from "zod";
2
+ const PLATFORM_APP_METHOD_TYPES = ["key", "none", "oauth1", "oauth2", "client_credentials", "mcp_oauth", "service_account"];
3
+ export const platformAppMethodTypeSchema = z.enum(PLATFORM_APP_METHOD_TYPES);
4
+ export const platformAppMethodTypesSchema = z.array(platformAppMethodTypeSchema).min(1).max(PLATFORM_APP_METHOD_TYPES.length)
5
+ .refine(methods => new Set(methods).size === methods.length, "Duplicate connection method");
6
+ export const platformOAuthScopeAlternativesSchema = z.array(z.array(z.string().min(1).max(256)).max(128)).min(1).max(128);
7
+ export const platformOAuthPermissionSchema = z.object({
8
+ status: z.enum(["available", "missing_scopes", "unsupported_auth_method", "unknown_grant", "unknown_requirements", "not_applicable"]),
9
+ required: platformOAuthScopeAlternativesSchema.optional(),
10
+ missing: z.array(z.string()).optional(),
11
+ connectionMethod: platformAppMethodTypeSchema.optional(),
12
+ requiredMethods: platformAppMethodTypesSchema.optional(),
13
+ });
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ import { organizationScopeSchema, projectScopeSchema } from "./platformPublicExecution.js";
3
+ import { memberTeamSkillAccessSchema, memberToolAccessSchema, platformProjectRoleSchema, platformTeamContextSchema, platformTeamQuerySchema, projectPermissionPolicySchema, projectPermissionSetDefinitionSchema, projectPermissionSetSchema, projectPermissionSetRefSchema } from "./platformToolAccess.js";
4
+ export const platformProjectStatusQuerySchema = platformTeamQuerySchema;
5
+ const projectRosterMember = platformTeamContextSchema.shape.member.extend({ role: platformProjectRoleSchema, permissionSet: projectPermissionSetRefSchema.nullable() });
6
+ const projectInvitation = projectRosterMember.omit({ memberId: true, name: true }).extend({ id: z.string(), expiresAt: z.string() });
7
+ export const platformProjectStatusSchema = platformTeamContextSchema.extend({
8
+ permissions: z.object({
9
+ permissionSet: projectPermissionSetRefSchema.nullable(), teamSkillAccess: memberTeamSkillAccessSchema,
10
+ toolExecution: z.object({ restricted: z.boolean(), allowedCount: z.number().int().nonnegative().nullable() }),
11
+ memberResourcesRestricted: z.boolean(), keyResourcesRestricted: z.boolean(),
12
+ }),
13
+ members: z.object({ items: z.array(projectRosterMember), nextOffset: z.number().int().nonnegative().nullable() }).nullable(),
14
+ invitations: z.object({ items: z.array(projectInvitation), nextOffset: z.number().int().nonnegative().nullable() }).nullable(),
15
+ });
16
+ const id = z.string().min(1).max(128), success = z.object({ success: z.literal(true) });
17
+ export const platformProjectPermissionContracts = {
18
+ updateDeveloperProjectTools: { input: projectScopeSchema.extend({ tools: projectPermissionPolicySchema.shape.tools, expectedVersion: z.number().int().positive() }).strict(),
19
+ output: z.object({ tools: projectPermissionPolicySchema.shape.tools, version: z.number().int().positive() }) },
20
+ listDeveloperUnmanagedProjects: { input: organizationScopeSchema.strict(), output: z.object({ projects: z.array(z.object({ id, name: z.string() })) }) },
21
+ recoverDeveloperProjectAdministration: { input: projectScopeSchema.strict(), output: success },
22
+ deleteDeveloperProject: { input: projectScopeSchema.extend({ name: z.string().max(200) }).strict(), output: success },
23
+ listDeveloperPermissionSets: { input: organizationScopeSchema.strict(), output: z.object({ permissionSets: z.array(projectPermissionSetSchema), canManage: z.boolean() }) },
24
+ createDeveloperPermissionSet: { input: organizationScopeSchema.extend({ permissionSet: projectPermissionSetDefinitionSchema }).strict(), output: z.object({ permissionSet: projectPermissionSetSchema }) },
25
+ updateDeveloperPermissionSet: { input: organizationScopeSchema.extend({ permissionSetId: id, expectedVersion: z.number().int().positive(), permissionSet: projectPermissionSetDefinitionSchema }).strict(), output: z.object({ permissionSet: projectPermissionSetSchema }) },
26
+ archiveDeveloperPermissionSet: { input: organizationScopeSchema.extend({ permissionSetId: id, expectedVersion: z.number().int().positive() }).strict(), output: success },
27
+ getDeveloperProjectAccess: { input: projectScopeSchema.strict(), output: z.object({
28
+ project: z.object({ id: z.string(), name: z.string() }), role: platformProjectRoleSchema,
29
+ permissionSet: projectPermissionSetSchema.nullable(), toolAccess: memberToolAccessSchema, tools: projectPermissionPolicySchema.shape.tools,
30
+ toolExecutionVersion: z.number().int().positive().default(1),
31
+ teamSkillAccess: memberTeamSkillAccessSchema, canManageMembers: z.boolean(), canDeleteProject: z.boolean().default(false),
32
+ }) },
33
+ };
@@ -1,44 +1,203 @@
1
1
  import { z } from "zod";
2
+ import { fitToolResultPage, TOOL_RESULT_CONTEXT_MAX_BYTES, toolResultContextSchema, toolResultPageSchema } from "./toolResultContext.js";
3
+ import { platformOAuthPermissionSchema } from "./platformOAuth.js";
2
4
  export const PLATFORM_EXECUTION_MAX_STEPS = 20;
5
+ export const PLATFORM_EXECUTION_MAX_WAIT_SECONDS = 25;
3
6
  export const PLATFORM_STEP_OUTPUT_MAX_BYTES = 1_048_576;
4
7
  export const PLATFORM_EXECUTION_RESPONSE_MAX_BYTES = PLATFORM_EXECUTION_MAX_STEPS * PLATFORM_STEP_OUTPUT_MAX_BYTES + 65_536;
8
+ export const PLATFORM_TOOL_REQUEST_MAX_BYTES = 1_048_576;
9
+ export const PLATFORM_CONSOLE_REQUEST_MAX_BYTES = 65_536;
10
+ export const PLATFORM_SEARCH_MAX_LENGTH = 100;
11
+ export const PLATFORM_MEDIA_URL_MAX_LENGTH = 4096;
5
12
  export const platformJsonObjectSchema = z.record(z.string(), z.json());
13
+ export const organizationScopeSchema = z.object({ developerOrganizationId: z.string().min(1).max(128) });
14
+ export const projectScopeSchema = organizationScopeSchema.extend({ developerProjectId: z.string().min(1).max(128) });
15
+ export const developerKeyScopeSchema = z.enum(["project:read", "usage:read", "tools:read", "tools:execute", "executions:read"]);
16
+ export const developerKeyAnyScopeSchema = z.enum([...developerKeyScopeSchema.options, "access:write", "sessions:write"]);
6
17
  export const PLATFORM_INPUT_MAX_BYTES = 12 * 1024 * 1024;
18
+ export const PLATFORM_FILE_CHUNK_MAX_BYTES = 32 * 1024 * 1024;
7
19
  export const PLATFORM_UPLOAD_MAX_BYTES = 16 * 1024 * 1024 + 4096;
8
20
  export const platformInputFileIdSchema = z.string().regex(/^f_[a-f0-9]{64}$/);
9
- export const platformInputMimeSchema = z.enum(["image/jpeg", "image/png", "image/webp", "audio/wav", "audio/mpeg", "video/mp4"]);
10
- export const platformInputUploadSchema = z.object({ mimeType: platformInputMimeSchema, data: z.string().min(4).max(16 * 1024 * 1024) }).strict();
11
- export const platformInputFileSchema = z.object({ id: platformInputFileIdSchema, mimeType: platformInputMimeSchema,
21
+ export const platformInputMimeSchema = z.enum(["image/jpeg", "image/png", "image/webp", "audio/wav", "audio/mpeg", "video/mp4", "video/quicktime"]);
22
+ export const platformInputFileMimeSchema = z.string().max(255).regex(/^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+$/);
23
+ export const platformInputUploadSchema = z.object({ mimeType: platformInputFileMimeSchema, data: z.string().min(4).max(16 * 1024 * 1024),
24
+ purpose: z.literal("file").optional().describe("file stores opaque bytes for provider uploads, including GIF, documents, archives and local upload chunks. Omit for validated AI media.") }).strict();
25
+ export const platformInputFileSchema = z.object({ id: platformInputFileIdSchema, mimeType: platformInputFileMimeSchema,
12
26
  sizeBytes: z.number().int().positive().max(PLATFORM_INPUT_MAX_BYTES), sha256: z.string().regex(/^[a-f0-9]{64}$/), expiresAt: z.iso.datetime() });
13
27
  export const platformMicrosSchema = z.number().int().min(0).max(1_000_000_000_000);
14
28
  export const platformToolNameSchema = z.string().regex(/^[a-z][a-z0-9_]{1,63}$/);
29
+ export const platformExecutionIdSchema = z.string().regex(/^[A-Za-z0-9_-]{1,128}$/);
30
+ export const platformToolSessionIdSchema = z.uuid();
31
+ export const platformOptionalToolSessionIdSchema = z.union([platformToolSessionIdSchema, z.literal("")]).transform(value => value || undefined).optional();
32
+ export const PLATFORM_SANDBOX_LIMITS = { code: 64000, sourceExecutions: 10, timeoutMs: 60000, sourceBytes: 32 * 1024 * 1024 };
33
+ export const platformProviderChoiceSchema = z.string().trim().regex(/^(?:[a-z][a-z0-9_]{0,63})?$/)
34
+ .transform(value => value === "" || value === "auto" ? undefined : value).optional()
35
+ .describe("Omit, use auto, or use an empty string for automatic routing. A catalog provider ID strictly selects that compatible provider; no other provider is substituted.");
36
+ export const platformRelevanceCheckSchema = z.enum(["", "auto", "light"])
37
+ .transform(value => value === "light" ? "light" : undefined).optional()
38
+ .describe("Auto result filtering: auto (default) or light, a cheaper check that keeps rows it cannot decide.");
39
+ export const platformInvalidArgumentFieldsSchema = z.array(z.string().max(200).regex(/^[\w.-]*$/)).max(50);
40
+ export const PLATFORM_REQUEST_INTENT_MAX_CHARS = 1000;
41
+ export const platformRequestIntentSchema = z.string().trim().max(PLATFORM_REQUEST_INTENT_MAX_CHARS).transform(value => value || undefined).optional()
42
+ .describe("Brief user goal without secrets or private content. Empty means omitted.");
15
43
  export const platformExecutionStatusSchema = z.enum(["queued", "running", "waiting", "succeeded", "failed", "cancelled", "needs_review"]);
44
+ export const platformFundingSchema = z.enum(["relvo", "provider", "mixed"]);
45
+ const platformModelFundingSchema = z.enum(["relvo", "provider"]);
16
46
  const workspaceArgumentNames = new Set(["workspaceid", "workspaceids", "teamid", "provideraccountid", "provideraccountids", "datasetid", "datasetids", "knowledgebaseid", "sessionid", "skillid"]);
17
- const standaloneArgumentsSchema = platformJsonObjectSchema.superRefine((value, context) => {
18
- for (const key of Object.keys(value))
19
- if (workspaceArgumentNames.has(key.replaceAll("_", "").toLowerCase())) {
20
- context.addIssue({ code: "custom", path: [key], message: "Workspace-owned data is unavailable on the standalone Platform." });
47
+ export function validatePlatformArgumentIdentifiers(tool, input, context, field = "arguments") {
48
+ if (tool?.includes("__"))
49
+ return;
50
+ const nativeFields = tool?.startsWith("tikhub_") ? ["session_id"]
51
+ : tool?.startsWith("brightdata_") ? ["dataset_id"]
52
+ : tool?.startsWith("firecrawl_") ? ["dataset_id", "session_id", "team_id"] : [];
53
+ for (const key of Object.keys(input))
54
+ if (workspaceArgumentNames.has(key.replaceAll("_", "").toLowerCase()) && !nativeFields.includes(key)) {
55
+ context.addIssue({ code: "custom", path: [field, key], message: "Workspace-owned data is unavailable on the standalone Platform." });
21
56
  }
22
- }).describe("Self-contained tool arguments: prompts, public URLs or public account identifiers. Web workspace identifiers are not supported.");
23
- export const platformToolInputSchema = z.object({ tool: platformToolNameSchema.describe("Tool name from the standalone Platform catalog."), arguments: standaloneArgumentsSchema }).strict();
57
+ }
58
+ const standaloneArgumentsSchema = z.record(z.string(), z.unknown()).pipe(platformJsonObjectSchema)
59
+ .describe("Self-contained tool arguments: prompts, public URLs or public account identifiers. Web workspace identifiers are not supported.");
60
+ export const platformToolInputSchema = z.object({ tool: platformToolNameSchema.describe("Tool name from the standalone Platform catalog."), arguments: standaloneArgumentsSchema,
61
+ provider: platformProviderChoiceSchema,
62
+ relevanceCheck: platformRelevanceCheckSchema,
63
+ intent: platformRequestIntentSchema,
64
+ sessionId: platformOptionalToolSessionIdSchema.describe("Relvo tool session returned by platform_search_tools. Omit or use an empty string for standalone executions.") }).strict()
65
+ .superRefine((value, context) => validatePlatformArgumentIdentifiers(value.tool, value.arguments, context));
66
+ export const platformQuoteRequestSchema = platformToolInputSchema.extend({
67
+ maximumChargeMicros: platformMicrosSchema.optional()
68
+ .describe("Optional cap: an Auto quote above it returns the best plan within it as plan; execute with plan's fields."),
69
+ }).strict();
70
+ export const platformRunRequestHashSchema = z.string().regex(/^[a-f0-9]{64}$/);
71
+ export const platformRecoverExecutionSchema = z.object({ idempotencyKey: z.string().regex(/^[A-Za-z0-9._:-]{8,128}$/),
72
+ requestHash: platformRunRequestHashSchema.optional() }).strict();
24
73
  export const platformCreateExecutionSchema = platformToolInputSchema.extend({
25
74
  maximumChargeMicros: platformMicrosSchema,
26
75
  priceVersion: z.string().min(1).max(100),
76
+ runRequestHash: platformRunRequestHashSchema.optional(),
27
77
  }).strict();
28
78
  export const platformQuoteSchema = z.object({
29
79
  tool: platformToolNameSchema, priceVersion: z.string(), currency: z.literal("usd"),
30
80
  minimumChargeMicros: platformMicrosSchema, maximumChargeMicros: platformMicrosSchema,
81
+ lowestChargeMicros: platformMicrosSchema.optional(),
31
82
  expiresAt: z.string(),
83
+ funding: platformFundingSchema.optional(), externalBillingProviders: z.array(z.string()).optional(),
84
+ plan: z.object({ provider: z.string().optional(), relevanceCheck: z.literal("light").optional() }).strict().optional(),
85
+ });
86
+ export const platformUpstreamRefusalSchema = z.object({
87
+ kind: z.enum(["rate_limited", "permission", "rejected"]),
88
+ httpStatus: z.number().int().min(100).max(599).optional(),
89
+ code: z.string().max(100).optional(),
90
+ retryAfterSeconds: z.number().int().nonnegative().optional(),
91
+ neededScopes: z.array(z.string().max(100)).max(20).optional(),
32
92
  });
93
+ const refusedStepSchema = z.object({ requestSucceeded: z.literal(false), response: z.object({ status: z.number().int().min(100).max(599).optional(), body: z.unknown().optional(),
94
+ headers: z.object({ retryAfter: z.string().optional() }).loose().optional() }).loose().optional() }).loose();
95
+ const multiStepOutputSchema = z.object({ results: z.array(z.object({ data: z.unknown() }).loose()) }).loose();
96
+ const refusalBodySchema = z.object({ error: z.union([z.string(), z.object({ code: z.union([z.string(), z.number()]) }).loose()]).optional(),
97
+ code: z.union([z.string(), z.number()]).optional(), needed: z.string().optional(),
98
+ errors: z.array(z.object({ extensions: z.object({ code: z.string() }).loose().optional() }).loose()).min(1).optional() }).loose();
99
+ const REFUSAL_CODE = /^[A-Za-z0-9_.:-]{1,100}$/;
100
+ const PERMISSION_CODES = new Set(["missing_scope", "no_permission", "not_allowed_token_type", "scope_not_authorized"]);
101
+ export function retryAfterSeconds(value, now = Date.now()) {
102
+ if (value === undefined || !value.trim())
103
+ return undefined;
104
+ const delay = Number(value), seconds = Number.isFinite(delay) ? delay : (Date.parse(value) - now) / 1000;
105
+ return Number.isFinite(seconds) ? Math.max(0, Math.ceil(seconds)) : undefined;
106
+ }
107
+ function refusalOf(step) {
108
+ const body = refusalBodySchema.safeParse(step.response?.body ?? step.response).data, status = step.response?.status;
109
+ const error = typeof body?.error === "object" ? body.error.code : body?.error;
110
+ const raw = String((typeof body?.code === "string" ? body.code : undefined) ?? error ?? body?.errors?.[0]?.extensions?.code ?? body?.code ?? "");
111
+ const code = REFUSAL_CODE.test(raw) ? raw : undefined;
112
+ const neededScopes = body?.needed?.split(",").map(scope => scope.trim()).filter(scope => REFUSAL_CODE.test(scope)).slice(0, 20) ?? [];
113
+ const wait = retryAfterSeconds(step.response?.headers?.retryAfter);
114
+ const kind = status === 429 || code === "ratelimited" ? "rate_limited"
115
+ : status === 401 || status === 403 || neededScopes.length || code !== undefined && PERMISSION_CODES.has(code) ? "permission" : "rejected";
116
+ return { kind, ...(status === undefined ? {} : { httpStatus: status }), ...(code ? { code } : {}), ...(wait === undefined ? {} : { retryAfterSeconds: wait }),
117
+ ...(neededScopes.length ? { neededScopes } : {}) };
118
+ }
119
+ export function connectedRequestRefusal(output) {
120
+ const step = refusedStepSchema.safeParse(output);
121
+ if (step.success)
122
+ return refusalOf(step.data);
123
+ const steps = multiStepOutputSchema.safeParse(output);
124
+ if (!steps.success)
125
+ return undefined;
126
+ for (const { data } of steps.data.results) {
127
+ const refused = refusedStepSchema.safeParse(data);
128
+ if (refused.success)
129
+ return refusalOf(refused.data);
130
+ }
131
+ return undefined;
132
+ }
33
133
  export const platformExecutionSchema = z.object({
34
- id: z.string(), tool: platformToolNameSchema, status: platformExecutionStatusSchema, cancelRequested: z.boolean(),
134
+ id: platformExecutionIdSchema, tool: platformToolNameSchema, status: platformExecutionStatusSchema, cancelRequested: z.boolean(),
35
135
  priceVersion: z.string(), currency: z.literal("usd"), reservedMicros: platformMicrosSchema, chargedMicros: platformMicrosSchema,
136
+ funding: platformFundingSchema.optional(), externalBillingProviders: z.array(z.string()).optional(),
36
137
  output: platformJsonObjectSchema.nullable(), errorCode: z.string().nullable(),
138
+ upstreamRefusal: platformUpstreamRefusalSchema.optional(),
139
+ rateLimitedUntil: z.string().optional(),
140
+ reconnectUrl: z.url().optional(),
141
+ actionUrl: z.url().optional(),
142
+ sourceRefusals: z.array(z.object({ source: z.string(), inputs: z.array(z.string()), applies: z.array(z.string()).optional() })).optional(),
37
143
  createdAt: z.string(), updatedAt: z.string(), completedAt: z.string().nullable(),
38
144
  });
145
+ export const platformExecutionContextSchema = platformExecutionSchema.extend({ resultContext: toolResultContextSchema.omit({ preview: true }) });
146
+ export function platformExecutionHasPartialOutput(execution) {
147
+ const output = execution.output, keys = output === null ? [] : Object.keys(output);
148
+ return ["failed", "cancelled"].includes(execution.status) && keys.length > 0
149
+ && !(keys.length === 1 && Array.isArray(output?.results) && output.results.length === 0);
150
+ }
151
+ export const platformExecutionResultPageSchema = z.object({ executionId: platformExecutionIdSchema, page: toolResultPageSchema,
152
+ status: platformExecutionStatusSchema.optional(), chargedMicros: platformMicrosSchema.nullable().optional(), errorCode: z.string().nullable().optional(), partial: z.boolean().optional(),
153
+ upstreamRefusal: platformUpstreamRefusalSchema.optional() });
154
+ export const PLATFORM_EXECUTION_CONTEXT_BUDGET_ERROR = "platform_execution_context_budget_exceeded";
155
+ export class PlatformExecutionContextBudgetError extends Error {
156
+ executionId;
157
+ kind;
158
+ code = PLATFORM_EXECUTION_CONTEXT_BUDGET_ERROR;
159
+ constructor(executionId, kind = "execution") {
160
+ super(kind === "page"
161
+ ? `Execution ${executionId} selected result page metadata exceeds the context budget. Read a narrower path or use a smaller limit/maxChars; the full result remains retained.`
162
+ : `Execution ${executionId} metadata exceeds the context budget. Recover it by this ID or the retained idempotency key.`);
163
+ this.executionId = executionId;
164
+ this.kind = kind;
165
+ this.name = "PlatformExecutionContextBudgetError";
166
+ }
167
+ }
168
+ const executionContextBytes = (value) => new TextEncoder().encode(JSON.stringify(value)).byteLength;
169
+ export function platformExecutionReceiptContext(result, options) {
170
+ const maximumBytes = options.maximumBytes ?? TOOL_RESULT_CONTEXT_MAX_BYTES;
171
+ if (executionContextBytes(result) <= maximumBytes)
172
+ return result;
173
+ const existing = platformExecutionContextSchema.safeParse(result.data);
174
+ const compact = { data: platformExecutionContextSchema.parse({ ...result.data, output: null,
175
+ resultContext: { offloaded: true, totalBytes: existing.success ? existing.data.resultContext.totalBytes : executionContextBytes(result.data.output),
176
+ reference: { ...(existing.success ? existing.data.resultContext.reference : {}), executionId: result.data.id, readWith: options.readWith } },
177
+ }) };
178
+ if (executionContextBytes(compact) > maximumBytes)
179
+ throw new PlatformExecutionContextBudgetError(result.data.id);
180
+ return compact;
181
+ }
182
+ export function platformExecutionResultPageContext(result, options) {
183
+ const maximumBytes = options.maximumBytes ?? TOOL_RESULT_CONTEXT_MAX_BYTES;
184
+ if (executionContextBytes(result) <= maximumBytes)
185
+ return result;
186
+ const { executionId, page, ...metadata } = result.data;
187
+ const fitted = { data: { executionId, ...metadata, page: fitToolResultPage(page, candidate => executionContextBytes({ data: { executionId, ...metadata, page: candidate } }) <= maximumBytes) } };
188
+ if (executionContextBytes(fitted) <= maximumBytes)
189
+ return fitted;
190
+ const compact = { data: platformExecutionResultPageSchema.parse({ executionId, ...metadata, page: { ...page,
191
+ context: { ...page.context, offloaded: true, preview: null, reference: { ...page.context.reference,
192
+ executionId, readWith: options.readWith, path: page.path, offset: page.offset } },
193
+ } }) };
194
+ if (executionContextBytes(compact) > maximumBytes)
195
+ throw new PlatformExecutionContextBudgetError(executionId, "page");
196
+ return compact;
197
+ }
39
198
  export const platformExecutionListQuerySchema = z.object({
40
199
  limit: z.number().int().min(1).max(100).default(20).describe("Page size, 1–100."),
41
- before: z.string().regex(/^[A-Za-z0-9_-]{1,128}$/).optional().describe("nextBefore from the previous page."),
200
+ before: platformExecutionIdSchema.optional().describe("nextBefore from the previous page."),
42
201
  status: platformExecutionStatusSchema.optional().describe("Only executions with this status."),
43
202
  tool: platformToolNameSchema.optional().describe("Only executions of this catalog tool."),
44
203
  }).strict();
@@ -48,17 +207,39 @@ export const platformExecutionListSchema = z.object({
48
207
  });
49
208
  export const platformArtifactIdSchema = z.string().regex(/^a_[A-Za-z0-9_-]{1,100}$/);
50
209
  export const platformArtifactSchema = z.object({
51
- id: platformArtifactIdSchema, mimeType: z.enum(["image/jpeg", "image/png", "image/webp", "audio/wav", "audio/mpeg", "video/mp4"]),
210
+ id: platformArtifactIdSchema, mimeType: z.enum(["image/jpeg", "image/png", "image/webp", "image/svg+xml", "audio/wav", "audio/mpeg", "audio/flac", "audio/l16", "audio/mulaw", "audio/alaw", "video/mp4", "video/quicktime", "model/gltf-binary", "application/zip"]),
52
211
  sizeBytes: z.number().int().positive().max(64 * 1024 * 1024), sha256: z.string().regex(/^[a-f0-9]{64}$/),
53
212
  generation: z.string().regex(/^\d{1,30}$/), expiresAt: z.iso.datetime(),
54
213
  });
55
- export const platformArtifactDownloadSchema = z.object({ url: z.url().refine((value) => { const url = new URL(value); return url.protocol === "https:" && !url.username && !url.password; }), expiresAt: z.iso.datetime() });
56
- export const platformCatalogSchema = z.object({
57
- priceVersion: z.string(), currency: z.literal("usd"), executionEnabled: z.boolean(),
58
- tools: z.array(z.object({
59
- name: platformToolNameSchema, description: z.string(), category: z.enum(["research", "seo", "social", "generation"]),
60
- available: z.boolean(), inputSchema: platformJsonObjectSchema, example: platformJsonObjectSchema,
61
- models: z.array(z.object({ id: z.string(), available: z.boolean(), example: platformJsonObjectSchema, priceDescription: z.string() })).optional(),
62
- price: z.object({ minimumChargeMicros: platformMicrosSchema, unit: z.string(), unitPriceMicros: platformMicrosSchema.nullable(), description: z.string() }),
63
- })),
214
+ export const platformArtifactDownloadSchema = z.object({ url: z.url().refine(value => {
215
+ if (!URL.canParse(value))
216
+ return false;
217
+ const url = new URL(value);
218
+ return !url.username && !url.password && !url.hash && (url.protocol === "https:" || url.protocol === "http:" && ["127.0.0.1", "localhost"].includes(url.hostname));
219
+ }), expiresAt: z.iso.datetime() });
220
+ export const platformUnavailableReasonSchema = z.enum(["setup", "own_key", "connection", "permission", "retired"]);
221
+ export const PLATFORM_TOOL_RESPONSE_SUMMARY_MAX = 2000;
222
+ export const platformCatalogToolSchema = z.object({
223
+ name: platformToolNameSchema, title: z.string().optional(), description: z.string(), category: z.enum(["research", "seo", "social", "generation", "enrichment", "finance", "news"]),
224
+ available: z.boolean(), unavailable: platformUnavailableReasonSchema.optional(), inputSchema: platformJsonObjectSchema, example: platformJsonObjectSchema,
225
+ responseSummary: z.string().max(PLATFORM_TOOL_RESPONSE_SUMMARY_MAX).optional(),
226
+ permission: platformOAuthPermissionSchema.optional(),
227
+ providers: z.array(z.object({ id: z.string(), name: z.string(), available: z.boolean(), unavailable: platformUnavailableReasonSchema.optional(),
228
+ role: z.enum(["primary", "fallback", "alternative"]), condition: z.string().optional(),
229
+ applies: z.array(z.string()).optional() })).optional(),
230
+ models: z.array(z.object({ id: z.string(), available: z.boolean(), unavailable: platformUnavailableReasonSchema.optional(), example: platformJsonObjectSchema, priceDescription: z.string(), funding: platformModelFundingSchema.optional() })).optional(),
231
+ price: z.object({ minimumChargeMicros: platformMicrosSchema, unit: z.string(), unitPriceMicros: platformMicrosSchema.nullable(), unitPriceCeilingMicros: platformMicrosSchema.optional(), description: z.string(),
232
+ unitsPerRequest: z.object({ minimum: z.number().int().positive(), maximum: z.number().int().positive() }).refine(range => range.minimum <= range.maximum).optional(),
233
+ funding: platformFundingSchema.optional(), externalBillingProviders: z.array(z.string()).optional() }),
64
234
  });
235
+ const platformCatalogHeader = { priceVersion: z.string(), currency: z.literal("usd"), executionEnabled: z.boolean() };
236
+ export const platformCatalogSchema = z.object({ ...platformCatalogHeader, tools: z.array(platformCatalogToolSchema) });
237
+ export const PLATFORM_CATALOG_PAGE_MAX = 50;
238
+ export const PLATFORM_READ_UNIT_BYTES = 262_144;
239
+ export const platformCatalogPageQuerySchema = z.object({
240
+ offset: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER).default(0),
241
+ limit: z.number().int().min(1).max(PLATFORM_CATALOG_PAGE_MAX).default(PLATFORM_CATALOG_PAGE_MAX),
242
+ }).strict();
243
+ export const platformCatalogPageSchema = platformCatalogSchema.extend({ total: z.number().int().min(0), nextOffset: z.number().int().min(0).nullable() });
244
+ export const platformCatalogSummarySchema = z.object({ ...platformCatalogHeader, tools: z.array(platformCatalogToolSchema.omit({ inputSchema: true })) });
245
+ export const platformCatalogToolDetailSchema = z.object({ ...platformCatalogHeader, tool: platformCatalogToolSchema });
@@ -0,0 +1,122 @@
1
+ const TOOL = "[a-z][a-z0-9_]{1,63}";
2
+ const EXECUTION = "[A-Za-z0-9_-]{1,128}";
3
+ const ARTIFACT = "a_[A-Za-z0-9_-]{1,100}";
4
+ const MONITOR = "mon_[A-Za-z0-9_-]{1,100}";
5
+ const CUSTOM_TOOL = "custom__[a-z][a-z0-9_]{1,39}";
6
+ const TEAM_SKILL = "[a-z][a-z0-9_]{1,39}";
7
+ const WORKFLOW = "[a-z][a-z0-9_]{1,39}";
8
+ const WORKFLOW_RUN = "wfr_[A-Za-z0-9_-]{1,100}";
9
+ const TRIGGER = "trg_[A-Za-z0-9_-]{1,100}";
10
+ const MEMBER = "[A-Za-z0-9-]{1,128}";
11
+ export const PLATFORM_ROUTES = {
12
+ tools: "/v1/tools",
13
+ connections: "/v1/connections",
14
+ connectApp: "/v1/connect-app",
15
+ quote: "/v1/quote",
16
+ project: "/v1/project",
17
+ projectStatus: "/v1/project/status",
18
+ team: "/v1/team",
19
+ usage: "/v1/usage",
20
+ executions: "/v1/executions",
21
+ executionRecovery: "/v1/executions/recover",
22
+ execution: `/v1/executions/:id{${EXECUTION}}`,
23
+ executionContext: `/v1/executions/:id{${EXECUTION}}/context`,
24
+ executionResult: `/v1/executions/:id{${EXECUTION}}/result`,
25
+ executionCancel: `/v1/executions/:id{${EXECUTION}}/cancel`,
26
+ artifactDownload: `/v1/executions/:id{${EXECUTION}}/artifacts/:artifact{${ARTIFACT}}/download`,
27
+ monitors: "/v1/monitors",
28
+ monitorTools: "/v1/monitors/tools",
29
+ monitorsPopular: "/v1/monitors/popular",
30
+ monitorQuote: "/v1/monitors/quote",
31
+ monitorResume: `/v1/monitors/:id{${MONITOR}}/resume`,
32
+ monitor: `/v1/monitors/:id{${MONITOR}}`,
33
+ monitorDelete: `/v1/monitors/:id{${MONITOR}}/delete`,
34
+ monitorEvents: `/v1/monitors/:id{${MONITOR}}/events`,
35
+ monitorDestinations: `/v1/monitors/:id{${MONITOR}}/destinations`,
36
+ monitorDestinationDelete: `/v1/monitors/:id{${MONITOR}}/destinations/:destinationId{dst_[A-Za-z0-9_-]{1,100}}/delete`,
37
+ monitorRecipients: "/v1/monitor-recipients",
38
+ monitorFeed: "/v1/monitor-events",
39
+ customTools: "/v1/custom-tools",
40
+ customTool: `/v1/custom-tools/:name{${CUSTOM_TOOL}}`,
41
+ customToolUpdate: `/v1/custom-tools/:name{${CUSTOM_TOOL}}/update`,
42
+ customToolDelete: `/v1/custom-tools/:name{${CUSTOM_TOOL}}/delete`,
43
+ customToolVersions: `/v1/custom-tools/:name{${CUSTOM_TOOL}}/versions`,
44
+ customToolRestore: `/v1/custom-tools/:name{${CUSTOM_TOOL}}/restore`,
45
+ teamSkills: "/v1/team-skills",
46
+ teamSkill: `/v1/team-skills/:slug{${TEAM_SKILL}}`,
47
+ teamSkillUpdate: `/v1/team-skills/:slug{${TEAM_SKILL}}/update`,
48
+ teamSkillDelete: `/v1/team-skills/:slug{${TEAM_SKILL}}/delete`,
49
+ teamSkillVersions: `/v1/team-skills/:slug{${TEAM_SKILL}}/versions`,
50
+ teamSkillRestore: `/v1/team-skills/:slug{${TEAM_SKILL}}/restore`,
51
+ workflows: "/v1/workflows",
52
+ workflow: `/v1/workflows/:slug{${WORKFLOW}}`,
53
+ workflowUpdate: `/v1/workflows/:slug{${WORKFLOW}}/update`,
54
+ workflowDelete: `/v1/workflows/:slug{${WORKFLOW}}/delete`,
55
+ workflowVersions: `/v1/workflows/:slug{${WORKFLOW}}/versions`,
56
+ workflowRuns: `/v1/workflows/:slug{${WORKFLOW}}/runs`,
57
+ workflowRun: `/v1/workflow-runs/:id{${WORKFLOW_RUN}}`,
58
+ workflowRunCancel: `/v1/workflow-runs/:id{${WORKFLOW_RUN}}/cancel`,
59
+ triggers: "/v1/triggers",
60
+ trigger: `/v1/triggers/:id{${TRIGGER}}`,
61
+ triggerUpdate: `/v1/triggers/:id{${TRIGGER}}/update`,
62
+ triggerDelete: `/v1/triggers/:id{${TRIGGER}}/delete`,
63
+ triggerEvents: `/v1/triggers/:id{${TRIGGER}}/events`,
64
+ triggerDestinations: `/v1/triggers/:id{${TRIGGER}}/destinations`,
65
+ triggerDestinationDelete: `/v1/triggers/:id{${TRIGGER}}/destinations/:destinationId{dst_[A-Za-z0-9_-]{1,100}}/delete`,
66
+ triggerFeed: "/v1/trigger-events",
67
+ triggerTypes: "/v1/trigger-types",
68
+ suggestions: "/v1/suggestions",
69
+ access: "/v1/access",
70
+ memberAccess: `/v1/access/members/:id{${MEMBER}}/update`,
71
+ definition: `/tools/definition/:name{${TOOL}}`,
72
+ tool: `/tools/:tool{${TOOL}}`,
73
+ discover: "/tools/discover",
74
+ upload: "/tools/upload",
75
+ skills: "/tools/skills",
76
+ metaSearch: "/tools/meta/search",
77
+ metaSchemas: "/tools/meta/schemas",
78
+ metaConnections: "/tools/meta/connections",
79
+ metaExecute: "/tools/meta/execute",
80
+ metaWorkbench: "/tools/meta/workbench",
81
+ metaBash: "/tools/meta/bash",
82
+ };
83
+ export const PLATFORM_TRIGGER_INGRESS_ROUTES = {
84
+ endpoint: "/v1/trigger-ingress/:endpoint{tep_[a-f0-9]{32}}",
85
+ app: "/v1/trigger-ingress/app/:app{[a-z0-9][a-z0-9_]{0,63}}",
86
+ };
87
+ export const PLATFORM_WALLET_ROUTES = {
88
+ signIn: "/v1/wallet/sign-in",
89
+ topUp: "/v1/wallet/top-up",
90
+ };
91
+ export const PLATFORM_META_ROUTES = [PLATFORM_ROUTES.metaSearch, PLATFORM_ROUTES.metaSchemas, PLATFORM_ROUTES.metaConnections,
92
+ PLATFORM_ROUTES.metaExecute, PLATFORM_ROUTES.metaWorkbench, PLATFORM_ROUTES.metaBash];
93
+ export const PLATFORM_BRIDGE_ROUTES = [
94
+ PLATFORM_ROUTES.tools, PLATFORM_ROUTES.connections, PLATFORM_ROUTES.quote, PLATFORM_ROUTES.project, PLATFORM_ROUTES.projectStatus, PLATFORM_ROUTES.team, PLATFORM_ROUTES.usage,
95
+ PLATFORM_ROUTES.executions, PLATFORM_ROUTES.executionRecovery, PLATFORM_ROUTES.execution, PLATFORM_ROUTES.executionContext, PLATFORM_ROUTES.executionResult,
96
+ PLATFORM_ROUTES.executionCancel, PLATFORM_ROUTES.artifactDownload, PLATFORM_ROUTES.definition, PLATFORM_ROUTES.tool,
97
+ ];
98
+ const ALIASED = "(?:project|team|usage|quote|executions|connections)(?:\\/|$)";
99
+ const TOOLS_ALIASES = new RegExp(`^\\/tools\\/${ALIASED}`), V1_ALIASED = new RegExp(`^\\/v1\\/(?=${ALIASED})`);
100
+ export function platformRoutePath(pathname) {
101
+ if (pathname === "/tools")
102
+ return PLATFORM_ROUTES.tools;
103
+ return TOOLS_ALIASES.test(pathname) ? pathname.replace(/^\/tools\//, "/v1/") : pathname;
104
+ }
105
+ const PARAMETER = /:([A-Za-z]+)\{((?:[^{}]|\{[^{}]*\})*)\}/g;
106
+ export function platformToolsPath(route, values = {}) {
107
+ const path = route === PLATFORM_ROUTES.tools ? "/tools" : route.replace(V1_ALIASED, "/tools/");
108
+ return path.replace(PARAMETER, (_, name) => values[name] ?? `{${name}}`);
109
+ }
110
+ function routeExpression(pattern) {
111
+ let source = "", last = 0;
112
+ for (const match of pattern.matchAll(PARAMETER)) {
113
+ source += escapeLiteral(pattern.slice(last, match.index)) + `(?:${match[2]})`;
114
+ last = match.index + match[0].length;
115
+ }
116
+ return source + escapeLiteral(pattern.slice(last));
117
+ }
118
+ const escapeLiteral = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
119
+ const BRIDGE_PATH = new RegExp(`^(?:${PLATFORM_BRIDGE_ROUTES.map(routeExpression).join("|")})$`);
120
+ export function isPlatformBridgePath(pathname) {
121
+ return BRIDGE_PATH.test(platformRoutePath(pathname));
122
+ }
@@ -0,0 +1,11 @@
1
+ import { z } from "zod";
2
+ export const PLATFORM_SKILLS_MAX_BYTES = 1_048_576;
3
+ export const PLATFORM_SKILL_MAX_BYTES = 65_536;
4
+ export const platformSkillSchema = z.object({ name: z.string().regex(/^relvo(?:-[a-z0-9]+)*$/).max(64),
5
+ description: z.string().min(1).max(1000), sha256: z.string().regex(/^[a-f0-9]{64}$/),
6
+ content: z.string().min(1).max(PLATFORM_SKILL_MAX_BYTES).refine(value => new TextEncoder().encode(value).byteLength <= PLATFORM_SKILL_MAX_BYTES) }).strict();
7
+ export const platformSkillsBundleSchema = z.object({ version: z.string().regex(/^[a-f0-9]{64}$/),
8
+ skills: z.array(platformSkillSchema).min(1).max(32) }).strict().superRefine((value, context) => {
9
+ if (new Set(value.skills.map(skill => skill.name)).size !== value.skills.length || new TextEncoder().encode(JSON.stringify(value)).byteLength > PLATFORM_SKILLS_MAX_BYTES)
10
+ context.addIssue({ code: "custom", message: "Invalid skill bundle" });
11
+ });
@@ -0,0 +1,3 @@
1
+ import { z } from "zod";
2
+ export const PLATFORM_TEAM_SECRET_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
3
+ export const platformTeamSecretNameSchema = z.string().regex(PLATFORM_TEAM_SECRET_NAME).describe("Letters, digits and underscores, not starting with a digit, e.g. STRIPE_API_KEY.");
@@ -0,0 +1 @@
1
+ export const PLATFORM_TEAM_SKILL_SLUG = /^[a-z][a-z0-9_]{1,39}$/;