@primitivedotdev/sdk 0.19.0 → 0.20.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.
@@ -62,6 +62,10 @@ export const openapiDocument = {
62
62
  {
63
63
  "name": "Webhook Deliveries",
64
64
  "description": "View and replay webhook delivery attempts"
65
+ },
66
+ {
67
+ "name": "Functions",
68
+ "description": "Deploy JavaScript handlers that run on inbound mail. Each function\nexports a default async handler receiving the `email.received`\nevent. Code runs on Primitive's edge runtime; there is no\ninfrastructure to manage. Secrets land in `env` as encrypted\nbindings and are refreshed on every redeploy.\n"
65
69
  }
66
70
  ],
67
71
  "paths": {
@@ -2075,7 +2079,519 @@ export const openapiDocument = {
2075
2079
  "type": "object",
2076
2080
  "properties": {
2077
2081
  "data": {
2078
- "$ref": "#/components/schemas/SentEmailDetail"
2082
+ "$ref": "#/components/schemas/SentEmailDetail"
2083
+ }
2084
+ }
2085
+ }
2086
+ ]
2087
+ }
2088
+ }
2089
+ }
2090
+ },
2091
+ "400": {
2092
+ "$ref": "#/components/responses/ValidationError"
2093
+ },
2094
+ "401": {
2095
+ "$ref": "#/components/responses/Unauthorized"
2096
+ },
2097
+ "404": {
2098
+ "$ref": "#/components/responses/NotFound"
2099
+ }
2100
+ }
2101
+ }
2102
+ },
2103
+ "/functions": {
2104
+ "get": {
2105
+ "operationId": "listFunctions",
2106
+ "summary": "List functions",
2107
+ "description": "Returns every active (non-deleted) function in the org, newest\nfirst. Each entry carries the deploy status and the gateway URL\nthat the platform's webhook delivery loop posts to. To inspect\nthe source code or deploy errors, use `GET /functions/{id}`.\n",
2108
+ "tags": [
2109
+ "Functions"
2110
+ ],
2111
+ "responses": {
2112
+ "200": {
2113
+ "description": "List of functions",
2114
+ "content": {
2115
+ "application/json": {
2116
+ "schema": {
2117
+ "allOf": [
2118
+ {
2119
+ "$ref": "#/components/schemas/SuccessEnvelope"
2120
+ },
2121
+ {
2122
+ "type": "object",
2123
+ "properties": {
2124
+ "data": {
2125
+ "type": "array",
2126
+ "items": {
2127
+ "$ref": "#/components/schemas/FunctionListItem"
2128
+ }
2129
+ }
2130
+ }
2131
+ }
2132
+ ]
2133
+ }
2134
+ }
2135
+ }
2136
+ },
2137
+ "401": {
2138
+ "$ref": "#/components/responses/Unauthorized"
2139
+ }
2140
+ }
2141
+ },
2142
+ "post": {
2143
+ "operationId": "createFunction",
2144
+ "summary": "Deploy a function",
2145
+ "description": "Creates and deploys a new function. The handler must be a single\nESM module that exports a default async function receiving the\n`email.received` event (see the Webhook payload section for the\nfull schema). Code is bundled before being uploaded; ship a\nsingle self-contained file rather than relying on external\nimports.\n\n**Code limits.** `code` is capped at 1 MiB UTF-8. `sourceMap`\n(optional) is capped at 5 MiB UTF-8 and is stored only on the\nedge runtime side; it is not persisted in Primitive's database.\n\n**Auto-wiring.** On successful deploy, Primitive automatically\ncreates a webhook endpoint that delivers inbound mail to the\nfunction. There is nothing to configure on the Endpoints API\nfor this to work; the gateway URL returned here is for\nreference only and is not directly callable from outside.\n\n**Secrets.** New functions ship with the managed secrets\n(`PRIMITIVE_WEBHOOK_SECRET`, `PRIMITIVE_API_KEY`) already\nbound. Add user-set secrets via\n`POST /functions/{id}/secrets`; secret writes only land in the\nrunning handler on the next redeploy.\n",
2146
+ "tags": [
2147
+ "Functions"
2148
+ ],
2149
+ "requestBody": {
2150
+ "required": true,
2151
+ "content": {
2152
+ "application/json": {
2153
+ "schema": {
2154
+ "$ref": "#/components/schemas/CreateFunctionInput"
2155
+ }
2156
+ }
2157
+ }
2158
+ },
2159
+ "responses": {
2160
+ "201": {
2161
+ "description": "Function created and deployed",
2162
+ "content": {
2163
+ "application/json": {
2164
+ "schema": {
2165
+ "allOf": [
2166
+ {
2167
+ "$ref": "#/components/schemas/SuccessEnvelope"
2168
+ },
2169
+ {
2170
+ "type": "object",
2171
+ "properties": {
2172
+ "data": {
2173
+ "$ref": "#/components/schemas/CreateFunctionResult"
2174
+ }
2175
+ }
2176
+ }
2177
+ ]
2178
+ }
2179
+ }
2180
+ }
2181
+ },
2182
+ "400": {
2183
+ "$ref": "#/components/responses/ValidationError"
2184
+ },
2185
+ "401": {
2186
+ "$ref": "#/components/responses/Unauthorized"
2187
+ },
2188
+ "409": {
2189
+ "description": "A function with this name already exists in the org",
2190
+ "content": {
2191
+ "application/json": {
2192
+ "schema": {
2193
+ "$ref": "#/components/schemas/ErrorResponse"
2194
+ }
2195
+ }
2196
+ }
2197
+ },
2198
+ "502": {
2199
+ "$ref": "#/components/responses/BadGateway"
2200
+ }
2201
+ }
2202
+ }
2203
+ },
2204
+ "/functions/{id}": {
2205
+ "parameters": [
2206
+ {
2207
+ "$ref": "#/components/parameters/ResourceId"
2208
+ }
2209
+ ],
2210
+ "get": {
2211
+ "operationId": "getFunction",
2212
+ "summary": "Get a function",
2213
+ "description": "Returns the full record for a function, including its current\nsource code and the deploy status / error from the most recent\ndeploy attempt.\n",
2214
+ "tags": [
2215
+ "Functions"
2216
+ ],
2217
+ "responses": {
2218
+ "200": {
2219
+ "description": "Function record",
2220
+ "content": {
2221
+ "application/json": {
2222
+ "schema": {
2223
+ "allOf": [
2224
+ {
2225
+ "$ref": "#/components/schemas/SuccessEnvelope"
2226
+ },
2227
+ {
2228
+ "type": "object",
2229
+ "properties": {
2230
+ "data": {
2231
+ "$ref": "#/components/schemas/FunctionDetail"
2232
+ }
2233
+ }
2234
+ }
2235
+ ]
2236
+ }
2237
+ }
2238
+ }
2239
+ },
2240
+ "401": {
2241
+ "$ref": "#/components/responses/Unauthorized"
2242
+ },
2243
+ "404": {
2244
+ "$ref": "#/components/responses/NotFound"
2245
+ }
2246
+ }
2247
+ },
2248
+ "put": {
2249
+ "operationId": "updateFunction",
2250
+ "summary": "Update and redeploy a function",
2251
+ "description": "Replaces the function's source code with the body's `code` and\ntriggers a redeploy. Same size limits as `POST /functions`.\nUse this verb to push secret writes into the running handler:\npassing the same `code` re-runs the deploy and refreshes the\nbinding set with the latest values from the secrets table.\n\nOn a 502 deploy failure, the previously-deployed code stays\nlive; the runtime never serves a half-built bundle. The\n`deploy_error` field on the returned record carries the error\nthat came back from the runtime so you can surface it to users\nwithout polling.\n",
2252
+ "tags": [
2253
+ "Functions"
2254
+ ],
2255
+ "requestBody": {
2256
+ "required": true,
2257
+ "content": {
2258
+ "application/json": {
2259
+ "schema": {
2260
+ "$ref": "#/components/schemas/UpdateFunctionInput"
2261
+ }
2262
+ }
2263
+ }
2264
+ },
2265
+ "responses": {
2266
+ "200": {
2267
+ "description": "Updated function",
2268
+ "content": {
2269
+ "application/json": {
2270
+ "schema": {
2271
+ "allOf": [
2272
+ {
2273
+ "$ref": "#/components/schemas/SuccessEnvelope"
2274
+ },
2275
+ {
2276
+ "type": "object",
2277
+ "properties": {
2278
+ "data": {
2279
+ "$ref": "#/components/schemas/FunctionDetail"
2280
+ }
2281
+ }
2282
+ }
2283
+ ]
2284
+ }
2285
+ }
2286
+ }
2287
+ },
2288
+ "400": {
2289
+ "$ref": "#/components/responses/ValidationError"
2290
+ },
2291
+ "401": {
2292
+ "$ref": "#/components/responses/Unauthorized"
2293
+ },
2294
+ "404": {
2295
+ "$ref": "#/components/responses/NotFound"
2296
+ },
2297
+ "502": {
2298
+ "$ref": "#/components/responses/BadGateway"
2299
+ }
2300
+ }
2301
+ },
2302
+ "delete": {
2303
+ "operationId": "deleteFunction",
2304
+ "summary": "Delete a function",
2305
+ "description": "Soft-deletes the function row, removes the script from the edge\nruntime, and deactivates the auto-wired webhook endpoint so no\nfurther inbound mail is delivered. Past deploy history,\ninvocations, and logs are retained.\n\nReturns 502 if the runtime delete fails partway; the function\nrow stays in place and the call is safe to retry until it\nsucceeds.\n",
2306
+ "tags": [
2307
+ "Functions"
2308
+ ],
2309
+ "responses": {
2310
+ "200": {
2311
+ "$ref": "#/components/responses/Deleted"
2312
+ },
2313
+ "401": {
2314
+ "$ref": "#/components/responses/Unauthorized"
2315
+ },
2316
+ "404": {
2317
+ "$ref": "#/components/responses/NotFound"
2318
+ },
2319
+ "502": {
2320
+ "$ref": "#/components/responses/BadGateway"
2321
+ }
2322
+ }
2323
+ }
2324
+ },
2325
+ "/functions/{id}/test": {
2326
+ "parameters": [
2327
+ {
2328
+ "$ref": "#/components/parameters/ResourceId"
2329
+ }
2330
+ ],
2331
+ "post": {
2332
+ "operationId": "testFunction",
2333
+ "summary": "Send a test invocation",
2334
+ "description": "Sends a real test email from a Primitive-controlled sender to a\nsynthetic local-part on one of the org's verified inbound\ndomains. The function fires through the normal MX delivery\npath, so reply / send-mail calls from inside the handler\nagainst the inbound's `email.id` work the same as in\nproduction. Returns immediately after the send is queued; the\ninvocation appears on the function's invocations list within a\nfew seconds.\n\nRequires that the function is currently `deployed`. Returns 422\nif the function is in `pending` or `failed` state, or if the\norg has no verified inbound domain to receive the test mail.\n",
2335
+ "tags": [
2336
+ "Functions"
2337
+ ],
2338
+ "responses": {
2339
+ "200": {
2340
+ "description": "Test send queued",
2341
+ "content": {
2342
+ "application/json": {
2343
+ "schema": {
2344
+ "allOf": [
2345
+ {
2346
+ "$ref": "#/components/schemas/SuccessEnvelope"
2347
+ },
2348
+ {
2349
+ "type": "object",
2350
+ "properties": {
2351
+ "data": {
2352
+ "$ref": "#/components/schemas/TestInvocationResult"
2353
+ }
2354
+ }
2355
+ }
2356
+ ]
2357
+ }
2358
+ }
2359
+ }
2360
+ },
2361
+ "400": {
2362
+ "$ref": "#/components/responses/ValidationError"
2363
+ },
2364
+ "401": {
2365
+ "$ref": "#/components/responses/Unauthorized"
2366
+ },
2367
+ "404": {
2368
+ "$ref": "#/components/responses/NotFound"
2369
+ },
2370
+ "422": {
2371
+ "description": "Function not in a state that can be invoked, or no inbound domain configured",
2372
+ "content": {
2373
+ "application/json": {
2374
+ "schema": {
2375
+ "$ref": "#/components/schemas/ErrorResponse"
2376
+ }
2377
+ }
2378
+ }
2379
+ },
2380
+ "502": {
2381
+ "$ref": "#/components/responses/BadGateway"
2382
+ },
2383
+ "503": {
2384
+ "description": "Sending agent misconfigured",
2385
+ "content": {
2386
+ "application/json": {
2387
+ "schema": {
2388
+ "$ref": "#/components/schemas/ErrorResponse"
2389
+ }
2390
+ }
2391
+ }
2392
+ }
2393
+ }
2394
+ }
2395
+ },
2396
+ "/functions/{id}/secrets": {
2397
+ "parameters": [
2398
+ {
2399
+ "$ref": "#/components/parameters/ResourceId"
2400
+ }
2401
+ ],
2402
+ "get": {
2403
+ "operationId": "listFunctionSecrets",
2404
+ "summary": "List a function's secrets",
2405
+ "description": "Returns metadata for every secret bound to the function, with\nmanaged entries (provisioned by Primitive) listed first and\nuser-set entries listed alphabetically after. **Values are\nnever returned.** Secret writes are write-only.\n\nManaged entries (e.g. `PRIMITIVE_WEBHOOK_SECRET`,\n`PRIMITIVE_API_KEY`) carry a `description` instead of\n`created_at` / `updated_at`. They cannot be created, updated,\nor deleted via this API.\n",
2406
+ "tags": [
2407
+ "Functions"
2408
+ ],
2409
+ "responses": {
2410
+ "200": {
2411
+ "description": "List of secrets (metadata only, no values)",
2412
+ "content": {
2413
+ "application/json": {
2414
+ "schema": {
2415
+ "allOf": [
2416
+ {
2417
+ "$ref": "#/components/schemas/SuccessEnvelope"
2418
+ },
2419
+ {
2420
+ "type": "object",
2421
+ "properties": {
2422
+ "data": {
2423
+ "type": "object",
2424
+ "properties": {
2425
+ "items": {
2426
+ "type": "array",
2427
+ "items": {
2428
+ "$ref": "#/components/schemas/FunctionSecretListItem"
2429
+ }
2430
+ }
2431
+ },
2432
+ "required": [
2433
+ "items"
2434
+ ]
2435
+ }
2436
+ }
2437
+ }
2438
+ ]
2439
+ }
2440
+ }
2441
+ }
2442
+ },
2443
+ "401": {
2444
+ "$ref": "#/components/responses/Unauthorized"
2445
+ },
2446
+ "404": {
2447
+ "$ref": "#/components/responses/NotFound"
2448
+ }
2449
+ }
2450
+ },
2451
+ "post": {
2452
+ "operationId": "createFunctionSecret",
2453
+ "summary": "Create or update a secret",
2454
+ "description": "Idempotent insert-or-update keyed on `(function_id, key)`.\nReturns 201 the first time the key is set, 200 on subsequent\nupdates. Values are encrypted at rest and only become visible\nto the running handler on the next deploy (`PUT /functions/{id}`\nwith the existing code is sufficient to refresh bindings).\n\nKeys must match `^[A-Z_][A-Z0-9_]*$` (uppercase letters,\ndigits, underscores; first character is a letter or\nunderscore). Values are at most 4096 UTF-8 bytes. System-\nmanaged keys are reserved and rejected.\n",
2455
+ "tags": [
2456
+ "Functions"
2457
+ ],
2458
+ "requestBody": {
2459
+ "required": true,
2460
+ "content": {
2461
+ "application/json": {
2462
+ "schema": {
2463
+ "$ref": "#/components/schemas/CreateFunctionSecretInput"
2464
+ }
2465
+ }
2466
+ }
2467
+ },
2468
+ "responses": {
2469
+ "200": {
2470
+ "description": "Secret updated",
2471
+ "content": {
2472
+ "application/json": {
2473
+ "schema": {
2474
+ "allOf": [
2475
+ {
2476
+ "$ref": "#/components/schemas/SuccessEnvelope"
2477
+ },
2478
+ {
2479
+ "type": "object",
2480
+ "properties": {
2481
+ "data": {
2482
+ "$ref": "#/components/schemas/FunctionSecretWriteResult"
2483
+ }
2484
+ }
2485
+ }
2486
+ ]
2487
+ }
2488
+ }
2489
+ }
2490
+ },
2491
+ "201": {
2492
+ "description": "Secret created",
2493
+ "content": {
2494
+ "application/json": {
2495
+ "schema": {
2496
+ "allOf": [
2497
+ {
2498
+ "$ref": "#/components/schemas/SuccessEnvelope"
2499
+ },
2500
+ {
2501
+ "type": "object",
2502
+ "properties": {
2503
+ "data": {
2504
+ "$ref": "#/components/schemas/FunctionSecretWriteResult"
2505
+ }
2506
+ }
2507
+ }
2508
+ ]
2509
+ }
2510
+ }
2511
+ }
2512
+ },
2513
+ "400": {
2514
+ "$ref": "#/components/responses/ValidationError"
2515
+ },
2516
+ "401": {
2517
+ "$ref": "#/components/responses/Unauthorized"
2518
+ },
2519
+ "404": {
2520
+ "$ref": "#/components/responses/NotFound"
2521
+ }
2522
+ }
2523
+ }
2524
+ },
2525
+ "/functions/{id}/secrets/{key}": {
2526
+ "parameters": [
2527
+ {
2528
+ "$ref": "#/components/parameters/ResourceId"
2529
+ },
2530
+ {
2531
+ "name": "key",
2532
+ "in": "path",
2533
+ "required": true,
2534
+ "description": "Secret key. Must match `^[A-Z_][A-Z0-9_]*$`.",
2535
+ "schema": {
2536
+ "type": "string",
2537
+ "pattern": "^[A-Z_][A-Z0-9_]*$"
2538
+ }
2539
+ }
2540
+ ],
2541
+ "put": {
2542
+ "operationId": "setFunctionSecret",
2543
+ "summary": "Set a secret by key",
2544
+ "description": "Path-keyed companion to `POST /functions/{id}/secrets`.\nIdempotent: returns 201 the first time the key is set, 200 on\nsubsequent updates. Same validation rules and same write-only\nguarantees as the POST verb; the new value lands in the running\nhandler on the next deploy.\n",
2545
+ "tags": [
2546
+ "Functions"
2547
+ ],
2548
+ "requestBody": {
2549
+ "required": true,
2550
+ "content": {
2551
+ "application/json": {
2552
+ "schema": {
2553
+ "$ref": "#/components/schemas/SetFunctionSecretInput"
2554
+ }
2555
+ }
2556
+ }
2557
+ },
2558
+ "responses": {
2559
+ "200": {
2560
+ "description": "Secret updated",
2561
+ "content": {
2562
+ "application/json": {
2563
+ "schema": {
2564
+ "allOf": [
2565
+ {
2566
+ "$ref": "#/components/schemas/SuccessEnvelope"
2567
+ },
2568
+ {
2569
+ "type": "object",
2570
+ "properties": {
2571
+ "data": {
2572
+ "$ref": "#/components/schemas/FunctionSecretWriteResult"
2573
+ }
2574
+ }
2575
+ }
2576
+ ]
2577
+ }
2578
+ }
2579
+ }
2580
+ },
2581
+ "201": {
2582
+ "description": "Secret created",
2583
+ "content": {
2584
+ "application/json": {
2585
+ "schema": {
2586
+ "allOf": [
2587
+ {
2588
+ "$ref": "#/components/schemas/SuccessEnvelope"
2589
+ },
2590
+ {
2591
+ "type": "object",
2592
+ "properties": {
2593
+ "data": {
2594
+ "$ref": "#/components/schemas/FunctionSecretWriteResult"
2079
2595
  }
2080
2596
  }
2081
2597
  }
@@ -2094,6 +2610,28 @@ export const openapiDocument = {
2094
2610
  "$ref": "#/components/responses/NotFound"
2095
2611
  }
2096
2612
  }
2613
+ },
2614
+ "delete": {
2615
+ "operationId": "deleteFunctionSecret",
2616
+ "summary": "Delete a secret",
2617
+ "description": "Removes the secret. The binding stays live in the running\nhandler until the next deploy refreshes the binding set\n(`PUT /functions/{id}` with the existing code is sufficient).\nReturns 404 if the key did not exist. Managed system keys\ncannot be deleted.\n",
2618
+ "tags": [
2619
+ "Functions"
2620
+ ],
2621
+ "responses": {
2622
+ "204": {
2623
+ "description": "Secret deleted"
2624
+ },
2625
+ "400": {
2626
+ "$ref": "#/components/responses/ValidationError"
2627
+ },
2628
+ "401": {
2629
+ "$ref": "#/components/responses/Unauthorized"
2630
+ },
2631
+ "404": {
2632
+ "$ref": "#/components/responses/NotFound"
2633
+ }
2634
+ }
2097
2635
  }
2098
2636
  }
2099
2637
  },
@@ -4318,6 +4856,339 @@ export const openapiDocument = {
4318
4856
  "discarded",
4319
4857
  "already_discarded"
4320
4858
  ]
4859
+ },
4860
+ "FunctionDeployStatus": {
4861
+ "type": "string",
4862
+ "enum": [
4863
+ "pending",
4864
+ "deployed",
4865
+ "failed"
4866
+ ],
4867
+ "description": "Lifecycle state of the latest deploy attempt:\n * `pending` — deploy in flight; the runtime has not yet\n confirmed the new bundle is live.\n * `deployed` — the running edge handler is the latest code.\n * `failed` — the most recent deploy attempt failed; the\n previously-live code (if any) is still running. The\n `deploy_error` field carries the error message.\n"
4868
+ },
4869
+ "FunctionListItem": {
4870
+ "type": "object",
4871
+ "description": "One row from the function listing.",
4872
+ "properties": {
4873
+ "id": {
4874
+ "type": "string",
4875
+ "format": "uuid",
4876
+ "description": "Function id, also the script name in the edge runtime."
4877
+ },
4878
+ "name": {
4879
+ "type": "string",
4880
+ "description": "Slug-style name set on creation. Stable; cannot be changed."
4881
+ },
4882
+ "deploy_status": {
4883
+ "$ref": "#/components/schemas/FunctionDeployStatus"
4884
+ },
4885
+ "deployed_at": {
4886
+ "type": [
4887
+ "string",
4888
+ "null"
4889
+ ],
4890
+ "format": "date-time",
4891
+ "description": "Timestamp of the most recent successful deploy. Null until the first deploy succeeds."
4892
+ },
4893
+ "gateway_url": {
4894
+ "type": "string",
4895
+ "format": "uri",
4896
+ "description": "URL the platform's webhook delivery loop posts to in order\nto invoke the function. Reference only; not directly\ncallable from outside.\n"
4897
+ },
4898
+ "created_at": {
4899
+ "type": "string",
4900
+ "format": "date-time"
4901
+ },
4902
+ "updated_at": {
4903
+ "type": "string",
4904
+ "format": "date-time"
4905
+ }
4906
+ },
4907
+ "required": [
4908
+ "id",
4909
+ "name",
4910
+ "deploy_status",
4911
+ "gateway_url",
4912
+ "created_at",
4913
+ "updated_at"
4914
+ ]
4915
+ },
4916
+ "FunctionDetail": {
4917
+ "type": "object",
4918
+ "description": "Full function record returned by GET / PUT.",
4919
+ "properties": {
4920
+ "id": {
4921
+ "type": "string",
4922
+ "format": "uuid"
4923
+ },
4924
+ "name": {
4925
+ "type": "string"
4926
+ },
4927
+ "code": {
4928
+ "type": "string",
4929
+ "description": "The bundled handler source. UTF-8 string up to 1 MiB. The\nsame value most recently passed as `code` to POST or PUT.\n"
4930
+ },
4931
+ "deploy_status": {
4932
+ "$ref": "#/components/schemas/FunctionDeployStatus"
4933
+ },
4934
+ "deploy_error": {
4935
+ "type": [
4936
+ "string",
4937
+ "null"
4938
+ ],
4939
+ "description": "Error message from the most recent failed deploy, or null\nafter a successful deploy. Surface this to users to explain\na `failed` status without polling.\n"
4940
+ },
4941
+ "deployed_at": {
4942
+ "type": [
4943
+ "string",
4944
+ "null"
4945
+ ],
4946
+ "format": "date-time"
4947
+ },
4948
+ "gateway_url": {
4949
+ "type": "string",
4950
+ "format": "uri"
4951
+ },
4952
+ "created_at": {
4953
+ "type": "string",
4954
+ "format": "date-time"
4955
+ },
4956
+ "updated_at": {
4957
+ "type": "string",
4958
+ "format": "date-time"
4959
+ }
4960
+ },
4961
+ "required": [
4962
+ "id",
4963
+ "name",
4964
+ "code",
4965
+ "deploy_status",
4966
+ "gateway_url",
4967
+ "created_at",
4968
+ "updated_at"
4969
+ ]
4970
+ },
4971
+ "CreateFunctionInput": {
4972
+ "type": "object",
4973
+ "additionalProperties": false,
4974
+ "properties": {
4975
+ "name": {
4976
+ "type": "string",
4977
+ "pattern": "^[a-z0-9_-]{1,64}$",
4978
+ "description": "Slug-style name. Lowercase letters, digits, hyphens, and\nunderscores. 1 to 64 characters. Must be unique within the\norg; a 409 is returned on collision.\n"
4979
+ },
4980
+ "code": {
4981
+ "type": "string",
4982
+ "minLength": 1,
4983
+ "maxLength": 1048576,
4984
+ "description": "Bundled handler as a single ESM module. Up to 1 MiB UTF-8.\nMust export a default `{ async fetch(req, env, ctx) { ... } }`\nobject.\n"
4985
+ },
4986
+ "sourceMap": {
4987
+ "type": "string",
4988
+ "minLength": 1,
4989
+ "maxLength": 5242880,
4990
+ "description": "Optional source map for the bundle. Up to 5 MiB UTF-8.\nStored only on the runtime side (not in Primitive's\ndatabase) and used to symbolicate stack traces in the\nfunction's logs.\n"
4991
+ }
4992
+ },
4993
+ "required": [
4994
+ "name",
4995
+ "code"
4996
+ ]
4997
+ },
4998
+ "CreateFunctionResult": {
4999
+ "type": "object",
5000
+ "description": "Returned by POST /functions on a successful deploy.",
5001
+ "properties": {
5002
+ "id": {
5003
+ "type": "string",
5004
+ "format": "uuid"
5005
+ },
5006
+ "name": {
5007
+ "type": "string"
5008
+ },
5009
+ "deploy_status": {
5010
+ "$ref": "#/components/schemas/FunctionDeployStatus"
5011
+ },
5012
+ "gateway_url": {
5013
+ "type": "string",
5014
+ "format": "uri"
5015
+ }
5016
+ },
5017
+ "required": [
5018
+ "id",
5019
+ "name",
5020
+ "deploy_status",
5021
+ "gateway_url"
5022
+ ]
5023
+ },
5024
+ "UpdateFunctionInput": {
5025
+ "type": "object",
5026
+ "additionalProperties": false,
5027
+ "properties": {
5028
+ "code": {
5029
+ "type": "string",
5030
+ "minLength": 1,
5031
+ "maxLength": 1048576,
5032
+ "description": "New bundled handler. Same rules as CreateFunctionInput.code."
5033
+ },
5034
+ "sourceMap": {
5035
+ "type": "string",
5036
+ "minLength": 1,
5037
+ "maxLength": 5242880
5038
+ }
5039
+ },
5040
+ "required": [
5041
+ "code"
5042
+ ]
5043
+ },
5044
+ "TestInvocationResult": {
5045
+ "type": "object",
5046
+ "description": "Metadata returned by POST /functions/{id}/test. The send is\nqueued; the actual invocation lands on the function's\ninvocations list a few seconds later as the inbound mail\ntraverses the MX path.\n",
5047
+ "properties": {
5048
+ "inbound_domain": {
5049
+ "type": "string",
5050
+ "description": "Verified inbound domain the test email was sent to."
5051
+ },
5052
+ "to": {
5053
+ "type": "string",
5054
+ "description": "Synthetic local-part plus inbound_domain. Visible in the org's inbox."
5055
+ },
5056
+ "from": {
5057
+ "type": "string",
5058
+ "description": "Primitive-controlled outbound sender used for the test."
5059
+ },
5060
+ "send_id": {
5061
+ "type": "string",
5062
+ "description": "Outbound message id from the underlying send. NOT the\ninbound email's id; the inbound id is created when the\nemail arrives via MX and lands on the function's\ninvocations list.\n"
5063
+ },
5064
+ "subject": {
5065
+ "type": "string",
5066
+ "description": "Subject placed on the test email so it can be located in the inbox."
5067
+ },
5068
+ "poll_since": {
5069
+ "type": "string",
5070
+ "format": "date-time",
5071
+ "description": "ISO timestamp suitable as a `since` lower bound when\npolling /emails for the inbound's arrival. Captured\nslightly before the send to absorb light clock skew.\n"
5072
+ },
5073
+ "watch_url": {
5074
+ "type": "string",
5075
+ "format": "uri",
5076
+ "description": "Function detail page where invocations show up live."
5077
+ }
5078
+ },
5079
+ "required": [
5080
+ "inbound_domain",
5081
+ "to",
5082
+ "from",
5083
+ "send_id",
5084
+ "subject",
5085
+ "poll_since",
5086
+ "watch_url"
5087
+ ]
5088
+ },
5089
+ "FunctionSecretListItem": {
5090
+ "type": "object",
5091
+ "description": "One row from GET /functions/{id}/secrets. Discriminate on the\n`managed` field:\n * `managed = true` — system secret provisioned by Primitive.\n `description` is set; `created_at` / `updated_at` are\n null because the row is virtual (resolved at deploy time\n from the managed registry, not stored in the secrets\n table).\n * `managed = false` — secret the user set via the API.\n `created_at` / `updated_at` are set; `description` is\n null.\n",
5092
+ "properties": {
5093
+ "key": {
5094
+ "type": "string"
5095
+ },
5096
+ "managed": {
5097
+ "type": "boolean",
5098
+ "description": "True for managed system secrets, false for user-set entries."
5099
+ },
5100
+ "description": {
5101
+ "type": [
5102
+ "string",
5103
+ "null"
5104
+ ],
5105
+ "description": "Set on managed entries only; null on user-set entries."
5106
+ },
5107
+ "created_at": {
5108
+ "type": [
5109
+ "string",
5110
+ "null"
5111
+ ],
5112
+ "format": "date-time",
5113
+ "description": "Set on user-set entries only; null on managed entries."
5114
+ },
5115
+ "updated_at": {
5116
+ "type": [
5117
+ "string",
5118
+ "null"
5119
+ ],
5120
+ "format": "date-time",
5121
+ "description": "Set on user-set entries only; null on managed entries."
5122
+ }
5123
+ },
5124
+ "required": [
5125
+ "key",
5126
+ "managed"
5127
+ ]
5128
+ },
5129
+ "CreateFunctionSecretInput": {
5130
+ "type": "object",
5131
+ "additionalProperties": false,
5132
+ "description": "Body for POST /functions/{id}/secrets.",
5133
+ "properties": {
5134
+ "key": {
5135
+ "type": "string",
5136
+ "pattern": "^[A-Z_][A-Z0-9_]*$",
5137
+ "description": "Uppercase letters, digits, and underscores. Must start with\na letter or underscore. System-managed keys (e.g.\nPRIMITIVE_WEBHOOK_SECRET) are reserved.\n"
5138
+ },
5139
+ "value": {
5140
+ "type": "string",
5141
+ "minLength": 1,
5142
+ "maxLength": 4096,
5143
+ "description": "Secret value, up to 4096 UTF-8 bytes. Encrypted at rest.\nNever returned by any read endpoint.\n"
5144
+ }
5145
+ },
5146
+ "required": [
5147
+ "key",
5148
+ "value"
5149
+ ]
5150
+ },
5151
+ "SetFunctionSecretInput": {
5152
+ "type": "object",
5153
+ "additionalProperties": false,
5154
+ "description": "Body for PUT /functions/{id}/secrets/{key}. Key comes from the path.",
5155
+ "properties": {
5156
+ "value": {
5157
+ "type": "string",
5158
+ "minLength": 1,
5159
+ "maxLength": 4096
5160
+ }
5161
+ },
5162
+ "required": [
5163
+ "value"
5164
+ ]
5165
+ },
5166
+ "FunctionSecretWriteResult": {
5167
+ "type": "object",
5168
+ "description": "Returned by POST and PUT secret routes.",
5169
+ "properties": {
5170
+ "key": {
5171
+ "type": "string"
5172
+ },
5173
+ "created_at": {
5174
+ "type": "string",
5175
+ "format": "date-time"
5176
+ },
5177
+ "updated_at": {
5178
+ "type": "string",
5179
+ "format": "date-time"
5180
+ },
5181
+ "created": {
5182
+ "type": "boolean",
5183
+ "description": "True if this call inserted a new row, false if it updated an existing one."
5184
+ }
5185
+ },
5186
+ "required": [
5187
+ "key",
5188
+ "created_at",
5189
+ "updated_at",
5190
+ "created"
5191
+ ]
4321
5192
  }
4322
5193
  }
4323
5194
  }