primcli 1.19.0 → 1.21.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 (2) hide show
  1. package/dist/oclif/index.js +1891 -12
  2. package/package.json +4 -1
@@ -1,12 +1,13 @@
1
1
  import { A as saveActiveChatState, C as resolveCliAuth, D as deleteChatState, E as chatStatePath, M as createClient, N as createConfig, O as loadActiveChatState, S as normalizeApiBaseUrl, T as saveSignupCredentials, _ as deleteCliCredentials, a as normalizeCliEnvironmentName, b as hasStoredCliLogin, c as resolveConfigEnvironment, d as validateCliHeaderName, f as validateCliHeaderValue, g as credentialsPath, h as credentialsLockPath, i as loadCliConfig, j as PrimitiveApiClient, k as loadChatConversationByLocalId, l as saveCliConfig, m as cliAccessTokenExpiresAt, n as deleteCliConfig, o as redactCliEnvironment, p as acquireCliCredentialsLock, r as emptyCliConfig, s as removeCliEnvironment, u as upsertCliEnvironment, v as deleteCliCredentialsLock, w as saveCliCredentials, x as loadCliCredentials, y as detectPrimitiveKeyEnvMisname } from "../cli-config-BKso8oJu.js";
2
2
  import { Args, Command, Errors, Flags, ux } from "@oclif/core";
3
- import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
3
+ import { chmodSync, closeSync, createWriteStream, existsSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import path, { basename, dirname, join, relative, resolve, sep } from "node:path";
6
6
  import process$1 from "node:process";
7
7
  import { createInterface } from "node:readline/promises";
8
8
  import { hostname } from "node:os";
9
9
  import { spawn } from "node:child_process";
10
+ import { open, rm, stat } from "node:fs/promises";
10
11
  import { gunzipSync } from "node:zlib";
11
12
  import { concat, getAddress, hexToBytes, keccak256, stringToBytes } from "viem";
12
13
  import { privateKeyToAccount } from "viem/accounts";
@@ -76,9 +77,12 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
76
77
  getSentEmail: () => getSentEmail,
77
78
  getSpendPolicy: () => getSpendPolicy,
78
79
  getStorageStats: () => getStorageStats,
80
+ getTemplate: () => getTemplate,
81
+ getTemplateInstall: () => getTemplateInstall,
79
82
  getThread: () => getThread,
80
83
  getWakeSchedule: () => getWakeSchedule,
81
84
  getWebhookSecret: () => getWebhookSecret,
85
+ installTemplate: () => installTemplate,
82
86
  listDeclinedPayments: () => listDeclinedPayments,
83
87
  listDeliveries: () => listDeliveries,
84
88
  listDomains: () => listDomains,
@@ -95,6 +99,7 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
95
99
  listRegistryRequests: () => listRegistryRequests,
96
100
  listRoutes: () => listRoutes,
97
101
  listSentEmails: () => listSentEmails,
102
+ listTemplates: () => listTemplates,
98
103
  listWakeAuthorizations: () => listWakeAuthorizations,
99
104
  listWakeDispatches: () => listWakeDispatches,
100
105
  listWakeSchedules: () => listWakeSchedules,
@@ -2025,6 +2030,65 @@ const searchMemories = (options) => (options?.client ?? client).get({
2025
2030
  ...options
2026
2031
  });
2027
2032
  /**
2033
+ * List function templates
2034
+ *
2035
+ * List approved Function templates available for browsing and
2036
+ * installation. Results are cacheable and paginated with
2037
+ * `data.next_cursor`.
2038
+ *
2039
+ */
2040
+ const listTemplates = (options) => (options?.client ?? client).get({
2041
+ url: "/templates",
2042
+ ...options
2043
+ });
2044
+ /**
2045
+ * Get a function template
2046
+ *
2047
+ * Fetch one approved Function template by slug, including its manifest
2048
+ * snapshot and README. The stored source files used for install are not
2049
+ * returned.
2050
+ *
2051
+ */
2052
+ const getTemplate = (options) => (options.client ?? client).get({
2053
+ url: "/templates/{id}",
2054
+ ...options
2055
+ });
2056
+ /**
2057
+ * Install a function template
2058
+ *
2059
+ * Start a one-shot deploy of an approved deploy-mode Function template.
2060
+ * The response returns an install record immediately; poll
2061
+ * `GET /templates/installs/{id}` for progress.
2062
+ *
2063
+ */
2064
+ const installTemplate = (options) => (options.client ?? client).post({
2065
+ security: [{
2066
+ scheme: "bearer",
2067
+ type: "http"
2068
+ }],
2069
+ url: "/templates/{id}/install",
2070
+ ...options,
2071
+ headers: {
2072
+ ...options.body !== void 0 && { "Content-Type": "application/json" },
2073
+ ...options.headers
2074
+ }
2075
+ });
2076
+ /**
2077
+ * Get template install status
2078
+ *
2079
+ * Fetch the current state of a template install. Reads may advance the
2080
+ * self-test phase when a reply effect has been observed.
2081
+ *
2082
+ */
2083
+ const getTemplateInstall = (options) => (options.client ?? client).get({
2084
+ security: [{
2085
+ scheme: "bearer",
2086
+ type: "http"
2087
+ }],
2088
+ url: "/templates/installs/{id}",
2089
+ ...options
2090
+ });
2091
+ /**
2028
2092
  * List payout addresses
2029
2093
  *
2030
2094
  * List your org's registered payout addresses, newest first.
@@ -2460,6 +2524,10 @@ const openapiDocument = {
2460
2524
  "name": "Memories",
2461
2525
  "description": "Durable org-scoped or function-scoped JSON key-value storage for\nagents and functions. Keys are caller-defined. Function scope is\nalways addressed by the function id UUID, not by function name.\n"
2462
2526
  },
2527
+ {
2528
+ "name": "Templates",
2529
+ "description": "Browse approved Function templates, install deploy-mode templates, and\npoll install progress.\n"
2530
+ },
2463
2531
  {
2464
2532
  "name": "Registries",
2465
2533
  "description": "The Agent Registry: ownable directories of agents, addressable by a\nregistry-scoped handle. A registry's publish policy (owner_only, request,\nor open) decides whether a publish lists immediately or pends owner\napproval. An agent is defined once with a globally unique,\nreachability-verified address, then published into any registry under a\nhandle. Discovery reads (list, resolve, get) are public for public\nregistries; managing a registry and moderating requests use the owner's\nAPI key.\n"
@@ -5285,6 +5353,167 @@ const openapiDocument = {
5285
5353
  "429": { "$ref": "#/components/responses/RateLimited" }
5286
5354
  }
5287
5355
  } },
5356
+ "/templates": { "get": {
5357
+ "operationId": "listTemplates",
5358
+ "summary": "List function templates",
5359
+ "description": "List approved Function templates available for browsing and\ninstallation. Results are cacheable and paginated with\n`data.next_cursor`.\n",
5360
+ "tags": ["Templates"],
5361
+ "security": [],
5362
+ "parameters": [
5363
+ {
5364
+ "name": "q",
5365
+ "in": "query",
5366
+ "required": false,
5367
+ "description": "Search templates by title, summary, or slug.",
5368
+ "schema": {
5369
+ "type": "string",
5370
+ "minLength": 1
5371
+ }
5372
+ },
5373
+ {
5374
+ "name": "tag",
5375
+ "in": "query",
5376
+ "required": false,
5377
+ "description": "Filter templates by an exact tag.",
5378
+ "schema": {
5379
+ "type": "string",
5380
+ "minLength": 1
5381
+ }
5382
+ },
5383
+ {
5384
+ "name": "cursor",
5385
+ "in": "query",
5386
+ "required": false,
5387
+ "description": "Cursor from a previous response `data.next_cursor` value.",
5388
+ "schema": { "type": "string" }
5389
+ },
5390
+ {
5391
+ "name": "limit",
5392
+ "in": "query",
5393
+ "required": false,
5394
+ "description": "Maximum number of templates to return. The server caps this at 100.",
5395
+ "schema": {
5396
+ "type": "integer",
5397
+ "minimum": 1,
5398
+ "maximum": 100,
5399
+ "default": 50
5400
+ }
5401
+ }
5402
+ ],
5403
+ "responses": {
5404
+ "200": {
5405
+ "description": "Paginated template registry summaries",
5406
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
5407
+ "type": "object",
5408
+ "properties": { "data": { "$ref": "#/components/schemas/TemplateRegistryPage" } },
5409
+ "required": ["data"]
5410
+ }] } } }
5411
+ },
5412
+ "400": { "$ref": "#/components/responses/ValidationError" },
5413
+ "429": { "$ref": "#/components/responses/RateLimited" }
5414
+ }
5415
+ } },
5416
+ "/templates/{id}": { "get": {
5417
+ "operationId": "getTemplate",
5418
+ "summary": "Get a function template",
5419
+ "description": "Fetch one approved Function template by slug, including its manifest\nsnapshot and README. The stored source files used for install are not\nreturned.\n",
5420
+ "tags": ["Templates"],
5421
+ "security": [],
5422
+ "parameters": [{
5423
+ "name": "id",
5424
+ "in": "path",
5425
+ "required": true,
5426
+ "description": "Template slug from the template manifest.",
5427
+ "schema": {
5428
+ "type": "string",
5429
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$"
5430
+ }
5431
+ }],
5432
+ "responses": {
5433
+ "200": {
5434
+ "description": "Template registry detail",
5435
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
5436
+ "type": "object",
5437
+ "properties": { "data": { "$ref": "#/components/schemas/TemplateRegistryDetail" } },
5438
+ "required": ["data"]
5439
+ }] } } }
5440
+ },
5441
+ "400": { "$ref": "#/components/responses/ValidationError" },
5442
+ "404": { "$ref": "#/components/responses/NotFound" },
5443
+ "429": { "$ref": "#/components/responses/RateLimited" }
5444
+ }
5445
+ } },
5446
+ "/templates/{id}/install": { "post": {
5447
+ "operationId": "installTemplate",
5448
+ "summary": "Install a function template",
5449
+ "description": "Start a one-shot deploy of an approved deploy-mode Function template.\nThe response returns an install record immediately; poll\n`GET /templates/installs/{id}` for progress.\n",
5450
+ "tags": ["Templates"],
5451
+ "security": [{ "BearerAuth": [] }],
5452
+ "parameters": [{
5453
+ "name": "id",
5454
+ "in": "path",
5455
+ "required": true,
5456
+ "description": "Template slug from the template manifest.",
5457
+ "schema": {
5458
+ "type": "string",
5459
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$"
5460
+ }
5461
+ }],
5462
+ "requestBody": {
5463
+ "required": true,
5464
+ "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InstallTemplateBody" } } }
5465
+ },
5466
+ "responses": {
5467
+ "201": {
5468
+ "description": "Template install started",
5469
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
5470
+ "type": "object",
5471
+ "properties": { "data": { "$ref": "#/components/schemas/TemplateInstallStatus" } },
5472
+ "required": ["data"]
5473
+ }] } } }
5474
+ },
5475
+ "400": { "$ref": "#/components/responses/ValidationError" },
5476
+ "401": { "$ref": "#/components/responses/Unauthorized" },
5477
+ "403": { "$ref": "#/components/responses/Forbidden" },
5478
+ "404": { "$ref": "#/components/responses/NotFound" },
5479
+ "409": { "$ref": "#/components/responses/Conflict" },
5480
+ "422": { "$ref": "#/components/responses/UnprocessableEntity" },
5481
+ "429": { "$ref": "#/components/responses/RateLimited" }
5482
+ }
5483
+ } },
5484
+ "/templates/installs/{id}": { "get": {
5485
+ "operationId": "getTemplateInstall",
5486
+ "summary": "Get template install status",
5487
+ "description": "Fetch the current state of a template install. Reads may advance the\nself-test phase when a reply effect has been observed.\n",
5488
+ "tags": ["Templates"],
5489
+ "security": [{ "BearerAuth": [] }],
5490
+ "parameters": [{
5491
+ "name": "id",
5492
+ "in": "path",
5493
+ "required": true,
5494
+ "description": "Template install UUID.",
5495
+ "schema": {
5496
+ "type": "string",
5497
+ "format": "uuid",
5498
+ "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
5499
+ }
5500
+ }],
5501
+ "responses": {
5502
+ "200": {
5503
+ "description": "Current template install status",
5504
+ "content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
5505
+ "type": "object",
5506
+ "properties": { "data": { "$ref": "#/components/schemas/TemplateInstallStatus" } },
5507
+ "required": ["data"]
5508
+ }] } } }
5509
+ },
5510
+ "400": { "$ref": "#/components/responses/ValidationError" },
5511
+ "401": { "$ref": "#/components/responses/Unauthorized" },
5512
+ "403": { "$ref": "#/components/responses/Forbidden" },
5513
+ "404": { "$ref": "#/components/responses/NotFound" },
5514
+ "429": { "$ref": "#/components/responses/RateLimited" }
5515
+ }
5516
+ } },
5288
5517
  "/x402/payout-addresses": {
5289
5518
  "post": {
5290
5519
  "operationId": "registerPayoutAddress",
@@ -6955,6 +7184,16 @@ const openapiDocument = {
6955
7184
  "org_not_accessible",
6956
7185
  "feature_disabled",
6957
7186
  "memory_conflict",
7187
+ "template_not_installable",
7188
+ "scaffold_only",
7189
+ "invalid_variables",
7190
+ "unknown_secrets",
7191
+ "missing_secrets",
7192
+ "no_inbound_domain",
7193
+ "domain_cannot_send",
7194
+ "address_taken",
7195
+ "route_cap_reached",
7196
+ "name_exhausted",
6958
7197
  "developer_usage_credit_exhausted",
6959
7198
  "no_payout_address",
6960
7199
  "ownership_proof_failed",
@@ -9003,6 +9242,40 @@ const openapiDocument = {
9003
9242
  },
9004
9243
  "required": ["filename", "content_base64"]
9005
9244
  },
9245
+ "SendMailPayloadRef": {
9246
+ "type": "object",
9247
+ "additionalProperties": false,
9248
+ "description": "A reference to an already-uploaded Primitive Payloads object, delivered as an attachment without inlining the bytes — the way to send an attachment larger than the inline cap. Upload the object via /v1/payloads (with a client-held CEK the server never sees), then reference it here.",
9249
+ "properties": {
9250
+ "root": {
9251
+ "type": "string",
9252
+ "pattern": "^[0-9a-f]{64}$",
9253
+ "description": "The 64-char lowercase-hex Merkle root of a finalized payloads object."
9254
+ },
9255
+ "filename": {
9256
+ "type": "string",
9257
+ "minLength": 1,
9258
+ "maxLength": 255,
9259
+ "description": "Attachment filename presented to the recipient."
9260
+ },
9261
+ "content_type": {
9262
+ "type": "string",
9263
+ "minLength": 1,
9264
+ "maxLength": 255,
9265
+ "description": "Optional MIME content type."
9266
+ },
9267
+ "cek": {
9268
+ "type": "string",
9269
+ "pattern": "^[A-Za-z0-9_-]{1,128}$",
9270
+ "description": "Base64url-encoded (unpadded) content-encryption key the recipient uses to decrypt. Travels with the email; the object store only ever holds ciphertext."
9271
+ }
9272
+ },
9273
+ "required": [
9274
+ "root",
9275
+ "filename",
9276
+ "cek"
9277
+ ]
9278
+ },
9006
9279
  "SendMailInput": {
9007
9280
  "type": "object",
9008
9281
  "additionalProperties": false,
@@ -9057,6 +9330,12 @@ const openapiDocument = {
9057
9330
  "description": "Inline attachments. Send requests with attachments to https://api.primitive.dev/v1/send-mail. Combined raw decoded attachment bytes must be at most 31457280.",
9058
9331
  "items": { "$ref": "#/components/schemas/SendMailAttachment" }
9059
9332
  },
9333
+ "payload_attachments": {
9334
+ "type": "array",
9335
+ "maxItems": 1,
9336
+ "description": "Deliver an already-uploaded Primitive Payloads object as an attachment by reference, without inlining the bytes — the way to send attachments larger than the inline cap. Upload the object via /v1/payloads (client-held CEK), then reference it here. v1 supports at most one.",
9337
+ "items": { "$ref": "#/components/schemas/SendMailPayloadRef" }
9338
+ },
9060
9339
  "wait": {
9061
9340
  "type": "boolean",
9062
9341
  "description": "When true, wait for the first downstream SMTP delivery outcome before returning."
@@ -11697,6 +11976,476 @@ const openapiDocument = {
11697
11976
  "key",
11698
11977
  "scope"
11699
11978
  ]
11979
+ },
11980
+ "TemplateAuthor": {
11981
+ "type": "object",
11982
+ "additionalProperties": false,
11983
+ "properties": {
11984
+ "id": {
11985
+ "type": "string",
11986
+ "minLength": 1
11987
+ },
11988
+ "name": {
11989
+ "type": "string",
11990
+ "minLength": 1
11991
+ },
11992
+ "url": {
11993
+ "type": "string",
11994
+ "format": "uri"
11995
+ }
11996
+ },
11997
+ "required": ["id", "name"]
11998
+ },
11999
+ "TemplateSource": { "oneOf": [{
12000
+ "type": "object",
12001
+ "additionalProperties": false,
12002
+ "properties": {
12003
+ "mode": {
12004
+ "type": "string",
12005
+ "const": "managed-build"
12006
+ },
12007
+ "dir": {
12008
+ "type": "string",
12009
+ "minLength": 1,
12010
+ "default": "."
12011
+ }
12012
+ },
12013
+ "required": ["mode", "dir"]
12014
+ }, {
12015
+ "type": "object",
12016
+ "additionalProperties": false,
12017
+ "properties": {
12018
+ "mode": {
12019
+ "type": "string",
12020
+ "const": "bundle"
12021
+ },
12022
+ "file": {
12023
+ "type": "string",
12024
+ "minLength": 1
12025
+ }
12026
+ },
12027
+ "required": ["mode", "file"]
12028
+ }] },
12029
+ "TemplateInstall": {
12030
+ "type": "object",
12031
+ "additionalProperties": false,
12032
+ "properties": {
12033
+ "mode": {
12034
+ "type": "string",
12035
+ "enum": ["deploy", "scaffold"]
12036
+ },
12037
+ "editFiles": {
12038
+ "type": "array",
12039
+ "items": {
12040
+ "type": "string",
12041
+ "minLength": 1
12042
+ }
12043
+ },
12044
+ "reason": {
12045
+ "type": "string",
12046
+ "default": ""
12047
+ }
12048
+ },
12049
+ "required": [
12050
+ "mode",
12051
+ "editFiles",
12052
+ "reason"
12053
+ ]
12054
+ },
12055
+ "TemplateSecret": {
12056
+ "type": "object",
12057
+ "additionalProperties": false,
12058
+ "properties": {
12059
+ "key": {
12060
+ "type": "string",
12061
+ "pattern": "^[A-Z_][A-Z0-9_]*$"
12062
+ },
12063
+ "required": {
12064
+ "type": "boolean",
12065
+ "default": true
12066
+ },
12067
+ "description": { "type": "string" }
12068
+ },
12069
+ "required": ["key", "required"]
12070
+ },
12071
+ "TemplateSecretGroup": {
12072
+ "type": "object",
12073
+ "additionalProperties": false,
12074
+ "properties": {
12075
+ "keys": {
12076
+ "type": "array",
12077
+ "minItems": 2,
12078
+ "items": {
12079
+ "type": "string",
12080
+ "pattern": "^[A-Z_][A-Z0-9_]*$"
12081
+ }
12082
+ },
12083
+ "min": {
12084
+ "type": "integer",
12085
+ "minimum": 1,
12086
+ "default": 1
12087
+ },
12088
+ "description": { "type": "string" }
12089
+ },
12090
+ "required": ["keys", "min"]
12091
+ },
12092
+ "TemplateVariableValidation": {
12093
+ "type": "object",
12094
+ "additionalProperties": false,
12095
+ "properties": {
12096
+ "pattern": {
12097
+ "type": "string",
12098
+ "minLength": 1
12099
+ },
12100
+ "maxLength": {
12101
+ "type": "integer",
12102
+ "minimum": 1
12103
+ }
12104
+ }
12105
+ },
12106
+ "TemplateVariable": {
12107
+ "type": "object",
12108
+ "additionalProperties": false,
12109
+ "properties": {
12110
+ "key": {
12111
+ "type": "string",
12112
+ "minLength": 1
12113
+ },
12114
+ "prompt": {
12115
+ "type": "string",
12116
+ "minLength": 1
12117
+ },
12118
+ "default": { "type": "string" },
12119
+ "file": {
12120
+ "type": "string",
12121
+ "minLength": 1
12122
+ },
12123
+ "type": {
12124
+ "type": "string",
12125
+ "enum": [
12126
+ "string",
12127
+ "select",
12128
+ "url",
12129
+ "email"
12130
+ ],
12131
+ "default": "string"
12132
+ },
12133
+ "options": {
12134
+ "type": "array",
12135
+ "items": {
12136
+ "type": "string",
12137
+ "minLength": 1
12138
+ }
12139
+ },
12140
+ "validation": { "$ref": "#/components/schemas/TemplateVariableValidation" }
12141
+ },
12142
+ "required": [
12143
+ "key",
12144
+ "prompt",
12145
+ "type"
12146
+ ]
12147
+ },
12148
+ "TemplateSetup": {
12149
+ "type": "object",
12150
+ "additionalProperties": false,
12151
+ "properties": {
12152
+ "agent": {
12153
+ "type": "string",
12154
+ "minLength": 1
12155
+ },
12156
+ "prompt": {
12157
+ "type": "string",
12158
+ "minLength": 1
12159
+ },
12160
+ "produces": {
12161
+ "type": "array",
12162
+ "items": {
12163
+ "type": "string",
12164
+ "minLength": 1
12165
+ }
12166
+ }
12167
+ },
12168
+ "required": [
12169
+ "agent",
12170
+ "prompt",
12171
+ "produces"
12172
+ ]
12173
+ },
12174
+ "TemplateManifest": {
12175
+ "type": "object",
12176
+ "additionalProperties": false,
12177
+ "properties": {
12178
+ "schemaVersion": {
12179
+ "type": "integer",
12180
+ "const": 1
12181
+ },
12182
+ "id": {
12183
+ "type": "string",
12184
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
12185
+ "description": "Stable template slug from the manifest."
12186
+ },
12187
+ "title": {
12188
+ "type": "string",
12189
+ "minLength": 1
12190
+ },
12191
+ "summary": {
12192
+ "type": "string",
12193
+ "minLength": 1
12194
+ },
12195
+ "description": { "type": "string" },
12196
+ "author": { "$ref": "#/components/schemas/TemplateAuthor" },
12197
+ "tags": {
12198
+ "type": "array",
12199
+ "items": {
12200
+ "type": "string",
12201
+ "minLength": 1
12202
+ }
12203
+ },
12204
+ "source": { "$ref": "#/components/schemas/TemplateSource" },
12205
+ "install": { "$ref": "#/components/schemas/TemplateInstall" },
12206
+ "secrets": {
12207
+ "type": "array",
12208
+ "items": { "$ref": "#/components/schemas/TemplateSecret" }
12209
+ },
12210
+ "secretGroups": {
12211
+ "type": "array",
12212
+ "items": { "$ref": "#/components/schemas/TemplateSecretGroup" }
12213
+ },
12214
+ "variables": {
12215
+ "type": "array",
12216
+ "items": { "$ref": "#/components/schemas/TemplateVariable" }
12217
+ },
12218
+ "setup": { "$ref": "#/components/schemas/TemplateSetup" },
12219
+ "postInstall": { "type": "string" }
12220
+ },
12221
+ "required": [
12222
+ "schemaVersion",
12223
+ "id",
12224
+ "title",
12225
+ "summary",
12226
+ "author",
12227
+ "tags",
12228
+ "source",
12229
+ "install",
12230
+ "secrets",
12231
+ "secretGroups",
12232
+ "variables"
12233
+ ]
12234
+ },
12235
+ "TemplateRegistryStatus": {
12236
+ "type": "string",
12237
+ "enum": [
12238
+ "pending",
12239
+ "approved",
12240
+ "rejected"
12241
+ ]
12242
+ },
12243
+ "TemplateRegistrySummary": {
12244
+ "type": "object",
12245
+ "properties": {
12246
+ "id": {
12247
+ "type": "string",
12248
+ "format": "uuid"
12249
+ },
12250
+ "slug": {
12251
+ "type": "string",
12252
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
12253
+ "description": "Stable template slug used in template URLs and install commands."
12254
+ },
12255
+ "title": { "type": "string" },
12256
+ "summary": { "type": "string" },
12257
+ "author": { "$ref": "#/components/schemas/TemplateAuthor" },
12258
+ "tags": {
12259
+ "type": "array",
12260
+ "items": { "type": "string" }
12261
+ },
12262
+ "verified": { "type": "boolean" },
12263
+ "install_count": {
12264
+ "type": "integer",
12265
+ "minimum": 0
12266
+ },
12267
+ "github_repo": {
12268
+ "type": "string",
12269
+ "pattern": "^[A-Za-z0-9-]+/[A-Za-z0-9_.-]+$",
12270
+ "description": "GitHub repository in owner/repo form."
12271
+ },
12272
+ "created_at": {
12273
+ "type": "string",
12274
+ "format": "date-time"
12275
+ },
12276
+ "updated_at": {
12277
+ "type": "string",
12278
+ "format": "date-time"
12279
+ }
12280
+ },
12281
+ "required": [
12282
+ "id",
12283
+ "slug",
12284
+ "title",
12285
+ "summary",
12286
+ "author",
12287
+ "tags",
12288
+ "verified",
12289
+ "install_count",
12290
+ "github_repo",
12291
+ "created_at",
12292
+ "updated_at"
12293
+ ]
12294
+ },
12295
+ "TemplateRegistryDetail": {
12296
+ "type": "object",
12297
+ "properties": {
12298
+ "id": {
12299
+ "type": "string",
12300
+ "format": "uuid"
12301
+ },
12302
+ "slug": {
12303
+ "type": "string",
12304
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
12305
+ "description": "Stable template slug used in template URLs and install commands."
12306
+ },
12307
+ "title": { "type": "string" },
12308
+ "summary": { "type": "string" },
12309
+ "author": { "$ref": "#/components/schemas/TemplateAuthor" },
12310
+ "tags": {
12311
+ "type": "array",
12312
+ "items": { "type": "string" }
12313
+ },
12314
+ "verified": { "type": "boolean" },
12315
+ "install_count": {
12316
+ "type": "integer",
12317
+ "minimum": 0
12318
+ },
12319
+ "github_repo": {
12320
+ "type": "string",
12321
+ "pattern": "^[A-Za-z0-9-]+/[A-Za-z0-9_.-]+$",
12322
+ "description": "GitHub repository in owner/repo form."
12323
+ },
12324
+ "created_at": {
12325
+ "type": "string",
12326
+ "format": "date-time"
12327
+ },
12328
+ "updated_at": {
12329
+ "type": "string",
12330
+ "format": "date-time"
12331
+ },
12332
+ "description": { "type": ["string", "null"] },
12333
+ "github_sha": { "type": "string" },
12334
+ "github_path": { "type": ["string", "null"] },
12335
+ "manifest": { "$ref": "#/components/schemas/TemplateManifest" },
12336
+ "readme": { "type": ["string", "null"] },
12337
+ "status": { "$ref": "#/components/schemas/TemplateRegistryStatus" }
12338
+ },
12339
+ "required": [
12340
+ "id",
12341
+ "slug",
12342
+ "title",
12343
+ "summary",
12344
+ "author",
12345
+ "tags",
12346
+ "verified",
12347
+ "install_count",
12348
+ "github_repo",
12349
+ "created_at",
12350
+ "updated_at",
12351
+ "description",
12352
+ "github_sha",
12353
+ "github_path",
12354
+ "manifest",
12355
+ "readme",
12356
+ "status"
12357
+ ]
12358
+ },
12359
+ "TemplateRegistryPage": {
12360
+ "type": "object",
12361
+ "properties": {
12362
+ "items": {
12363
+ "type": "array",
12364
+ "items": { "$ref": "#/components/schemas/TemplateRegistrySummary" }
12365
+ },
12366
+ "next_cursor": {
12367
+ "type": ["string", "null"],
12368
+ "description": "Cursor to pass as the next `cursor` query value, or null when there are no more templates."
12369
+ }
12370
+ },
12371
+ "required": ["items", "next_cursor"]
12372
+ },
12373
+ "InstallTemplateBody": {
12374
+ "type": "object",
12375
+ "additionalProperties": false,
12376
+ "properties": {
12377
+ "address": {
12378
+ "type": "string",
12379
+ "pattern": "^[a-z0-9][a-z0-9._-]{0,63}$",
12380
+ "description": "Localpart to claim on the selected inbound domain. Defaults to the template slug."
12381
+ },
12382
+ "domain": {
12383
+ "type": "string",
12384
+ "minLength": 3,
12385
+ "description": "Org domain name to claim the address on. Defaults to the org's newest active domain."
12386
+ },
12387
+ "variables": {
12388
+ "type": "object",
12389
+ "additionalProperties": { "type": "string" },
12390
+ "description": "Template variable values keyed by manifest variable key."
12391
+ },
12392
+ "secrets": {
12393
+ "type": "object",
12394
+ "additionalProperties": { "type": "string" },
12395
+ "description": "Secret values keyed by manifest secret key."
12396
+ }
12397
+ }
12398
+ },
12399
+ "TemplateInstallState": {
12400
+ "type": "string",
12401
+ "enum": [
12402
+ "deploying",
12403
+ "connecting",
12404
+ "bound",
12405
+ "tested",
12406
+ "deploy_failed",
12407
+ "bind_failed",
12408
+ "test_failed"
12409
+ ]
12410
+ },
12411
+ "TemplateInstallStatus": {
12412
+ "type": "object",
12413
+ "properties": {
12414
+ "id": {
12415
+ "type": "string",
12416
+ "format": "uuid"
12417
+ },
12418
+ "template_slug": {
12419
+ "type": "string",
12420
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
12421
+ "description": "Template slug for this install."
12422
+ },
12423
+ "state": { "$ref": "#/components/schemas/TemplateInstallState" },
12424
+ "address": { "type": ["string", "null"] },
12425
+ "function_id": {
12426
+ "type": ["string", "null"],
12427
+ "format": "uuid"
12428
+ },
12429
+ "error": { "type": ["string", "null"] },
12430
+ "created_at": {
12431
+ "type": "string",
12432
+ "format": "date-time"
12433
+ },
12434
+ "updated_at": {
12435
+ "type": "string",
12436
+ "format": "date-time"
12437
+ }
12438
+ },
12439
+ "required": [
12440
+ "id",
12441
+ "template_slug",
12442
+ "state",
12443
+ "address",
12444
+ "function_id",
12445
+ "error",
12446
+ "created_at",
12447
+ "updated_at"
12448
+ ]
11700
12449
  }
11701
12450
  }
11702
12451
  }
@@ -21124,6 +21873,45 @@ const operationManifest = [
21124
21873
  "required": ["filename", "content_base64"]
21125
21874
  }
21126
21875
  },
21876
+ "payload_attachments": {
21877
+ "type": "array",
21878
+ "maxItems": 1,
21879
+ "description": "Deliver an already-uploaded Primitive Payloads object as an attachment by reference, without inlining the bytes — the way to send attachments larger than the inline cap. Upload the object via /v1/payloads (client-held CEK), then reference it here. v1 supports at most one.",
21880
+ "items": {
21881
+ "type": "object",
21882
+ "additionalProperties": false,
21883
+ "description": "A reference to an already-uploaded Primitive Payloads object, delivered as an attachment without inlining the bytes — the way to send an attachment larger than the inline cap. Upload the object via /v1/payloads (with a client-held CEK the server never sees), then reference it here.",
21884
+ "properties": {
21885
+ "root": {
21886
+ "type": "string",
21887
+ "pattern": "^[0-9a-f]{64}$",
21888
+ "description": "The 64-char lowercase-hex Merkle root of a finalized payloads object."
21889
+ },
21890
+ "filename": {
21891
+ "type": "string",
21892
+ "minLength": 1,
21893
+ "maxLength": 255,
21894
+ "description": "Attachment filename presented to the recipient."
21895
+ },
21896
+ "content_type": {
21897
+ "type": "string",
21898
+ "minLength": 1,
21899
+ "maxLength": 255,
21900
+ "description": "Optional MIME content type."
21901
+ },
21902
+ "cek": {
21903
+ "type": "string",
21904
+ "pattern": "^[A-Za-z0-9_-]{1,128}$",
21905
+ "description": "Base64url-encoded (unpadded) content-encryption key the recipient uses to decrypt. Travels with the email; the object store only ever holds ciphertext."
21906
+ }
21907
+ },
21908
+ "required": [
21909
+ "root",
21910
+ "filename",
21911
+ "cek"
21912
+ ]
21913
+ }
21914
+ },
21127
21915
  "wait": {
21128
21916
  "type": "boolean",
21129
21917
  "description": "When true, wait for the first downstream SMTP delivery outcome before returning."
@@ -21234,6 +22022,667 @@ const operationManifest = [
21234
22022
  "tag": "Sending",
21235
22023
  "tagCommand": "sending"
21236
22024
  },
22025
+ {
22026
+ "binaryResponse": false,
22027
+ "bodyRequired": false,
22028
+ "command": "get-template",
22029
+ "description": "Fetch one approved Function template by slug, including its manifest\nsnapshot and README. The stored source files used for install are not\nreturned.\n",
22030
+ "hasJsonBody": false,
22031
+ "method": "GET",
22032
+ "operationId": "getTemplate",
22033
+ "path": "/templates/{id}",
22034
+ "pathParams": [{
22035
+ "description": "Template slug from the template manifest.",
22036
+ "enum": null,
22037
+ "name": "id",
22038
+ "required": true,
22039
+ "type": "string"
22040
+ }],
22041
+ "queryParams": [],
22042
+ "requestSchema": null,
22043
+ "responseSchema": {
22044
+ "type": "object",
22045
+ "properties": {
22046
+ "id": {
22047
+ "type": "string",
22048
+ "format": "uuid"
22049
+ },
22050
+ "slug": {
22051
+ "type": "string",
22052
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
22053
+ "description": "Stable template slug used in template URLs and install commands."
22054
+ },
22055
+ "title": { "type": "string" },
22056
+ "summary": { "type": "string" },
22057
+ "author": {
22058
+ "type": "object",
22059
+ "additionalProperties": false,
22060
+ "properties": {
22061
+ "id": {
22062
+ "type": "string",
22063
+ "minLength": 1
22064
+ },
22065
+ "name": {
22066
+ "type": "string",
22067
+ "minLength": 1
22068
+ },
22069
+ "url": {
22070
+ "type": "string",
22071
+ "format": "uri"
22072
+ }
22073
+ },
22074
+ "required": ["id", "name"]
22075
+ },
22076
+ "tags": {
22077
+ "type": "array",
22078
+ "items": { "type": "string" }
22079
+ },
22080
+ "verified": { "type": "boolean" },
22081
+ "install_count": {
22082
+ "type": "integer",
22083
+ "minimum": 0
22084
+ },
22085
+ "github_repo": {
22086
+ "type": "string",
22087
+ "pattern": "^[A-Za-z0-9-]+/[A-Za-z0-9_.-]+$",
22088
+ "description": "GitHub repository in owner/repo form."
22089
+ },
22090
+ "created_at": {
22091
+ "type": "string",
22092
+ "format": "date-time"
22093
+ },
22094
+ "updated_at": {
22095
+ "type": "string",
22096
+ "format": "date-time"
22097
+ },
22098
+ "description": { "type": ["string", "null"] },
22099
+ "github_sha": { "type": "string" },
22100
+ "github_path": { "type": ["string", "null"] },
22101
+ "manifest": {
22102
+ "type": "object",
22103
+ "additionalProperties": false,
22104
+ "properties": {
22105
+ "schemaVersion": {
22106
+ "type": "integer",
22107
+ "const": 1
22108
+ },
22109
+ "id": {
22110
+ "type": "string",
22111
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
22112
+ "description": "Stable template slug from the manifest."
22113
+ },
22114
+ "title": {
22115
+ "type": "string",
22116
+ "minLength": 1
22117
+ },
22118
+ "summary": {
22119
+ "type": "string",
22120
+ "minLength": 1
22121
+ },
22122
+ "description": { "type": "string" },
22123
+ "author": {
22124
+ "type": "object",
22125
+ "additionalProperties": false,
22126
+ "properties": {
22127
+ "id": {
22128
+ "type": "string",
22129
+ "minLength": 1
22130
+ },
22131
+ "name": {
22132
+ "type": "string",
22133
+ "minLength": 1
22134
+ },
22135
+ "url": {
22136
+ "type": "string",
22137
+ "format": "uri"
22138
+ }
22139
+ },
22140
+ "required": ["id", "name"]
22141
+ },
22142
+ "tags": {
22143
+ "type": "array",
22144
+ "items": {
22145
+ "type": "string",
22146
+ "minLength": 1
22147
+ }
22148
+ },
22149
+ "source": { "oneOf": [{
22150
+ "type": "object",
22151
+ "additionalProperties": false,
22152
+ "properties": {
22153
+ "mode": {
22154
+ "type": "string",
22155
+ "const": "managed-build"
22156
+ },
22157
+ "dir": {
22158
+ "type": "string",
22159
+ "minLength": 1,
22160
+ "default": "."
22161
+ }
22162
+ },
22163
+ "required": ["mode", "dir"]
22164
+ }, {
22165
+ "type": "object",
22166
+ "additionalProperties": false,
22167
+ "properties": {
22168
+ "mode": {
22169
+ "type": "string",
22170
+ "const": "bundle"
22171
+ },
22172
+ "file": {
22173
+ "type": "string",
22174
+ "minLength": 1
22175
+ }
22176
+ },
22177
+ "required": ["mode", "file"]
22178
+ }] },
22179
+ "install": {
22180
+ "type": "object",
22181
+ "additionalProperties": false,
22182
+ "properties": {
22183
+ "mode": {
22184
+ "type": "string",
22185
+ "enum": ["deploy", "scaffold"]
22186
+ },
22187
+ "editFiles": {
22188
+ "type": "array",
22189
+ "items": {
22190
+ "type": "string",
22191
+ "minLength": 1
22192
+ }
22193
+ },
22194
+ "reason": {
22195
+ "type": "string",
22196
+ "default": ""
22197
+ }
22198
+ },
22199
+ "required": [
22200
+ "mode",
22201
+ "editFiles",
22202
+ "reason"
22203
+ ]
22204
+ },
22205
+ "secrets": {
22206
+ "type": "array",
22207
+ "items": {
22208
+ "type": "object",
22209
+ "additionalProperties": false,
22210
+ "properties": {
22211
+ "key": {
22212
+ "type": "string",
22213
+ "pattern": "^[A-Z_][A-Z0-9_]*$"
22214
+ },
22215
+ "required": {
22216
+ "type": "boolean",
22217
+ "default": true
22218
+ },
22219
+ "description": { "type": "string" }
22220
+ },
22221
+ "required": ["key", "required"]
22222
+ }
22223
+ },
22224
+ "secretGroups": {
22225
+ "type": "array",
22226
+ "items": {
22227
+ "type": "object",
22228
+ "additionalProperties": false,
22229
+ "properties": {
22230
+ "keys": {
22231
+ "type": "array",
22232
+ "minItems": 2,
22233
+ "items": {
22234
+ "type": "string",
22235
+ "pattern": "^[A-Z_][A-Z0-9_]*$"
22236
+ }
22237
+ },
22238
+ "min": {
22239
+ "type": "integer",
22240
+ "minimum": 1,
22241
+ "default": 1
22242
+ },
22243
+ "description": { "type": "string" }
22244
+ },
22245
+ "required": ["keys", "min"]
22246
+ }
22247
+ },
22248
+ "variables": {
22249
+ "type": "array",
22250
+ "items": {
22251
+ "type": "object",
22252
+ "additionalProperties": false,
22253
+ "properties": {
22254
+ "key": {
22255
+ "type": "string",
22256
+ "minLength": 1
22257
+ },
22258
+ "prompt": {
22259
+ "type": "string",
22260
+ "minLength": 1
22261
+ },
22262
+ "default": { "type": "string" },
22263
+ "file": {
22264
+ "type": "string",
22265
+ "minLength": 1
22266
+ },
22267
+ "type": {
22268
+ "type": "string",
22269
+ "enum": [
22270
+ "string",
22271
+ "select",
22272
+ "url",
22273
+ "email"
22274
+ ],
22275
+ "default": "string"
22276
+ },
22277
+ "options": {
22278
+ "type": "array",
22279
+ "items": {
22280
+ "type": "string",
22281
+ "minLength": 1
22282
+ }
22283
+ },
22284
+ "validation": {
22285
+ "type": "object",
22286
+ "additionalProperties": false,
22287
+ "properties": {
22288
+ "pattern": {
22289
+ "type": "string",
22290
+ "minLength": 1
22291
+ },
22292
+ "maxLength": {
22293
+ "type": "integer",
22294
+ "minimum": 1
22295
+ }
22296
+ }
22297
+ }
22298
+ },
22299
+ "required": [
22300
+ "key",
22301
+ "prompt",
22302
+ "type"
22303
+ ]
22304
+ }
22305
+ },
22306
+ "setup": {
22307
+ "type": "object",
22308
+ "additionalProperties": false,
22309
+ "properties": {
22310
+ "agent": {
22311
+ "type": "string",
22312
+ "minLength": 1
22313
+ },
22314
+ "prompt": {
22315
+ "type": "string",
22316
+ "minLength": 1
22317
+ },
22318
+ "produces": {
22319
+ "type": "array",
22320
+ "items": {
22321
+ "type": "string",
22322
+ "minLength": 1
22323
+ }
22324
+ }
22325
+ },
22326
+ "required": [
22327
+ "agent",
22328
+ "prompt",
22329
+ "produces"
22330
+ ]
22331
+ },
22332
+ "postInstall": { "type": "string" }
22333
+ },
22334
+ "required": [
22335
+ "schemaVersion",
22336
+ "id",
22337
+ "title",
22338
+ "summary",
22339
+ "author",
22340
+ "tags",
22341
+ "source",
22342
+ "install",
22343
+ "secrets",
22344
+ "secretGroups",
22345
+ "variables"
22346
+ ]
22347
+ },
22348
+ "readme": { "type": ["string", "null"] },
22349
+ "status": {
22350
+ "type": "string",
22351
+ "enum": [
22352
+ "pending",
22353
+ "approved",
22354
+ "rejected"
22355
+ ]
22356
+ }
22357
+ },
22358
+ "required": [
22359
+ "id",
22360
+ "slug",
22361
+ "title",
22362
+ "summary",
22363
+ "author",
22364
+ "tags",
22365
+ "verified",
22366
+ "install_count",
22367
+ "github_repo",
22368
+ "created_at",
22369
+ "updated_at",
22370
+ "description",
22371
+ "github_sha",
22372
+ "github_path",
22373
+ "manifest",
22374
+ "readme",
22375
+ "status"
22376
+ ]
22377
+ },
22378
+ "sdkName": "getTemplate",
22379
+ "summary": "Get a function template",
22380
+ "tag": "Templates",
22381
+ "tagCommand": "templates"
22382
+ },
22383
+ {
22384
+ "binaryResponse": false,
22385
+ "bodyRequired": false,
22386
+ "command": "get-template-install",
22387
+ "description": "Fetch the current state of a template install. Reads may advance the\nself-test phase when a reply effect has been observed.\n",
22388
+ "hasJsonBody": false,
22389
+ "method": "GET",
22390
+ "operationId": "getTemplateInstall",
22391
+ "path": "/templates/installs/{id}",
22392
+ "pathParams": [{
22393
+ "description": "Template install UUID.",
22394
+ "enum": null,
22395
+ "name": "id",
22396
+ "required": true,
22397
+ "type": "string"
22398
+ }],
22399
+ "queryParams": [],
22400
+ "requestSchema": null,
22401
+ "responseSchema": {
22402
+ "type": "object",
22403
+ "properties": {
22404
+ "id": {
22405
+ "type": "string",
22406
+ "format": "uuid"
22407
+ },
22408
+ "template_slug": {
22409
+ "type": "string",
22410
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
22411
+ "description": "Template slug for this install."
22412
+ },
22413
+ "state": {
22414
+ "type": "string",
22415
+ "enum": [
22416
+ "deploying",
22417
+ "connecting",
22418
+ "bound",
22419
+ "tested",
22420
+ "deploy_failed",
22421
+ "bind_failed",
22422
+ "test_failed"
22423
+ ]
22424
+ },
22425
+ "address": { "type": ["string", "null"] },
22426
+ "function_id": {
22427
+ "type": ["string", "null"],
22428
+ "format": "uuid"
22429
+ },
22430
+ "error": { "type": ["string", "null"] },
22431
+ "created_at": {
22432
+ "type": "string",
22433
+ "format": "date-time"
22434
+ },
22435
+ "updated_at": {
22436
+ "type": "string",
22437
+ "format": "date-time"
22438
+ }
22439
+ },
22440
+ "required": [
22441
+ "id",
22442
+ "template_slug",
22443
+ "state",
22444
+ "address",
22445
+ "function_id",
22446
+ "error",
22447
+ "created_at",
22448
+ "updated_at"
22449
+ ]
22450
+ },
22451
+ "sdkName": "getTemplateInstall",
22452
+ "summary": "Get template install status",
22453
+ "tag": "Templates",
22454
+ "tagCommand": "templates"
22455
+ },
22456
+ {
22457
+ "binaryResponse": false,
22458
+ "bodyRequired": true,
22459
+ "command": "install-template",
22460
+ "description": "Start a one-shot deploy of an approved deploy-mode Function template.\nThe response returns an install record immediately; poll\n`GET /templates/installs/{id}` for progress.\n",
22461
+ "hasJsonBody": true,
22462
+ "method": "POST",
22463
+ "operationId": "installTemplate",
22464
+ "path": "/templates/{id}/install",
22465
+ "pathParams": [{
22466
+ "description": "Template slug from the template manifest.",
22467
+ "enum": null,
22468
+ "name": "id",
22469
+ "required": true,
22470
+ "type": "string"
22471
+ }],
22472
+ "queryParams": [],
22473
+ "requestSchema": {
22474
+ "type": "object",
22475
+ "additionalProperties": false,
22476
+ "properties": {
22477
+ "address": {
22478
+ "type": "string",
22479
+ "pattern": "^[a-z0-9][a-z0-9._-]{0,63}$",
22480
+ "description": "Localpart to claim on the selected inbound domain. Defaults to the template slug."
22481
+ },
22482
+ "domain": {
22483
+ "type": "string",
22484
+ "minLength": 3,
22485
+ "description": "Org domain name to claim the address on. Defaults to the org's newest active domain."
22486
+ },
22487
+ "variables": {
22488
+ "type": "object",
22489
+ "additionalProperties": { "type": "string" },
22490
+ "description": "Template variable values keyed by manifest variable key."
22491
+ },
22492
+ "secrets": {
22493
+ "type": "object",
22494
+ "additionalProperties": { "type": "string" },
22495
+ "description": "Secret values keyed by manifest secret key."
22496
+ }
22497
+ }
22498
+ },
22499
+ "responseSchema": {
22500
+ "type": "object",
22501
+ "properties": {
22502
+ "id": {
22503
+ "type": "string",
22504
+ "format": "uuid"
22505
+ },
22506
+ "template_slug": {
22507
+ "type": "string",
22508
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
22509
+ "description": "Template slug for this install."
22510
+ },
22511
+ "state": {
22512
+ "type": "string",
22513
+ "enum": [
22514
+ "deploying",
22515
+ "connecting",
22516
+ "bound",
22517
+ "tested",
22518
+ "deploy_failed",
22519
+ "bind_failed",
22520
+ "test_failed"
22521
+ ]
22522
+ },
22523
+ "address": { "type": ["string", "null"] },
22524
+ "function_id": {
22525
+ "type": ["string", "null"],
22526
+ "format": "uuid"
22527
+ },
22528
+ "error": { "type": ["string", "null"] },
22529
+ "created_at": {
22530
+ "type": "string",
22531
+ "format": "date-time"
22532
+ },
22533
+ "updated_at": {
22534
+ "type": "string",
22535
+ "format": "date-time"
22536
+ }
22537
+ },
22538
+ "required": [
22539
+ "id",
22540
+ "template_slug",
22541
+ "state",
22542
+ "address",
22543
+ "function_id",
22544
+ "error",
22545
+ "created_at",
22546
+ "updated_at"
22547
+ ]
22548
+ },
22549
+ "sdkName": "installTemplate",
22550
+ "summary": "Install a function template",
22551
+ "tag": "Templates",
22552
+ "tagCommand": "templates"
22553
+ },
22554
+ {
22555
+ "binaryResponse": false,
22556
+ "bodyRequired": false,
22557
+ "command": "list-templates",
22558
+ "description": "List approved Function templates available for browsing and\ninstallation. Results are cacheable and paginated with\n`data.next_cursor`.\n",
22559
+ "hasJsonBody": false,
22560
+ "method": "GET",
22561
+ "operationId": "listTemplates",
22562
+ "path": "/templates",
22563
+ "pathParams": [],
22564
+ "queryParams": [
22565
+ {
22566
+ "description": "Search templates by title, summary, or slug.",
22567
+ "enum": null,
22568
+ "name": "q",
22569
+ "required": false,
22570
+ "type": "string"
22571
+ },
22572
+ {
22573
+ "description": "Filter templates by an exact tag.",
22574
+ "enum": null,
22575
+ "name": "tag",
22576
+ "required": false,
22577
+ "type": "string"
22578
+ },
22579
+ {
22580
+ "description": "Cursor from a previous response `data.next_cursor` value.",
22581
+ "enum": null,
22582
+ "name": "cursor",
22583
+ "required": false,
22584
+ "type": "string"
22585
+ },
22586
+ {
22587
+ "default": 50,
22588
+ "description": "Maximum number of templates to return. The server caps this at 100.",
22589
+ "enum": null,
22590
+ "maximum": 100,
22591
+ "minimum": 1,
22592
+ "name": "limit",
22593
+ "required": false,
22594
+ "type": "integer"
22595
+ }
22596
+ ],
22597
+ "requestSchema": null,
22598
+ "responseSchema": {
22599
+ "type": "object",
22600
+ "properties": {
22601
+ "items": {
22602
+ "type": "array",
22603
+ "items": {
22604
+ "type": "object",
22605
+ "properties": {
22606
+ "id": {
22607
+ "type": "string",
22608
+ "format": "uuid"
22609
+ },
22610
+ "slug": {
22611
+ "type": "string",
22612
+ "pattern": "^[a-z0-9][a-z0-9_-]{0,62}$",
22613
+ "description": "Stable template slug used in template URLs and install commands."
22614
+ },
22615
+ "title": { "type": "string" },
22616
+ "summary": { "type": "string" },
22617
+ "author": {
22618
+ "type": "object",
22619
+ "additionalProperties": false,
22620
+ "properties": {
22621
+ "id": {
22622
+ "type": "string",
22623
+ "minLength": 1
22624
+ },
22625
+ "name": {
22626
+ "type": "string",
22627
+ "minLength": 1
22628
+ },
22629
+ "url": {
22630
+ "type": "string",
22631
+ "format": "uri"
22632
+ }
22633
+ },
22634
+ "required": ["id", "name"]
22635
+ },
22636
+ "tags": {
22637
+ "type": "array",
22638
+ "items": { "type": "string" }
22639
+ },
22640
+ "verified": { "type": "boolean" },
22641
+ "install_count": {
22642
+ "type": "integer",
22643
+ "minimum": 0
22644
+ },
22645
+ "github_repo": {
22646
+ "type": "string",
22647
+ "pattern": "^[A-Za-z0-9-]+/[A-Za-z0-9_.-]+$",
22648
+ "description": "GitHub repository in owner/repo form."
22649
+ },
22650
+ "created_at": {
22651
+ "type": "string",
22652
+ "format": "date-time"
22653
+ },
22654
+ "updated_at": {
22655
+ "type": "string",
22656
+ "format": "date-time"
22657
+ }
22658
+ },
22659
+ "required": [
22660
+ "id",
22661
+ "slug",
22662
+ "title",
22663
+ "summary",
22664
+ "author",
22665
+ "tags",
22666
+ "verified",
22667
+ "install_count",
22668
+ "github_repo",
22669
+ "created_at",
22670
+ "updated_at"
22671
+ ]
22672
+ }
22673
+ },
22674
+ "next_cursor": {
22675
+ "type": ["string", "null"],
22676
+ "description": "Cursor to pass as the next `cursor` query value, or null when there are no more templates."
22677
+ }
22678
+ },
22679
+ "required": ["items", "next_cursor"]
22680
+ },
22681
+ "sdkName": "listTemplates",
22682
+ "summary": "List function templates",
22683
+ "tag": "Templates",
22684
+ "tagCommand": "templates"
22685
+ },
21237
22686
  {
21238
22687
  "binaryResponse": false,
21239
22688
  "bodyRequired": false,
@@ -23472,7 +24921,7 @@ async function fetchEmailSearchPage(params) {
23472
24921
  rows
23473
24922
  };
23474
24923
  }
23475
- function sleep$1(ms) {
24924
+ function sleep$2(ms) {
23476
24925
  return new Promise((resolve) => setTimeout(resolve, ms));
23477
24926
  }
23478
24927
  function cliError$6(message) {
@@ -24505,7 +25954,7 @@ async function waitForReply(params) {
24505
25954
  if (lastAccepted !== void 0) continue;
24506
25955
  if (phase.deadline !== null && Date.now() >= phase.deadline) break;
24507
25956
  if (totalDeadline !== null && Date.now() >= totalDeadline) return null;
24508
- await sleep$1(params.interval * 1e3);
25957
+ await sleep$2(params.interval * 1e3);
24509
25958
  }
24510
25959
  }
24511
25960
  return null;
@@ -25287,7 +26736,7 @@ var EmailsWaitCommand = class EmailsWaitCommand extends Command {
25287
26736
  }
25288
26737
  if (cursorAdvanced) continue;
25289
26738
  if (deadline !== null && Date.now() >= deadline) break;
25290
- await sleep$1(flags.interval * 1e3);
26739
+ await sleep$2(flags.interval * 1e3);
25291
26740
  }
25292
26741
  process.stderr.write(`Timed out waiting for ${flags.number} matching email${flags.number === 1 ? "" : "s"}; received ${matched}.\n`);
25293
26742
  process.exitCode = 1;
@@ -25406,7 +26855,7 @@ var EmailsWatchCommand = class EmailsWatchCommand extends Command {
25406
26855
  }
25407
26856
  if (cursorAdvanced) continue;
25408
26857
  if (deadline !== null && Date.now() >= deadline) break;
25409
- await sleep$1(flags.interval * 1e3);
26858
+ await sleep$2(flags.interval * 1e3);
25410
26859
  }
25411
26860
  }
25412
26861
  };
@@ -26567,8 +28016,8 @@ const PRIMITIVE_TEAM_AUTHOR = {
26567
28016
  name: "Primitive Team",
26568
28017
  url: "https://primitive.dev"
26569
28018
  };
26570
- const SDK_VERSION_RANGE = "^1.19.0";
26571
- const CLI_VERSION_RANGE = "^1.19.0";
28019
+ const SDK_VERSION_RANGE = "^1.21.0";
28020
+ const CLI_VERSION_RANGE = "^1.21.0";
26572
28021
  const ESBUILD_VERSION_RANGE = "^0.27.0";
26573
28022
  function renderHandler() {
26574
28023
  return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
@@ -27303,7 +28752,7 @@ var FunctionsLogsCommand = class FunctionsLogsCommand extends Command {
27303
28752
  return;
27304
28753
  }
27305
28754
  completedInitialFollowPoll = true;
27306
- await sleep$1(flags["poll-interval"] * 1e3);
28755
+ await sleep$2(flags["poll-interval"] * 1e3);
27307
28756
  }
27308
28757
  });
27309
28758
  }
@@ -28214,7 +29663,7 @@ var FunctionsTestFunctionCommand = class FunctionsTestFunctionCommand extends Co
28214
29663
  trace = fetched;
28215
29664
  break;
28216
29665
  }
28217
- await sleep$1(pollIntervalMs);
29666
+ await sleep$2(pollIntervalMs);
28218
29667
  }
28219
29668
  if (!trace) {
28220
29669
  const finalTrace = ((await getFunctionTestRunTrace({
@@ -28593,7 +30042,7 @@ const MAX_CLI_LOGIN_POLL_INTERVAL_SECONDS = 60;
28593
30042
  function cliError$3(message) {
28594
30043
  return new Errors.CLIError(message, { exit: 1 });
28595
30044
  }
28596
- function sleep(ms) {
30045
+ function sleep$1(ms) {
28597
30046
  return new Promise((resolve) => setTimeout(resolve, ms));
28598
30047
  }
28599
30048
  function openBrowser(url) {
@@ -28758,7 +30207,7 @@ var LoginCommand$1 = class extends Command {
28758
30207
  let interval = Math.min(Math.max(1, start.interval), MAX_CLI_LOGIN_POLL_INTERVAL_SECONDS);
28759
30208
  let nextPollDelay = 1;
28760
30209
  while (Date.now() < deadline) {
28761
- await sleep(nextPollDelay * 1e3);
30210
+ await sleep$1(nextPollDelay * 1e3);
28762
30211
  nextPollDelay = interval;
28763
30212
  const polled = await pollCliLogin({
28764
30213
  body: { device_code: start.device_code },
@@ -30388,6 +31837,434 @@ var OrgSecretsSetCommand = class OrgSecretsSetCommand extends Command {
30388
31837
  }
30389
31838
  };
30390
31839
  //#endregion
31840
+ //#region ../sdk-node/dist/payloads/index.js
31841
+ /**
31842
+ * Primitive Payloads — streaming client for large, content-addressed,
31843
+ * end-to-end-encrypted objects (attachments up to ~1 TB).
31844
+ *
31845
+ * Objects are split into fixed 64 MiB chunks; each chunk is encrypted with a
31846
+ * per-chunk AES-256-GCM key (HKDF-derived from the object CEK), content-addressed
31847
+ * by its ciphertext SHA-256, and committed under a Merkle root. This module
31848
+ * streams: it processes one chunk at a time and never holds the whole object in
31849
+ * memory, so a multi-GB file uploads/downloads in bounded memory.
31850
+ *
31851
+ * The chunk/manifest construction is byte-compatible with the server's object
31852
+ * model (packages/payloads-core in the API monorepo).
31853
+ */
31854
+ const CHUNK_SIZE = 64 * 1024 * 1024;
31855
+ const MANIFEST_VERSION = 1;
31856
+ const CHUNK_KDF_INFO = "payloads-chunk";
31857
+ const OBJECT_ID_BYTES = 16;
31858
+ const CEK_BYTES = 32;
31859
+ const subtle = globalThis.crypto.subtle;
31860
+ const textEncoder = new TextEncoder();
31861
+ function randomBytes(length) {
31862
+ const out = new Uint8Array(length);
31863
+ globalThis.crypto.getRandomValues(out);
31864
+ return out;
31865
+ }
31866
+ function toHex(bytes) {
31867
+ let out = "";
31868
+ for (const b of bytes) out += b.toString(16).padStart(2, "0");
31869
+ return out;
31870
+ }
31871
+ function fromHex(hex) {
31872
+ if (hex.length % 2 !== 0) throw new Error("invalid hex: odd length");
31873
+ if (hex.length > 0 && !/^[0-9a-fA-F]+$/.test(hex)) throw new Error("invalid hex: non-hex character");
31874
+ const out = new Uint8Array(hex.length / 2);
31875
+ for (let i = 0; i < out.length; i++) out[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
31876
+ return out;
31877
+ }
31878
+ async function contentHash(bytes) {
31879
+ return new Uint8Array(await subtle.digest("SHA-256", bytes));
31880
+ }
31881
+ async function contentHashHex(bytes) {
31882
+ return toHex(await contentHash(bytes));
31883
+ }
31884
+ /** Binary Merkle root over ordered hex leaf hashes (odd node promoted). */
31885
+ async function merkleRoot(leafHashesHex) {
31886
+ if (leafHashesHex.length === 0) return contentHashHex(new Uint8Array(0));
31887
+ let level = leafHashesHex.map(fromHex);
31888
+ while (level.length > 1) {
31889
+ const next = [];
31890
+ for (let i = 0; i < level.length; i += 2) {
31891
+ const left = level[i];
31892
+ const right = i + 1 < level.length ? level[i + 1] : level[i];
31893
+ const combined = new Uint8Array(left.length + right.length);
31894
+ combined.set(left, 0);
31895
+ combined.set(right, left.length);
31896
+ next.push(await contentHash(combined));
31897
+ }
31898
+ level = next;
31899
+ }
31900
+ return toHex(level[0]);
31901
+ }
31902
+ async function deriveChunkKey(cek, index) {
31903
+ const baseKey = await subtle.importKey("raw", cek, "HKDF", false, ["deriveKey"]);
31904
+ const info = textEncoder.encode(`${CHUNK_KDF_INFO}:${index}`);
31905
+ return subtle.deriveKey({
31906
+ name: "HKDF",
31907
+ hash: "SHA-256",
31908
+ salt: new Uint8Array(32),
31909
+ info
31910
+ }, baseKey, {
31911
+ name: "AES-GCM",
31912
+ length: 256
31913
+ }, false, ["encrypt", "decrypt"]);
31914
+ }
31915
+ function chunkNonce(index) {
31916
+ const nonce = new Uint8Array(12);
31917
+ new DataView(nonce.buffer).setUint32(8, index >>> 0, false);
31918
+ return nonce;
31919
+ }
31920
+ function chunkAad(objectId, index) {
31921
+ const aad = new Uint8Array(objectId.length + 4);
31922
+ aad.set(objectId, 0);
31923
+ new DataView(aad.buffer).setUint32(objectId.length, index >>> 0, false);
31924
+ return aad;
31925
+ }
31926
+ async function encryptChunk(cek, objectId, index, plaintext) {
31927
+ const key = await deriveChunkKey(cek, index);
31928
+ const ct = await subtle.encrypt({
31929
+ name: "AES-GCM",
31930
+ iv: chunkNonce(index),
31931
+ additionalData: chunkAad(objectId, index)
31932
+ }, key, plaintext);
31933
+ return new Uint8Array(ct);
31934
+ }
31935
+ async function decryptChunk(cek, objectId, index, ciphertext) {
31936
+ const key = await deriveChunkKey(cek, index);
31937
+ const pt = await subtle.decrypt({
31938
+ name: "AES-GCM",
31939
+ iv: chunkNonce(index),
31940
+ additionalData: chunkAad(objectId, index)
31941
+ }, key, ciphertext);
31942
+ return new Uint8Array(pt);
31943
+ }
31944
+ function authHeaders(apiKey) {
31945
+ return { authorization: `Bearer ${apiKey}` };
31946
+ }
31947
+ function apiRoot(baseUrl) {
31948
+ let end = baseUrl.length;
31949
+ while (end > 0 && baseUrl.charCodeAt(end - 1) === 47) end--;
31950
+ return `${baseUrl.slice(0, end)}/v1/payloads`;
31951
+ }
31952
+ const DEFAULT_MAX_RETRIES = 6;
31953
+ const RETRYABLE_STATUS = new Set([
31954
+ 429,
31955
+ 500,
31956
+ 502,
31957
+ 503,
31958
+ 504
31959
+ ]);
31960
+ function sleep(ms) {
31961
+ return new Promise((resolve) => setTimeout(resolve, ms));
31962
+ }
31963
+ /**
31964
+ * fetch with exponential backoff on transient failures. Request bodies here are
31965
+ * in-memory buffers/strings (never streams), so a retry can safely resend them.
31966
+ */
31967
+ async function retryingFetch(url, init, label, maxRetries = DEFAULT_MAX_RETRIES) {
31968
+ for (let attempt = 0;; attempt++) {
31969
+ let res;
31970
+ let networkError;
31971
+ try {
31972
+ res = await fetch(url, init);
31973
+ } catch (err) {
31974
+ networkError = err;
31975
+ }
31976
+ if (res && !RETRYABLE_STATUS.has(res.status)) return res;
31977
+ if (attempt >= maxRetries) {
31978
+ if (res) return res;
31979
+ throw new Error(`${label}: network error after ${attempt} retries: ${networkError?.message ?? networkError}`);
31980
+ }
31981
+ if (res) await res.text().catch(() => {});
31982
+ await sleep(Math.min(1e3 * 2 ** attempt, 15e3) + Math.floor(Math.random() * 250));
31983
+ }
31984
+ }
31985
+ async function initiate(opts, manifest) {
31986
+ const res = await retryingFetch(apiRoot(opts.baseUrl), {
31987
+ method: "POST",
31988
+ headers: {
31989
+ ...authHeaders(opts.apiKey),
31990
+ "content-type": "application/json"
31991
+ },
31992
+ body: JSON.stringify({ manifest })
31993
+ }, "initiate");
31994
+ if (!res.ok) throw new Error(`initiate failed: HTTP ${res.status} ${await res.text()}`);
31995
+ await res.text();
31996
+ }
31997
+ async function putChunk(opts, root, d, bytes) {
31998
+ const res = await retryingFetch(`${apiRoot(opts.baseUrl)}/${root}/chunks/${d.ciphertextHash}`, {
31999
+ method: "PUT",
32000
+ headers: {
32001
+ ...authHeaders(opts.apiKey),
32002
+ "content-type": "application/octet-stream"
32003
+ },
32004
+ body: bytes
32005
+ }, `chunk ${d.index} upload`);
32006
+ if (!res.ok) throw new Error(`chunk ${d.index} upload failed: HTTP ${res.status} ${await res.text()}`);
32007
+ await res.text();
32008
+ }
32009
+ async function finalize(opts, root) {
32010
+ const res = await retryingFetch(`${apiRoot(opts.baseUrl)}/${root}/finalize`, {
32011
+ method: "POST",
32012
+ headers: authHeaders(opts.apiKey)
32013
+ }, "finalize");
32014
+ if (!res.ok) throw new Error(`finalize failed: HTTP ${res.status} ${await res.text()}`);
32015
+ await res.text();
32016
+ }
32017
+ async function fetchManifest(opts, root) {
32018
+ const res = await retryingFetch(`${apiRoot(opts.baseUrl)}/${root}/manifest`, { headers: authHeaders(opts.apiKey) }, "get manifest");
32019
+ if (!res.ok) throw new Error(`get manifest failed: HTTP ${res.status} ${await res.text()}`);
32020
+ return (await res.json()).data.manifest;
32021
+ }
32022
+ async function getChunkBytes(opts, root, d) {
32023
+ const res = await retryingFetch(`${apiRoot(opts.baseUrl)}/${root}/chunks/${d.ciphertextHash}`, { headers: authHeaders(opts.apiKey) }, `get chunk ${d.index}`);
32024
+ if (!res.ok) throw new Error(`get chunk ${d.index} failed: HTTP ${res.status}`);
32025
+ return new Uint8Array(await res.arrayBuffer());
32026
+ }
32027
+ async function readWindow(fh, position, length) {
32028
+ const buf = Buffer.allocUnsafe(length);
32029
+ let read = 0;
32030
+ while (read < length) {
32031
+ const { bytesRead } = await fh.read(buf, read, length - read, position + read);
32032
+ if (bytesRead === 0) break;
32033
+ read += bytesRead;
32034
+ }
32035
+ return read === length ? buf : buf.subarray(0, read);
32036
+ }
32037
+ async function mapLimit(items, limit, fn) {
32038
+ let next = 0;
32039
+ let firstError;
32040
+ const worker = async () => {
32041
+ while (next < items.length && firstError === void 0) {
32042
+ const i = next++;
32043
+ try {
32044
+ await fn(items[i], i);
32045
+ } catch (err) {
32046
+ if (firstError === void 0) firstError = err;
32047
+ return;
32048
+ }
32049
+ }
32050
+ };
32051
+ await Promise.all(Array.from({ length: Math.min(limit, items.length || 1) }, () => worker()));
32052
+ if (firstError !== void 0) throw firstError;
32053
+ }
32054
+ /**
32055
+ * Stream a file up as a Primitive Payload. Two passes over the file (encrypt to
32056
+ * build the manifest, then encrypt again to upload) keep memory bounded to a few
32057
+ * chunks — the whole object is never resident. Returns the content address
32058
+ * (merkleRoot) and the hex CEK needed to download it.
32059
+ */
32060
+ async function pushFile(filePath, opts) {
32061
+ const chunkSize = opts.chunkSize ?? CHUNK_SIZE;
32062
+ const concurrency = opts.concurrency ?? 3;
32063
+ const { size } = await stat(filePath);
32064
+ const cek = randomBytes(CEK_BYTES);
32065
+ const objectId = randomBytes(OBJECT_ID_BYTES);
32066
+ const chunkCount = size === 0 ? 0 : Math.ceil(size / chunkSize);
32067
+ const fh = await open(filePath, "r");
32068
+ try {
32069
+ const descriptors = [];
32070
+ for (let index = 0; index < chunkCount; index++) {
32071
+ const position = index * chunkSize;
32072
+ const length = Math.min(chunkSize, size - position);
32073
+ const plaintext = await readWindow(fh, position, length);
32074
+ const ciphertext = await encryptChunk(cek, objectId, index, plaintext);
32075
+ descriptors.push({
32076
+ index,
32077
+ ciphertextHash: await contentHashHex(ciphertext),
32078
+ plaintextSize: length,
32079
+ ciphertextSize: ciphertext.length
32080
+ });
32081
+ opts.onProgress?.("encrypt", index + 1, chunkCount);
32082
+ }
32083
+ const root = await merkleRoot(descriptors.map((d) => d.ciphertextHash));
32084
+ await initiate(opts, {
32085
+ version: MANIFEST_VERSION,
32086
+ objectId: toHex(objectId),
32087
+ chunkSize,
32088
+ totalPlaintextSize: size,
32089
+ chunkCount,
32090
+ chunks: descriptors,
32091
+ merkleRoot: root
32092
+ });
32093
+ let uploaded = 0;
32094
+ await mapLimit(descriptors, concurrency, async (d) => {
32095
+ const plaintext = await readWindow(fh, d.index * chunkSize, d.plaintextSize);
32096
+ await putChunk(opts, root, d, await encryptChunk(cek, objectId, d.index, plaintext));
32097
+ opts.onProgress?.("upload", ++uploaded, chunkCount);
32098
+ });
32099
+ await finalize(opts, root);
32100
+ return {
32101
+ merkleRoot: root,
32102
+ cek: toHex(cek),
32103
+ chunkCount,
32104
+ totalBytes: size
32105
+ };
32106
+ } finally {
32107
+ await fh.close();
32108
+ }
32109
+ }
32110
+ /**
32111
+ * Stream a Primitive Payload down to a file, verifying and decrypting one chunk
32112
+ * at a time (bounded memory). Every chunk is content-address-checked before
32113
+ * decryption, so a corrupt or substituted chunk throws.
32114
+ */
32115
+ async function pullFile(root, outPath, opts) {
32116
+ const manifest = await fetchManifest(opts, root);
32117
+ const computedRoot = await merkleRoot(manifest.chunks.map((c) => c.ciphertextHash));
32118
+ if (computedRoot !== root) throw new Error(`manifest does not match the requested content address (got ${computedRoot})`);
32119
+ const cek = fromHex(opts.cek);
32120
+ const objectId = fromHex(manifest.objectId);
32121
+ const out = createWriteStream(outPath);
32122
+ let onWriteError = () => {};
32123
+ const writeErrored = new Promise((_, reject) => {
32124
+ onWriteError = reject;
32125
+ });
32126
+ writeErrored.catch(() => {});
32127
+ out.on("error", (err) => onWriteError(err));
32128
+ try {
32129
+ let done = 0;
32130
+ for (const d of manifest.chunks) {
32131
+ const ciphertext = await getChunkBytes(opts, root, d);
32132
+ if (await contentHashHex(ciphertext) !== d.ciphertextHash) throw new Error(`chunk ${d.index} failed integrity check`);
32133
+ const plaintext = await decryptChunk(cek, objectId, d.index, ciphertext);
32134
+ if (!out.write(plaintext)) await Promise.race([new Promise((resolve) => out.once("drain", resolve)), writeErrored]);
32135
+ opts.onProgress?.("download", ++done, manifest.chunkCount);
32136
+ }
32137
+ await Promise.race([new Promise((resolve) => out.end(resolve)), writeErrored]);
32138
+ } catch (err) {
32139
+ out.destroy();
32140
+ await rm(outPath, { force: true });
32141
+ throw err;
32142
+ }
32143
+ return manifest;
32144
+ }
32145
+ //#endregion
32146
+ //#region src/oclif/commands/payloads.ts
32147
+ const DEFAULT_API_BASE_URL = "https://api.primitive.dev";
32148
+ const authFlags = {
32149
+ "api-key": Flags.string({
32150
+ description: "Primitive API key (defaults to PRIMITIVE_API_KEY or saved login credentials)",
32151
+ env: "PRIMITIVE_API_KEY"
32152
+ }),
32153
+ "api-base-url": Flags.string({
32154
+ description: "Override the API base URL. Internal testing only.",
32155
+ env: "PRIMITIVE_API_BASE_URL",
32156
+ hidden: true
32157
+ })
32158
+ };
32159
+ function resolveClient(configDir, flags) {
32160
+ const auth = resolveCliAuth({
32161
+ configDir,
32162
+ apiKey: flags["api-key"],
32163
+ apiBaseUrl: flags["api-base-url"]
32164
+ });
32165
+ if (!auth.apiKey) throw new Error("Not authenticated: set PRIMITIVE_API_KEY, pass --api-key, or run `primitive login`.");
32166
+ return {
32167
+ baseUrl: auth.apiBaseUrl ?? DEFAULT_API_BASE_URL,
32168
+ apiKey: auth.apiKey
32169
+ };
32170
+ }
32171
+ function progressToStderr() {
32172
+ let lastPct = -1;
32173
+ return (phase, done, total) => {
32174
+ const pct = total === 0 ? 100 : Math.floor(done / total * 100);
32175
+ if (pct !== lastPct) {
32176
+ lastPct = pct;
32177
+ process.stderr.write(`\r${phase}: ${done}/${total} (${pct}%) `);
32178
+ if (done === total) process.stderr.write("\n");
32179
+ }
32180
+ };
32181
+ }
32182
+ var PayloadsPushCommand = class PayloadsPushCommand extends Command {
32183
+ static description = `Upload a file as a Primitive Payload — a large, content-addressed, end-to-end-encrypted object.
32184
+
32185
+ The file is chunked and encrypted client-side and streamed up in bounded
32186
+ memory (multi-GB files never load fully into RAM). Prints the object's content
32187
+ address (merkle_root) and the hex CEK required to download it — keep the CEK
32188
+ secret; without it the object cannot be decrypted.`;
32189
+ static summary = "Stream-upload a file as an encrypted payload";
32190
+ static examples = ["<%= config.bin %> payloads push ./big-video.mp4"];
32191
+ static args = { file: Args.string({
32192
+ required: true,
32193
+ description: "Path to the file to upload"
32194
+ }) };
32195
+ static flags = {
32196
+ ...authFlags,
32197
+ concurrency: Flags.integer({
32198
+ description: "Parallel chunk uploads",
32199
+ default: 3
32200
+ }),
32201
+ quiet: Flags.boolean({
32202
+ description: "Suppress progress output",
32203
+ default: false
32204
+ })
32205
+ };
32206
+ async run() {
32207
+ const { args, flags } = await this.parse(PayloadsPushCommand);
32208
+ const { baseUrl, apiKey } = resolveClient(this.config.configDir, flags);
32209
+ const result = await pushFile(args.file, {
32210
+ baseUrl,
32211
+ apiKey,
32212
+ concurrency: flags.concurrency,
32213
+ onProgress: flags.quiet ? void 0 : progressToStderr()
32214
+ });
32215
+ this.log(JSON.stringify({
32216
+ merkle_root: result.merkleRoot,
32217
+ cek: result.cek,
32218
+ chunk_count: result.chunkCount,
32219
+ total_bytes: result.totalBytes
32220
+ }, null, 2));
32221
+ }
32222
+ };
32223
+ var PayloadsPullCommand = class PayloadsPullCommand extends Command {
32224
+ static description = `Download and decrypt a Primitive Payload to a file.
32225
+
32226
+ Streams one chunk at a time, verifying each against its content address before
32227
+ decryption, so a corrupt or substituted chunk fails loudly. Requires the hex
32228
+ CEK printed by \`payloads push\`.`;
32229
+ static summary = "Stream-download and decrypt a payload to a file";
32230
+ static examples = ["<%= config.bin %> payloads pull <merkle_root> --cek <hex> --out ./restored.mp4"];
32231
+ static args = { root: Args.string({
32232
+ required: true,
32233
+ description: "Object content address (merkle_root)"
32234
+ }) };
32235
+ static flags = {
32236
+ ...authFlags,
32237
+ out: Flags.string({
32238
+ required: true,
32239
+ description: "Output file path"
32240
+ }),
32241
+ cek: Flags.string({
32242
+ required: true,
32243
+ description: "Hex content-encryption key from `payloads push`"
32244
+ }),
32245
+ quiet: Flags.boolean({
32246
+ description: "Suppress progress output",
32247
+ default: false
32248
+ })
32249
+ };
32250
+ async run() {
32251
+ const { args, flags } = await this.parse(PayloadsPullCommand);
32252
+ const { baseUrl, apiKey } = resolveClient(this.config.configDir, flags);
32253
+ const manifest = await pullFile(args.root, flags.out, {
32254
+ baseUrl,
32255
+ apiKey,
32256
+ cek: flags.cek,
32257
+ onProgress: flags.quiet ? void 0 : progressToStderr()
32258
+ });
32259
+ this.log(JSON.stringify({
32260
+ merkle_root: args.root,
32261
+ out: flags.out,
32262
+ chunk_count: manifest.chunkCount,
32263
+ total_bytes: manifest.totalPlaintextSize
32264
+ }, null, 2));
32265
+ }
32266
+ };
32267
+ //#endregion
30391
32268
  //#region ../sdk-node/dist/x402/index.js
30392
32269
  /**
30393
32270
  * x402 client-side signing.
@@ -31817,7 +33694,7 @@ async function pollForSettlementInteraction(params) {
31817
33694
  }
31818
33695
  if (receipt) return receipt;
31819
33696
  if (deadline !== null && Date.now() >= deadline) break;
31820
- await sleep$1(params.intervalSeconds * 1e3);
33697
+ await sleep$2(params.intervalSeconds * 1e3);
31821
33698
  }
31822
33699
  return null;
31823
33700
  }
@@ -34779,6 +36656,8 @@ const COMMANDS = {
34779
36656
  "org:secrets:list": OrgSecretsListCommand,
34780
36657
  "org:secrets:set": OrgSecretsSetCommand,
34781
36658
  "org:secrets:remove": OrgSecretsRemoveCommand,
36659
+ "payloads:push": PayloadsPushCommand,
36660
+ "payloads:pull": PayloadsPullCommand,
34782
36661
  "functions:test": FunctionsTestFunctionCommand,
34783
36662
  "functions:test-function": FunctionsTestFunctionCommand,
34784
36663
  "functions:route-set": FunctionsRouteSetCommand,