@ingram-cloud/sdk 1.0.0

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 (64) hide show
  1. package/README.md +74 -0
  2. package/dist/client.js +460 -0
  3. package/dist/events.js +108 -0
  4. package/dist/index.js +19 -0
  5. package/dist/responses.js +12 -0
  6. package/dist/schemas.js +4 -0
  7. package/dist/zod/_page.js +17 -0
  8. package/dist/zod/agents.js +176 -0
  9. package/dist/zod/approvals.js +38 -0
  10. package/dist/zod/budgets.js +62 -0
  11. package/dist/zod/catalog.js +49 -0
  12. package/dist/zod/connections.js +75 -0
  13. package/dist/zod/conversations.js +91 -0
  14. package/dist/zod/customers.js +53 -0
  15. package/dist/zod/deployments.js +81 -0
  16. package/dist/zod/discord.js +32 -0
  17. package/dist/zod/email.js +45 -0
  18. package/dist/zod/files.js +55 -0
  19. package/dist/zod/index.js +35 -0
  20. package/dist/zod/mcp.js +107 -0
  21. package/dist/zod/memories.js +43 -0
  22. package/dist/zod/observability.js +133 -0
  23. package/dist/zod/projects.js +58 -0
  24. package/dist/zod/runs.js +119 -0
  25. package/dist/zod/schedules.js +71 -0
  26. package/dist/zod/slack.js +69 -0
  27. package/dist/zod/smith-revisions.js +42 -0
  28. package/dist/zod/smiths.js +108 -0
  29. package/dist/zod/telegram.js +36 -0
  30. package/dist/zod/tenant.js +219 -0
  31. package/dist/zod/vector-stores.js +251 -0
  32. package/dist/zod/whatsapp.js +47 -0
  33. package/package.json +56 -0
  34. package/ts/client.ts +1187 -0
  35. package/ts/events.ts +119 -0
  36. package/ts/index.ts +20 -0
  37. package/ts/responses.ts +83 -0
  38. package/ts/schemas.ts +4 -0
  39. package/ts/zod/_page.ts +18 -0
  40. package/ts/zod/agents.ts +202 -0
  41. package/ts/zod/approvals.ts +44 -0
  42. package/ts/zod/budgets.ts +75 -0
  43. package/ts/zod/catalog.ts +57 -0
  44. package/ts/zod/connections.ts +87 -0
  45. package/ts/zod/conversations.ts +103 -0
  46. package/ts/zod/customers.ts +62 -0
  47. package/ts/zod/deployments.ts +93 -0
  48. package/ts/zod/discord.ts +39 -0
  49. package/ts/zod/email.ts +52 -0
  50. package/ts/zod/files.ts +62 -0
  51. package/ts/zod/index.ts +35 -0
  52. package/ts/zod/mcp.ts +123 -0
  53. package/ts/zod/memories.ts +53 -0
  54. package/ts/zod/observability.ts +155 -0
  55. package/ts/zod/projects.ts +68 -0
  56. package/ts/zod/runs.ts +135 -0
  57. package/ts/zod/schedules.ts +82 -0
  58. package/ts/zod/slack.ts +79 -0
  59. package/ts/zod/smith-revisions.ts +50 -0
  60. package/ts/zod/smiths.ts +118 -0
  61. package/ts/zod/telegram.ts +43 -0
  62. package/ts/zod/tenant.ts +267 -0
  63. package/ts/zod/vector-stores.ts +296 -0
  64. package/ts/zod/whatsapp.ts +54 -0
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `connections` resource — per-smith OAuth
3
+ * grants under `/v1/smiths/:pid/connections`. The wire's source of truth,
4
+ * replacing the loose generated shapes for this resource.
5
+ *
6
+ * One source, three outputs: the API imports these into its `createRoute`
7
+ * definitions (validation + emitted OpenAPI), and the consumer-facing `IC*`
8
+ * types are `z.infer`red from them here and re-exported by `../responses`. No
9
+ * Zod is pulled into a type-only consumer — `responses.ts` re-exports these as
10
+ * `export type`.
11
+ *
12
+ * SECURITY INVARIANT: `ConnectionOut` NEVER carries the secret credential
13
+ * material — only `id`, `provider`, `scopes`, `status`, `expires_at`,
14
+ * `metadata`, `created_at`. The handler's `toPublic` serializer is validated
15
+ * against this schema.
16
+ *
17
+ * `.meta({ id })` names the component so the emitted OpenAPI references it as
18
+ * `#/components/schemas/<id>` rather than inlining it.
19
+ */
20
+ import { z } from "zod";
21
+
22
+ /** OAuth token material the tenant pushes in; IC stores it encrypted and never
23
+ * echoes it back. Only `kind: "oauth_tokens"` is accepted. */
24
+ export const Credential = z
25
+ .object({
26
+ kind: z.string().optional(),
27
+ access_token: z.string().nullish(),
28
+ refresh_token: z.string().nullish(),
29
+ expires_at: z.string().nullish(),
30
+ token_uri: z.string().nullish(),
31
+ })
32
+ .meta({ id: "Credential" });
33
+
34
+ /** A connection WITHOUT the secret credential material. */
35
+ export const ConnectionOut = z
36
+ .object({
37
+ id: z.string(),
38
+ provider: z.string(),
39
+ scopes: z.array(z.string()),
40
+ status: z.string(),
41
+ expires_at: z.string().nullable(),
42
+ metadata: z.record(z.string(), z.unknown()).optional(),
43
+ created_at: z.string().nullable(),
44
+ })
45
+ .meta({ id: "ConnectionOut" });
46
+
47
+ export const ConnectionListOut = z
48
+ .object({ data: z.array(ConnectionOut) })
49
+ .meta({ id: "ConnectionListOut" });
50
+
51
+ // ── Request bodies ──────────────────────────────────────────────────────────
52
+
53
+ export const ConnectionIn = z
54
+ .object({
55
+ provider: z.string(),
56
+ scopes: z.array(z.string()).optional(),
57
+ credential: Credential,
58
+ metadata: z.record(z.string(), z.unknown()).optional(),
59
+ })
60
+ .meta({ id: "ConnectionIn" });
61
+
62
+ export const ConnectionPatch = z
63
+ .object({
64
+ scopes: z.array(z.string()).nullish(),
65
+ credential: Credential.nullish(),
66
+ status: z.string().nullish(),
67
+ metadata: z.record(z.string(), z.unknown()).nullish(),
68
+ })
69
+ .meta({ id: "ConnectionPatch" });
70
+
71
+ /** The `authorize` 200 body: the minted authorize URL + echoed provider. */
72
+ export const AuthorizeOut = z
73
+ .object({ authorize_url: z.string().nullable(), provider: z.string() })
74
+ .meta({ id: "AuthorizeOut" });
75
+
76
+ /** Body for the OAuth consent broker: `POST …/connections/authorize`. */
77
+ export const AuthorizeIn = z
78
+ .object({
79
+ provider: z.string(),
80
+ return_url: z.string().nullish(),
81
+ mcp_server: z.string().nullish(),
82
+ })
83
+ .meta({ id: "AuthorizeIn" });
84
+
85
+ // ── Inferred consumer-facing types (re-exported by ../responses) ─────────────
86
+
87
+ export type ICConnection = z.infer<typeof ConnectionOut>;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `conversations` resource — the wire's source
3
+ * of truth, mapped onto the OpenAI **Conversations API** so an OpenAI client
4
+ * library talks to it unchanged.
5
+ *
6
+ * One source, three outputs: the API imports these into its `createRoute`
7
+ * definitions (validation + emitted OpenAPI), and the consumer-facing `IC*`
8
+ * types are `z.infer`red here and re-exported by `../responses`.
9
+ *
10
+ * Standards mapping: the object matches OpenAI's `conversation`
11
+ * (`id`/`object`/`created_at`/`metadata`); `title`, `smith_id`, and `updated_at`
12
+ * are documented IC extensions OpenAI omits (OpenAI has no title and no list
13
+ * endpoint, both of which a console conversation list needs). `created_at`/
14
+ * `updated_at` are unix-second integers like every OpenAI object, not the ISO
15
+ * strings the native `ic_*` resources use. Items are read-only and reconstructed
16
+ * from the conversation's runs — they accrue from `/v1/responses`, not a write
17
+ * endpoint.
18
+ */
19
+ import { z } from "zod";
20
+ import { pageOut } from "./_page.js";
21
+
22
+ /** A conversation — the OpenAI Conversations object + IC extensions. */
23
+ export const ConversationOut = z
24
+ .object({
25
+ id: z.string(),
26
+ object: z.literal("conversation"),
27
+ /** Unix seconds, like every OpenAI object. */
28
+ created_at: z.number().int(),
29
+ /** Unix seconds of the last run in the conversation (IC extension). */
30
+ updated_at: z.number().int(),
31
+ /** Auto-set from the first user turn of a Responses-API run that names this
32
+ * conversation; null until then. Set it yourself any time. IC extension. */
33
+ title: z.string().nullable(),
34
+ /** The smith that owns this conversation. IC extension. */
35
+ smith_id: z.string(),
36
+ metadata: z.record(z.string(), z.unknown()),
37
+ })
38
+ .meta({ id: "ConversationOut" });
39
+
40
+ export const ConversationListOut = pageOut(ConversationOut, "ConversationListOut");
41
+
42
+ /** The delete acknowledgement, in OpenAI's `*.deleted` shape. */
43
+ export const ConversationDeleted = z
44
+ .object({
45
+ id: z.string(),
46
+ object: z.literal("conversation.deleted"),
47
+ deleted: z.literal(true),
48
+ })
49
+ .meta({ id: "ConversationDeleted" });
50
+
51
+ /** One reconstructed item in a conversation. Modelled loosely on the Responses
52
+ * output items: a `message` carries `content` parts (`input_text`/`output_text`);
53
+ * the tool-step items mirror their wire shapes — `function_call`
54
+ * (`call_id`/`name`/`arguments`) and `function_call_output` (`call_id`/`output`) for
55
+ * client-side tools, `mcp_call` (`name`/`arguments`/`output`/`server_label`) for a
56
+ * tool the run loop executed server-side. */
57
+ export const ConversationItem = z
58
+ .object({
59
+ id: z.string(),
60
+ type: z.string(),
61
+ role: z.string().optional(),
62
+ status: z.string().optional(),
63
+ content: z.array(z.record(z.string(), z.unknown())).optional(),
64
+ // Tool-step fields (present on function_call / function_call_output / mcp_call).
65
+ call_id: z.string().optional(),
66
+ name: z.string().optional(),
67
+ arguments: z.string().optional(),
68
+ output: z.string().optional(),
69
+ server_label: z.string().optional(),
70
+ })
71
+ .meta({ id: "ConversationItem" });
72
+
73
+ /** A conversation's items, in OpenAI's `list` envelope (not the IC cursor page). */
74
+ export const ConversationItemListOut = z
75
+ .object({
76
+ object: z.literal("list"),
77
+ data: z.array(ConversationItem),
78
+ first_id: z.string().nullable(),
79
+ last_id: z.string().nullable(),
80
+ has_more: z.boolean(),
81
+ })
82
+ .meta({ id: "ConversationItemListOut" });
83
+
84
+ /** Create body — OpenAI accepts `metadata`; `title` is the IC extension. */
85
+ export const ConversationCreate = z
86
+ .object({
87
+ title: z.string().optional(),
88
+ metadata: z.record(z.string(), z.unknown()).optional(),
89
+ })
90
+ .meta({ id: "ConversationCreate" });
91
+
92
+ /** Update body — set the title and/or merge metadata. */
93
+ export const ConversationUpdate = z
94
+ .object({
95
+ title: z.string().optional(),
96
+ metadata: z.record(z.string(), z.unknown()).optional(),
97
+ })
98
+ .meta({ id: "ConversationUpdate" });
99
+
100
+ // ── Inferred consumer-facing types (re-exported by ../responses) ─────────────
101
+
102
+ export type ICConversation = z.infer<typeof ConversationOut>;
103
+ export type ICConversationItem = z.infer<typeof ConversationItem>;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `customers` resource — the wire's source of
3
+ * truth, replacing the loose generated shapes for this resource.
4
+ *
5
+ * One source, three outputs: the API imports these into its `createRoute`
6
+ * definitions (validation + emitted OpenAPI), and the consumer-facing `IC*`
7
+ * types are `z.infer`red from them here and re-exported by `../responses`. No
8
+ * Zod is pulled into a type-only consumer — `responses.ts` re-exports these as
9
+ * `export type`.
10
+ *
11
+ * A customer is the *tenant's* billable party for its smiths (never ours); many
12
+ * smiths roll up to one customer, so `smith_count` is a correlated count.
13
+ *
14
+ * `.meta({ id })` names the component so the emitted OpenAPI references it as
15
+ * `#/components/schemas/<id>` rather than inlining it.
16
+ */
17
+ import { z } from "zod";
18
+
19
+ export const CustomerOut = z
20
+ .object({
21
+ id: z.string(),
22
+ name: z.string(),
23
+ /** Opaque external system → id map (e.g. CRM/billing keys). */
24
+ external_ids: z.record(z.string(), z.string()),
25
+ /** Free-form tenant annotations. */
26
+ metadata: z.record(z.string(), z.unknown()),
27
+ /** Active smiths rolling up to this customer; present on single-customer reads. */
28
+ smith_count: z.number().int().optional(),
29
+ created_at: z.string().nullable(),
30
+ })
31
+ .meta({ id: "CustomerOut" });
32
+
33
+ /** Paginated list envelope: keyset cursor over `created_at, id` (desc). */
34
+ export const CustomerListOut = z
35
+ .object({
36
+ data: z.array(CustomerOut),
37
+ next_cursor: z.string().nullable(),
38
+ has_more: z.boolean(),
39
+ })
40
+ .meta({ id: "CustomerListOut" });
41
+
42
+ // ── Request bodies ──────────────────────────────────────────────────────────
43
+
44
+ export const CustomerCreate = z
45
+ .object({
46
+ name: z.string(),
47
+ external_ids: z.record(z.string(), z.string()).optional(),
48
+ metadata: z.record(z.string(), z.unknown()).optional(),
49
+ })
50
+ .meta({ id: "CustomerCreate" });
51
+
52
+ export const CustomerPatch = z
53
+ .object({
54
+ name: z.string().nullish(),
55
+ external_ids: z.record(z.string(), z.string()).nullish(),
56
+ metadata: z.record(z.string(), z.unknown()).nullish(),
57
+ })
58
+ .meta({ id: "CustomerPatch" });
59
+
60
+ // ── Inferred consumer-facing types (re-exported by ../responses) ─────────────
61
+
62
+ export type ICCustomer = z.infer<typeof CustomerOut>;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `deployments` resource — messaging endpoints
3
+ * attached to a smith (Telegram/WhatsApp/Slack/SMS/voice/email).
4
+ *
5
+ * One source, three outputs: the API imports these into its `createRoute`
6
+ * definitions (validation + emitted OpenAPI), and the consumer-facing `IC*`
7
+ * types are `z.infer`red from them here and re-exported by `../responses`. No
8
+ * Zod is pulled into a type-only consumer — `responses.ts` re-exports these as
9
+ * `export type`.
10
+ *
11
+ * `.meta({ id })` names the component so the emitted OpenAPI references it as
12
+ * `#/components/schemas/<id>` rather than inlining it.
13
+ *
14
+ * Two response shapes on purpose: `DeploymentOut` is the plain serializer
15
+ * (`api/src/runtime/deployments.ts::publicDeployment`) returned by GET/list, PATCH,
16
+ * and the email `provision` create. `DeploymentCreatedOut` is the richer create
17
+ * response — the deferred-setup gateways (telegram/whatsapp `start_token`,
18
+ * slack `provision`/`oauth_install`) hand back binding affordances on top of
19
+ * the base shape (`start_token` + `deep_link`, slack's `install_url`/`state`,
20
+ * …). The relic `DeploymentOut` did NOT document these create-only fields; the
21
+ * handler is the truth, so they live here as optionals.
22
+ */
23
+ import { z } from "zod";
24
+ import { pageOut } from "./_page.js";
25
+
26
+ /** A deployment's target: a fixed `smith` (one running clone) or an `agent`
27
+ * catch-all that mints a fresh smith per inbound sender. */
28
+ export const DeploymentTarget = z
29
+ .object({ type: z.enum(["smith", "agent"]), id: z.string() })
30
+ .meta({ id: "DeploymentTarget" });
31
+
32
+ export const DeploymentOut = z
33
+ .object({
34
+ id: z.string(),
35
+ target: DeploymentTarget,
36
+ kind: z.string(),
37
+ address: z.string().nullable(),
38
+ provider: z.string().nullable(),
39
+ provider_metadata: z.record(z.string(), z.unknown()).optional(),
40
+ /** Names of the encrypted secret fields that are set (values never returned). */
41
+ secret_keys: z.array(z.string()).optional(),
42
+ status: z.string(),
43
+ created_at: z.string().nullable(),
44
+ })
45
+ .meta({ id: "DeploymentOut" });
46
+
47
+ export const DeploymentListOut = pageOut(DeploymentOut, "DeploymentListOut");
48
+
49
+ /**
50
+ * The richer create response. Beyond the base `DeploymentOut`, the setup gateways
51
+ * attach provider-specific binding affordances:
52
+ * - telegram `start_token`: `start_token`, `deep_link` (t.me link).
53
+ * - whatsapp `start_token`: `start_token`, `prefilled_message`, `deep_link` (wa.me link).
54
+ * - slack `provision`/`oauth_install`: `install_url`, `state`, optional `slack_app_id`.
55
+ * - email `provision`: no extras (plain `DeploymentOut`).
56
+ * All are optional — which appear depends on the kind + setup mode.
57
+ */
58
+ export const DeploymentCreatedOut = DeploymentOut.extend({
59
+ start_token: z.string().optional(),
60
+ deep_link: z.string().optional(),
61
+ prefilled_message: z.string().optional(),
62
+ install_url: z.string().optional(),
63
+ state: z.string().optional(),
64
+ slack_app_id: z.string().optional(),
65
+ }).meta({ id: "DeploymentCreatedOut" });
66
+
67
+ // ── Request bodies ──────────────────────────────────────────────────────────
68
+
69
+ export const DeploymentIn = z
70
+ .object({
71
+ /** Who the deployment binds: a `smith` (fixed) or an `agent` (mints a smith
72
+ * per inbound sender). A smith token may only target its own smith. */
73
+ target: DeploymentTarget,
74
+ kind: z.string(),
75
+ address: z.string().nullish(),
76
+ provider: z.string().nullish(),
77
+ provider_metadata: z.record(z.string(), z.unknown()).optional(),
78
+ secrets: z.record(z.string(), z.unknown()).optional(),
79
+ setup: z.record(z.string(), z.unknown()).nullish(),
80
+ })
81
+ .meta({ id: "DeploymentIn" });
82
+
83
+ export const DeploymentPatch = z
84
+ .object({
85
+ display_name: z.string().nullish(),
86
+ owner_email: z.string().nullish(),
87
+ })
88
+ .meta({ id: "DeploymentPatch" });
89
+
90
+ // ── Inferred consumer-facing types (re-exported by ../responses) ─────────────
91
+
92
+ export type ICDeployment = z.infer<typeof DeploymentOut>;
93
+ export type ICDeploymentCreated = z.infer<typeof DeploymentCreatedOut>;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `discord` channel-config resource — the wire's
3
+ * source of truth, mirroring `telegram.ts`.
4
+ *
5
+ * Discord is delivered over its HTTP Interactions endpoint: the tenant registers one
6
+ * Discord application (its public key + a bot token) and Ingram Cloud verifies every
7
+ * inbound interaction's Ed25519 signature with that public key, so there is no shared
8
+ * webhook secret. Secrets are never returned.
9
+ */
10
+ import { z } from "zod";
11
+
12
+ /**
13
+ * The tenant's Discord app config status. The bot token is never returned; the
14
+ * optional fields are present once `configured` is true. `webhook_url` is the
15
+ * Interactions Endpoint URL to register in the Discord Developer Portal.
16
+ */
17
+ export const DiscordAppOut = z
18
+ .object({
19
+ configured: z.boolean(),
20
+ application_id: z.string().optional(),
21
+ public_key: z.string().optional(),
22
+ has_bot_token: z.boolean().optional(),
23
+ webhook_url: z.string().optional(),
24
+ })
25
+ .meta({ id: "DiscordAppOut" });
26
+
27
+ // ── Request bodies ──────────────────────────────────────────────────────────
28
+
29
+ export const DiscordAppIn = z
30
+ .object({
31
+ application_id: z.string(),
32
+ public_key: z.string(),
33
+ bot_token: z.string(),
34
+ })
35
+ .meta({ id: "DiscordAppIn" });
36
+
37
+ // ── Inferred consumer-facing types (re-exported by ../responses) ─────────────
38
+
39
+ export type ICDiscordApp = z.infer<typeof DiscordAppOut>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `email` channel-config resource — the
3
+ * wire's source of truth for the tenant Cloudflare sending config.
4
+ *
5
+ * One source, three outputs: the API imports these into its `createRoute`
6
+ * definitions (validation + emitted OpenAPI), and the consumer-facing `IC*`
7
+ * type is `z.infer`red from `EmailConfigOut` here and re-exported by
8
+ * `../responses` as `export type` — no Zod is pulled into a type-only consumer.
9
+ *
10
+ * `.meta({ id })` names the component so the emitted OpenAPI references it as
11
+ * `#/components/schemas/<id>` rather than inlining it.
12
+ *
13
+ * The out shape is the union of two builders in `api/src/routes/email.ts`
14
+ * (via `runtime/email.ts`):
15
+ * - GET `/v1/tenant/email` (`configStatus`) — `{ configured: false }`, or
16
+ * `{ configured: true, from_domain, display_name, has_token, inbound_url }`.
17
+ * - PUT `/v1/tenant/email` (`configureEmail`) — `{ configured: true,
18
+ * from_domain, display_name, inbound_url, inbound_secret }`.
19
+ * Hence `configured` is the only required field; everything else is optional,
20
+ * and `inbound_secret` is present only on the PUT response (shown once).
21
+ */
22
+ import { z } from "zod";
23
+
24
+ export const EmailConfigOut = z
25
+ .object({
26
+ /** False when the tenant has no email config; true otherwise. */
27
+ configured: z.boolean(),
28
+ from_domain: z.string().optional(),
29
+ display_name: z.string().nullish(),
30
+ /** Present on GET when configured — the API token is never returned. */
31
+ has_token: z.boolean().optional(),
32
+ inbound_url: z.string().optional(),
33
+ /** Only present on PUT (shown once) — wire it into the inbound worker. */
34
+ inbound_secret: z.string().optional(),
35
+ })
36
+ .meta({ id: "EmailConfigOut" });
37
+
38
+ // ── Request body ─────────────────────────────────────────────────────────────
39
+
40
+ export const EmailConfigIn = z
41
+ .object({
42
+ cloudflare_account_id: z.string(),
43
+ cloudflare_api_token: z.string(),
44
+ from_domain: z.string(),
45
+ display_name: z.string().nullish(),
46
+ inbound_secret: z.string().nullish(),
47
+ })
48
+ .meta({ id: "EmailConfigIn" });
49
+
50
+ // ── Inferred consumer-facing type (re-exported by ../responses) ──────────────
51
+
52
+ export type ICEmailConfig = z.infer<typeof EmailConfigOut>;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `files` resource — the wire's source of
3
+ * truth, mapped onto the OpenAI **Files API** so an OpenAI client library talks
4
+ * to it unchanged.
5
+ *
6
+ * The File object is exactly OpenAI's (`status`/`status_details` included, inert
7
+ * upstream and here). Upload is `multipart/form-data`, so there is no `In`
8
+ * schema — the route reads the form directly. The list uses OpenAI's `list`
9
+ * envelope with `after`/`limit`/`order` paging and enumerates Files-API uploads
10
+ * only; files inlined into a conversation stay reachable by id but are not
11
+ * listed.
12
+ */
13
+ import { z } from "zod";
14
+
15
+ /** OpenAI's upload purposes. Vector-store source files are `assistants`. */
16
+ export const FilePurpose = z.enum([
17
+ "assistants",
18
+ "batch",
19
+ "fine-tune",
20
+ "vision",
21
+ "user_data",
22
+ "evals",
23
+ ]);
24
+
25
+ /** The OpenAI File object. */
26
+ export const FileOut = z
27
+ .object({
28
+ id: z.string(),
29
+ object: z.literal("file"),
30
+ bytes: z.number().int(),
31
+ /** Unix seconds, like every OpenAI object. */
32
+ created_at: z.number().int(),
33
+ filename: z.string(),
34
+ purpose: z.string(),
35
+ /** Deprecated upstream; always `processed` here. */
36
+ status: z.literal("processed"),
37
+ status_details: z.null(),
38
+ })
39
+ .meta({ id: "FileOut" });
40
+
41
+ /** Files, in OpenAI's `list` envelope (not the IC cursor page). */
42
+ export const FileListOut = z
43
+ .object({
44
+ object: z.literal("list"),
45
+ data: z.array(FileOut),
46
+ first_id: z.string().nullable(),
47
+ last_id: z.string().nullable(),
48
+ has_more: z.boolean(),
49
+ })
50
+ .meta({ id: "FileListOut" });
51
+
52
+ /** The delete acknowledgement, in OpenAI's `*.deleted` shape. */
53
+ export const FileDeleted = z
54
+ .object({
55
+ id: z.string(),
56
+ object: z.literal("file"),
57
+ deleted: z.literal(true),
58
+ })
59
+ .meta({ id: "FileDeleted" });
60
+
61
+ export type ICFile = z.infer<typeof FileOut>;
62
+ export type ICFileList = z.infer<typeof FileListOut>;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Hand-authored Zod schemas — the wire's source of truth, one resource module
3
+ * per file. The API imports these into its `createRoute` definitions (runtime
4
+ * validation + emitted OpenAPI); `../responses` re-exports the `z.infer`red
5
+ * `IC*` types from them.
6
+ *
7
+ * Resources are migrated here off the generated `../schemas.ts` one at a time;
8
+ * when the last one lands, the generated file and the `openapi-zod-client` step
9
+ * are deleted and this becomes the sole `schemas` source.
10
+ */
11
+ export * from "./_page.js";
12
+ export * from "./agents.js";
13
+ export * from "./approvals.js";
14
+ export * from "./budgets.js";
15
+ export * from "./catalog.js";
16
+ export * from "./connections.js";
17
+ export * from "./conversations.js";
18
+ export * from "./deployments.js";
19
+ export * from "./customers.js";
20
+ export * from "./discord.js";
21
+ export * from "./email.js";
22
+ export * from "./files.js";
23
+ export * from "./mcp.js";
24
+ export * from "./memories.js";
25
+ export * from "./observability.js";
26
+ export * from "./projects.js";
27
+ export * from "./runs.js";
28
+ export * from "./schedules.js";
29
+ export * from "./slack.js";
30
+ export * from "./smith-revisions.js";
31
+ export * from "./smiths.js";
32
+ export * from "./telegram.js";
33
+ export * from "./tenant.js";
34
+ export * from "./vector-stores.js";
35
+ export * from "./whatsapp.js";
package/ts/zod/mcp.ts ADDED
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Hand-authored Zod schemas for the `mcp` resource — the tenant config plane for
3
+ * registering third-party MCP tool servers (`/v1/tenant/mcp/...`).
4
+ *
5
+ * One source, three outputs: the API imports these into its `createRoute`
6
+ * definitions (validation + emitted OpenAPI), and the consumer-facing `IC*`
7
+ * types are `z.infer`red from them here and re-exported by `../responses`. No
8
+ * Zod is pulled into a type-only consumer — `responses.ts` re-exports these as
9
+ * `export type`.
10
+ *
11
+ * `.meta({ id })` names the component so the emitted OpenAPI references it as
12
+ * `#/components/schemas/<id>` rather than inlining it. `ApprovalRule` and
13
+ * `McpTool` are standalone named schemas referenced by `McpServerOut`, so they
14
+ * emit as `$ref` components rather than inlined objects.
15
+ */
16
+ import { z } from "zod";
17
+
18
+ /** One approval-policy rule: a name glob that gates matching tools behind a
19
+ * human approval. `require` is always `"approval"` today (the only supported
20
+ * value); arg-conditional (`when`) gating is rejected, not stored. */
21
+ export const ApprovalRule = z
22
+ .object({
23
+ match: z.string(),
24
+ require: z.string().optional(),
25
+ })
26
+ .meta({ id: "ApprovalRule" });
27
+
28
+ /** The rule shape on *input* (`McpServerIn.approval_policy`). Loose, so unknown
29
+ * clauses (e.g. an arg-conditional `when`) reach the handler, which rejects them
30
+ * with its own `unsupported_policy_rule` (422) rather than being silently
31
+ * stripped by a strict object. */
32
+ export const ApprovalRuleIn = z.looseObject({
33
+ match: z.string(),
34
+ require: z.string().optional(),
35
+ });
36
+
37
+ /** A discovered MCP tool, with its *effective* gating folded in by the
38
+ * serializer: `enabled` reflects the default-deny `tool_allowlist`,
39
+ * `requires_approval` folds the server's destructive hint with the approval
40
+ * policy. */
41
+ export const McpTool = z
42
+ .object({
43
+ name: z.string(),
44
+ description: z.string().nullable(),
45
+ /** Effective gate: server destructiveHint OR an approval_policy match. */
46
+ requires_approval: z.boolean(),
47
+ /** Passes the default-deny tool_allowlist (always true when no allow-list). */
48
+ enabled: z.boolean(),
49
+ })
50
+ .meta({ id: "McpTool" });
51
+
52
+ /** Secret-free auth descriptor returned for a registered server. */
53
+ export const McpAuth = z
54
+ .object({
55
+ kind: z.string(),
56
+ provider: z.string().nullable(),
57
+ client_mode: z.string().optional(),
58
+ })
59
+ .meta({ id: "McpAuth" });
60
+
61
+ export const McpServerOut = z
62
+ .object({
63
+ id: z.string(),
64
+ name: z.string(),
65
+ url: z.string(),
66
+ auth: McpAuth,
67
+ /** tenant_owned | tenant_registered | catalog. */
68
+ origin: z.string().optional(),
69
+ catalog_slug: z.string().nullish(),
70
+ /** null = expose all discovered tools; otherwise the default-deny set. */
71
+ tool_allowlist: z.array(z.string()).nullish(),
72
+ approval_policy: z.array(ApprovalRule).optional(),
73
+ tools: z.array(McpTool),
74
+ tools_refreshed_at: z.string().nullable(),
75
+ /** `degraded` when the edge failed discovery or its secret can't be decoded
76
+ * at run time; otherwise the stored lifecycle status. */
77
+ status: z.string(),
78
+ /** Last discovery/runtime-load failure, or null when the edge is healthy. */
79
+ discovery_error: z.string().nullable(),
80
+ created_at: z.string().nullable(),
81
+ })
82
+ .meta({ id: "McpServerOut" });
83
+
84
+ export const McpServerListOut = z
85
+ .object({ data: z.array(McpServerOut) })
86
+ .meta({ id: "McpServerListOut" });
87
+
88
+ /** Register/replace and refresh echo the server back plus the count of tools
89
+ * discovered in the just-run `tools/list`. */
90
+ export const McpServerWriteOut = McpServerOut.extend({
91
+ tools_discovered: z.number().int(),
92
+ }).meta({ id: "McpServerWriteOut" });
93
+
94
+ // ── Request bodies ──────────────────────────────────────────────────────────
95
+
96
+ /** Auth block on a register/replace body. `secret` is write-only (a static
97
+ * bearer) — never echoed back. */
98
+ export const McpAuthIn = z
99
+ .object({
100
+ kind: z.string().nullish(),
101
+ provider: z.string().nullish(),
102
+ secret: z.string().nullish(),
103
+ client_mode: z.string().nullish(),
104
+ })
105
+ .meta({ id: "McpAuthIn" });
106
+
107
+ /** Register or replace a server: supply a raw `url` + `auth`, or a `catalog`
108
+ * slug (catalog defaults are stamped down, body fields override). */
109
+ export const McpServerIn = z
110
+ .object({
111
+ url: z.string().nullish(),
112
+ catalog: z.string().nullish(),
113
+ auth: McpAuthIn.nullish(),
114
+ tool_allowlist: z.array(z.string()).nullish(),
115
+ approval_policy: z.array(ApprovalRuleIn).nullish(),
116
+ })
117
+ .meta({ id: "McpServerIn" });
118
+
119
+ // ── Inferred consumer-facing types (re-exported by ../responses) ─────────────
120
+
121
+ export type ICMcpTool = z.infer<typeof McpTool>;
122
+ export type ICApprovalRule = z.infer<typeof ApprovalRule>;
123
+ export type ICMcpServer = z.infer<typeof McpServerOut>;