@primitivedotdev/cli 1.3.0 → 1.5.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.
- package/dist/oclif/index.js +865 -11
- package/package.json +7 -1
package/dist/oclif/index.js
CHANGED
|
@@ -3,9 +3,9 @@ import { Args, Command, Errors, Flags, ux } from "@oclif/core";
|
|
|
3
3
|
import { chmodSync, closeSync, 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
|
-
import { hostname } from "node:os";
|
|
7
6
|
import process$1 from "node:process";
|
|
8
7
|
import { createInterface } from "node:readline/promises";
|
|
8
|
+
import { hostname } from "node:os";
|
|
9
9
|
import { spawn } from "node:child_process";
|
|
10
10
|
//#region \0rolldown/runtime.js
|
|
11
11
|
var __defProp = Object.defineProperty;
|
|
@@ -32,12 +32,14 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
|
|
|
32
32
|
createFilter: () => createFilter,
|
|
33
33
|
createFunction: () => createFunction,
|
|
34
34
|
createFunctionSecret: () => createFunctionSecret,
|
|
35
|
+
createOrgSecret: () => createOrgSecret,
|
|
35
36
|
deleteDomain: () => deleteDomain,
|
|
36
37
|
deleteEmail: () => deleteEmail,
|
|
37
38
|
deleteEndpoint: () => deleteEndpoint,
|
|
38
39
|
deleteFilter: () => deleteFilter,
|
|
39
40
|
deleteFunction: () => deleteFunction,
|
|
40
41
|
deleteFunctionSecret: () => deleteFunctionSecret,
|
|
42
|
+
deleteOrgSecret: () => deleteOrgSecret,
|
|
41
43
|
discardEmailContent: () => discardEmailContent,
|
|
42
44
|
downloadAttachments: () => downloadAttachments,
|
|
43
45
|
downloadDomainZoneFile: () => downloadDomainZoneFile,
|
|
@@ -63,6 +65,7 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
|
|
|
63
65
|
listFunctionLogs: () => listFunctionLogs,
|
|
64
66
|
listFunctionSecrets: () => listFunctionSecrets,
|
|
65
67
|
listFunctions: () => listFunctions,
|
|
68
|
+
listOrgSecrets: () => listOrgSecrets,
|
|
66
69
|
listSentEmails: () => listSentEmails,
|
|
67
70
|
pollCliLogin: () => pollCliLogin,
|
|
68
71
|
replayDelivery: () => replayDelivery,
|
|
@@ -76,6 +79,7 @@ var sdk_gen_exports = /* @__PURE__ */ __exportAll({
|
|
|
76
79
|
sendEmail: () => sendEmail,
|
|
77
80
|
setFunctionRoute: () => setFunctionRoute,
|
|
78
81
|
setFunctionSecret: () => setFunctionSecret,
|
|
82
|
+
setOrgSecret: () => setOrgSecret,
|
|
79
83
|
startAgentClaim: () => startAgentClaim,
|
|
80
84
|
startAgentSignup: () => startAgentSignup,
|
|
81
85
|
startCliLogin: () => startCliLogin,
|
|
@@ -1194,10 +1198,12 @@ const listFunctions = (options) => (options?.client ?? client).get({
|
|
|
1194
1198
|
* each delivery and forwards the `Primitive-Signature` header to
|
|
1195
1199
|
* the handler. Verify the raw request body with
|
|
1196
1200
|
* `PRIMITIVE_WEBHOOK_SECRET` before parsing JSON; after verification
|
|
1197
|
-
* the request body parses to
|
|
1198
|
-
* `
|
|
1199
|
-
*
|
|
1200
|
-
*
|
|
1201
|
+
* the request body parses to a webhook event whose `event` field is
|
|
1202
|
+
* `email.received` for normal inbound mail, or a machine-mail type
|
|
1203
|
+
* (`email.bounced`, `email.tls_report`, `email.dmarc_report`,
|
|
1204
|
+
* `email.dmarc_failure`) for bounces and reports. Code is bundled
|
|
1205
|
+
* before being uploaded; ship a single self-contained file rather
|
|
1206
|
+
* than relying on external imports.
|
|
1201
1207
|
*
|
|
1202
1208
|
* **Code limits.** `code` is capped at 1 MiB UTF-8. `sourceMap`
|
|
1203
1209
|
* (optional) is capped at 5 MiB UTF-8, stored with each deployment
|
|
@@ -1515,6 +1521,85 @@ const setFunctionSecret = (options) => (options.client ?? client).put({
|
|
|
1515
1521
|
}
|
|
1516
1522
|
});
|
|
1517
1523
|
/**
|
|
1524
|
+
* List org-level (global) secrets
|
|
1525
|
+
*
|
|
1526
|
+
* Returns metadata for every org-level secret. Org secrets apply
|
|
1527
|
+
* to every function in the org and are read as `env.<KEY>` in
|
|
1528
|
+
* handlers. **Values are never returned.** Secret writes are
|
|
1529
|
+
* write-only. A function-level secret of the same name overrides
|
|
1530
|
+
* the org-level value for that function.
|
|
1531
|
+
*
|
|
1532
|
+
*/
|
|
1533
|
+
const listOrgSecrets = (options) => (options?.client ?? client).get({
|
|
1534
|
+
security: [{
|
|
1535
|
+
scheme: "bearer",
|
|
1536
|
+
type: "http"
|
|
1537
|
+
}],
|
|
1538
|
+
url: "/org/secrets",
|
|
1539
|
+
...options
|
|
1540
|
+
});
|
|
1541
|
+
/**
|
|
1542
|
+
* Create or update an org secret
|
|
1543
|
+
*
|
|
1544
|
+
* Idempotent insert-or-update keyed on `(org_id, key)`. Returns
|
|
1545
|
+
* 201 the first time the key is set, 200 on subsequent updates.
|
|
1546
|
+
* Values are encrypted at rest. A changed value lands in a
|
|
1547
|
+
* function only on that function's next deploy.
|
|
1548
|
+
*
|
|
1549
|
+
* Keys must match `^[A-Z_][A-Z0-9_]*$` (uppercase letters,
|
|
1550
|
+
* digits, underscores; first character is a letter or
|
|
1551
|
+
* underscore). Values are at most 4096 UTF-8 bytes. System-
|
|
1552
|
+
* managed keys are reserved and rejected.
|
|
1553
|
+
*
|
|
1554
|
+
*/
|
|
1555
|
+
const createOrgSecret = (options) => (options.client ?? client).post({
|
|
1556
|
+
security: [{
|
|
1557
|
+
scheme: "bearer",
|
|
1558
|
+
type: "http"
|
|
1559
|
+
}],
|
|
1560
|
+
url: "/org/secrets",
|
|
1561
|
+
...options,
|
|
1562
|
+
headers: {
|
|
1563
|
+
...options.body !== void 0 && { "Content-Type": "application/json" },
|
|
1564
|
+
...options.headers
|
|
1565
|
+
}
|
|
1566
|
+
});
|
|
1567
|
+
/**
|
|
1568
|
+
* Delete an org secret
|
|
1569
|
+
*
|
|
1570
|
+
* Removes the org secret. Functions keep the previous value until
|
|
1571
|
+
* each is redeployed. Returns 404 if the key did not exist.
|
|
1572
|
+
*
|
|
1573
|
+
*/
|
|
1574
|
+
const deleteOrgSecret = (options) => (options.client ?? client).delete({
|
|
1575
|
+
security: [{
|
|
1576
|
+
scheme: "bearer",
|
|
1577
|
+
type: "http"
|
|
1578
|
+
}],
|
|
1579
|
+
url: "/org/secrets/{key}",
|
|
1580
|
+
...options
|
|
1581
|
+
});
|
|
1582
|
+
/**
|
|
1583
|
+
* Set an org secret by key
|
|
1584
|
+
*
|
|
1585
|
+
* Path-keyed companion to `POST /org/secrets`. Idempotent:
|
|
1586
|
+
* returns 201 the first time the key is set, 200 on subsequent
|
|
1587
|
+
* updates. Same validation and write-only guarantees as POST.
|
|
1588
|
+
*
|
|
1589
|
+
*/
|
|
1590
|
+
const setOrgSecret = (options) => (options.client ?? client).put({
|
|
1591
|
+
security: [{
|
|
1592
|
+
scheme: "bearer",
|
|
1593
|
+
type: "http"
|
|
1594
|
+
}],
|
|
1595
|
+
url: "/org/secrets/{key}",
|
|
1596
|
+
...options,
|
|
1597
|
+
headers: {
|
|
1598
|
+
...options.body !== void 0 && { "Content-Type": "application/json" },
|
|
1599
|
+
...options.headers
|
|
1600
|
+
}
|
|
1601
|
+
});
|
|
1602
|
+
/**
|
|
1518
1603
|
* List a function's execution logs
|
|
1519
1604
|
*
|
|
1520
1605
|
* Returns the most recent `function_logs` rows for the function,
|
|
@@ -1618,7 +1703,7 @@ const openapiDocument = {
|
|
|
1618
1703
|
},
|
|
1619
1704
|
{
|
|
1620
1705
|
"name": "Functions",
|
|
1621
|
-
"description": "Deploy JavaScript handlers that run on inbound mail. Each function\nis a single ESM module whose default export is an object with an\nasync `fetch(request, env)` method, in the shape of a Workers-style\nhandler. Primitive signs each delivery and forwards the\n`Primitive-Signature` header to the handler; verify the raw request\nbody with `PRIMITIVE_WEBHOOK_SECRET` before trusting the parsed
|
|
1706
|
+
"description": "Deploy JavaScript handlers that run on inbound mail. Each function\nis a single ESM module whose default export is an object with an\nasync `fetch(request, env)` method, in the shape of a Workers-style\nhandler. Primitive signs each delivery and forwards the\n`Primitive-Signature` header to the handler; verify the raw request\nbody with `PRIMITIVE_WEBHOOK_SECRET` before trusting the parsed event.\nThe `event` field is `email.received` for normal inbound mail, or a\nmachine-mail type (`email.bounced`, `email.tls_report`,\n`email.dmarc_report`, `email.dmarc_failure`) for bounces and reports;\nthe payload shape is otherwise identical. Code runs on\nPrimitive's edge runtime; there is no infrastructure to manage.\nSecrets land in `env` as encrypted bindings and are refreshed on\nevery redeploy.\n"
|
|
1622
1707
|
}
|
|
1623
1708
|
],
|
|
1624
1709
|
"paths": {
|
|
@@ -2390,6 +2475,25 @@ const openapiDocument = {
|
|
|
2390
2475
|
"format": "date-time"
|
|
2391
2476
|
},
|
|
2392
2477
|
"description": "Filter emails created on or before this timestamp"
|
|
2478
|
+
},
|
|
2479
|
+
{
|
|
2480
|
+
"name": "since",
|
|
2481
|
+
"in": "query",
|
|
2482
|
+
"schema": {
|
|
2483
|
+
"type": "string",
|
|
2484
|
+
"maxLength": 200
|
|
2485
|
+
},
|
|
2486
|
+
"description": "Forward-tail cursor. Returns rows that became visible AFTER this\ncursor, oldest-first, so a caller can stream new inbound mail by\nre-passing the cursor from each response. Mutually exclusive with\n`cursor` (which pages history newest-first). Pass the `meta.cursor`\nfrom the previous `since` response; an empty page means caught up.\n"
|
|
2487
|
+
},
|
|
2488
|
+
{
|
|
2489
|
+
"name": "wait",
|
|
2490
|
+
"in": "query",
|
|
2491
|
+
"schema": {
|
|
2492
|
+
"type": "integer",
|
|
2493
|
+
"minimum": 0,
|
|
2494
|
+
"maximum": 30
|
|
2495
|
+
},
|
|
2496
|
+
"description": "Long-poll: hold the request up to this many seconds waiting for new\nmail past `since`, returning as soon as any arrives (or an empty\npage when the wait elapses). Requires `since`. Omitted means no wait\n(returns immediately); the server treats an absent value as 0. NOT\ngiven an OpenAPI `default` on purpose: a default makes some\ngenerators (e.g. openapi-python-client) send `wait=0` on every call,\nwhich then fails the `wait` requires `since` check for plain history\nlistings.\n"
|
|
2393
2497
|
}
|
|
2394
2498
|
],
|
|
2395
2499
|
"responses": {
|
|
@@ -3329,7 +3433,7 @@ const openapiDocument = {
|
|
|
3329
3433
|
"post": {
|
|
3330
3434
|
"operationId": "createFunction",
|
|
3331
3435
|
"summary": "Deploy a function",
|
|
3332
|
-
"description": "Creates and deploys a new function. The handler must be a single\nESM module whose default export is an object with an async\n`fetch(request, env)` method (Workers-style). Primitive signs\neach delivery and forwards the `Primitive-Signature` header to\nthe handler. Verify the raw request body with\n`PRIMITIVE_WEBHOOK_SECRET` before parsing JSON; after verification\nthe request body parses to
|
|
3436
|
+
"description": "Creates and deploys a new function. The handler must be a single\nESM module whose default export is an object with an async\n`fetch(request, env)` method (Workers-style). Primitive signs\neach delivery and forwards the `Primitive-Signature` header to\nthe handler. Verify the raw request body with\n`PRIMITIVE_WEBHOOK_SECRET` before parsing JSON; after verification\nthe request body parses to a webhook event whose `event` field is\n`email.received` for normal inbound mail, or a machine-mail type\n(`email.bounced`, `email.tls_report`, `email.dmarc_report`,\n`email.dmarc_failure`) for bounces and reports. Code is bundled\nbefore being uploaded; ship a single self-contained file rather\nthan relying on external imports.\n\n**Code limits.** `code` is capped at 1 MiB UTF-8. `sourceMap`\n(optional) is capped at 5 MiB UTF-8, stored with each deployment\nattempt, and sent to the runtime so stack traces can resolve to\noriginal source files.\n\n**Routing.** On successful deploy, the function code is live\nin the runtime, but inbound mail will not reach it until at\nleast one route is bound. Routes are managed from the Primitive\ndashboard. A `deploy_status` of `deployed` means the script is\ninstalled, not that the function is receiving mail. The\ninternal runtime URL is not returned by the API and is not a\ncustomer-facing integration surface.\n\n**Secrets.** New functions ship with the managed secrets\n(`PRIMITIVE_WEBHOOK_SECRET`, `PRIMITIVE_API_KEY`,\n`PRIMITIVE_API_BASE_URL`) already bound. Add user-set secrets via\n`POST /functions/{id}/secrets`; secret writes only land in the\nrunning handler on the next redeploy.\n",
|
|
3333
3437
|
"tags": ["Functions"],
|
|
3334
3438
|
"requestBody": {
|
|
3335
3439
|
"required": true,
|
|
@@ -3688,6 +3792,111 @@ const openapiDocument = {
|
|
|
3688
3792
|
}
|
|
3689
3793
|
}
|
|
3690
3794
|
},
|
|
3795
|
+
"/org/secrets": {
|
|
3796
|
+
"get": {
|
|
3797
|
+
"operationId": "listOrgSecrets",
|
|
3798
|
+
"summary": "List org-level (global) secrets",
|
|
3799
|
+
"description": "Returns metadata for every org-level secret. Org secrets apply\nto every function in the org and are read as `env.<KEY>` in\nhandlers. **Values are never returned.** Secret writes are\nwrite-only. A function-level secret of the same name overrides\nthe org-level value for that function.\n",
|
|
3800
|
+
"tags": ["Functions"],
|
|
3801
|
+
"responses": {
|
|
3802
|
+
"200": {
|
|
3803
|
+
"description": "List of org secrets (metadata only, no values)",
|
|
3804
|
+
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
3805
|
+
"type": "object",
|
|
3806
|
+
"properties": { "data": {
|
|
3807
|
+
"type": "object",
|
|
3808
|
+
"properties": { "items": {
|
|
3809
|
+
"type": "array",
|
|
3810
|
+
"items": { "$ref": "#/components/schemas/OrgSecretListItem" }
|
|
3811
|
+
} },
|
|
3812
|
+
"required": ["items"]
|
|
3813
|
+
} }
|
|
3814
|
+
}] } } }
|
|
3815
|
+
},
|
|
3816
|
+
"401": { "$ref": "#/components/responses/Unauthorized" }
|
|
3817
|
+
}
|
|
3818
|
+
},
|
|
3819
|
+
"post": {
|
|
3820
|
+
"operationId": "createOrgSecret",
|
|
3821
|
+
"summary": "Create or update an org secret",
|
|
3822
|
+
"description": "Idempotent insert-or-update keyed on `(org_id, key)`. Returns\n201 the first time the key is set, 200 on subsequent updates.\nValues are encrypted at rest. A changed value lands in a\nfunction only on that function's next deploy.\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",
|
|
3823
|
+
"tags": ["Functions"],
|
|
3824
|
+
"requestBody": {
|
|
3825
|
+
"required": true,
|
|
3826
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateOrgSecretInput" } } }
|
|
3827
|
+
},
|
|
3828
|
+
"responses": {
|
|
3829
|
+
"200": {
|
|
3830
|
+
"description": "Secret updated",
|
|
3831
|
+
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
3832
|
+
"type": "object",
|
|
3833
|
+
"properties": { "data": { "$ref": "#/components/schemas/OrgSecretWriteResult" } }
|
|
3834
|
+
}] } } }
|
|
3835
|
+
},
|
|
3836
|
+
"201": {
|
|
3837
|
+
"description": "Secret created",
|
|
3838
|
+
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
3839
|
+
"type": "object",
|
|
3840
|
+
"properties": { "data": { "$ref": "#/components/schemas/OrgSecretWriteResult" } }
|
|
3841
|
+
}] } } }
|
|
3842
|
+
},
|
|
3843
|
+
"400": { "$ref": "#/components/responses/ValidationError" },
|
|
3844
|
+
"401": { "$ref": "#/components/responses/Unauthorized" }
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3847
|
+
},
|
|
3848
|
+
"/org/secrets/{key}": {
|
|
3849
|
+
"parameters": [{
|
|
3850
|
+
"name": "key",
|
|
3851
|
+
"in": "path",
|
|
3852
|
+
"required": true,
|
|
3853
|
+
"description": "Secret key. Must match `^[A-Z_][A-Z0-9_]*$`.",
|
|
3854
|
+
"schema": {
|
|
3855
|
+
"type": "string",
|
|
3856
|
+
"pattern": "^[A-Z_][A-Z0-9_]*$"
|
|
3857
|
+
}
|
|
3858
|
+
}],
|
|
3859
|
+
"put": {
|
|
3860
|
+
"operationId": "setOrgSecret",
|
|
3861
|
+
"summary": "Set an org secret by key",
|
|
3862
|
+
"description": "Path-keyed companion to `POST /org/secrets`. Idempotent:\nreturns 201 the first time the key is set, 200 on subsequent\nupdates. Same validation and write-only guarantees as POST.\n",
|
|
3863
|
+
"tags": ["Functions"],
|
|
3864
|
+
"requestBody": {
|
|
3865
|
+
"required": true,
|
|
3866
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetOrgSecretInput" } } }
|
|
3867
|
+
},
|
|
3868
|
+
"responses": {
|
|
3869
|
+
"200": {
|
|
3870
|
+
"description": "Secret updated",
|
|
3871
|
+
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
3872
|
+
"type": "object",
|
|
3873
|
+
"properties": { "data": { "$ref": "#/components/schemas/OrgSecretWriteResult" } }
|
|
3874
|
+
}] } } }
|
|
3875
|
+
},
|
|
3876
|
+
"201": {
|
|
3877
|
+
"description": "Secret created",
|
|
3878
|
+
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
3879
|
+
"type": "object",
|
|
3880
|
+
"properties": { "data": { "$ref": "#/components/schemas/OrgSecretWriteResult" } }
|
|
3881
|
+
}] } } }
|
|
3882
|
+
},
|
|
3883
|
+
"400": { "$ref": "#/components/responses/ValidationError" },
|
|
3884
|
+
"401": { "$ref": "#/components/responses/Unauthorized" }
|
|
3885
|
+
}
|
|
3886
|
+
},
|
|
3887
|
+
"delete": {
|
|
3888
|
+
"operationId": "deleteOrgSecret",
|
|
3889
|
+
"summary": "Delete an org secret",
|
|
3890
|
+
"description": "Removes the org secret. Functions keep the previous value until\neach is redeployed. Returns 404 if the key did not exist.\n",
|
|
3891
|
+
"tags": ["Functions"],
|
|
3892
|
+
"responses": {
|
|
3893
|
+
"204": { "description": "Secret deleted" },
|
|
3894
|
+
"400": { "$ref": "#/components/responses/ValidationError" },
|
|
3895
|
+
"401": { "$ref": "#/components/responses/Unauthorized" },
|
|
3896
|
+
"404": { "$ref": "#/components/responses/NotFound" }
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
},
|
|
3691
3900
|
"/functions/{id}/logs": {
|
|
3692
3901
|
"parameters": [{ "$ref": "#/components/parameters/ResourceId" }],
|
|
3693
3902
|
"get": {
|
|
@@ -4849,6 +5058,16 @@ const openapiDocument = {
|
|
|
4849
5058
|
},
|
|
4850
5059
|
"email": { "type": "string" },
|
|
4851
5060
|
"plan": { "type": "string" },
|
|
5061
|
+
"limits": { "$ref": "#/components/schemas/PlanLimits" },
|
|
5062
|
+
"entitlements": {
|
|
5063
|
+
"type": "array",
|
|
5064
|
+
"items": { "type": "string" },
|
|
5065
|
+
"description": "Granted org entitlement keys (sorted). A headless caller reads its\ncapabilities here — e.g. an emailless agent seeing only\n[\"send_mail\", \"send_to_known_addresses\"] knows it is reply-only.\n"
|
|
5066
|
+
},
|
|
5067
|
+
"managed_inbox_address": {
|
|
5068
|
+
"type": ["string", "null"],
|
|
5069
|
+
"description": "The managed inbox FQDN to reply as, or null if the org has no managed inbox."
|
|
5070
|
+
},
|
|
4852
5071
|
"created_at": {
|
|
4853
5072
|
"type": "string",
|
|
4854
5073
|
"format": "date-time"
|
|
@@ -4876,6 +5095,9 @@ const openapiDocument = {
|
|
|
4876
5095
|
"id",
|
|
4877
5096
|
"email",
|
|
4878
5097
|
"plan",
|
|
5098
|
+
"limits",
|
|
5099
|
+
"entitlements",
|
|
5100
|
+
"managed_inbox_address",
|
|
4879
5101
|
"created_at",
|
|
4880
5102
|
"discard_content_on_webhook_confirmed"
|
|
4881
5103
|
]
|
|
@@ -7886,6 +8108,81 @@ const openapiDocument = {
|
|
|
7886
8108
|
"updated_at",
|
|
7887
8109
|
"created"
|
|
7888
8110
|
]
|
|
8111
|
+
},
|
|
8112
|
+
"OrgSecretListItem": {
|
|
8113
|
+
"type": "object",
|
|
8114
|
+
"description": "One row from GET /org/secrets. Org secrets are always user-set\n(there are no managed org secrets), so `created_at` /\n`updated_at` are always present.\n",
|
|
8115
|
+
"properties": {
|
|
8116
|
+
"key": { "type": "string" },
|
|
8117
|
+
"created_at": {
|
|
8118
|
+
"type": "string",
|
|
8119
|
+
"format": "date-time"
|
|
8120
|
+
},
|
|
8121
|
+
"updated_at": {
|
|
8122
|
+
"type": "string",
|
|
8123
|
+
"format": "date-time"
|
|
8124
|
+
}
|
|
8125
|
+
},
|
|
8126
|
+
"required": [
|
|
8127
|
+
"key",
|
|
8128
|
+
"created_at",
|
|
8129
|
+
"updated_at"
|
|
8130
|
+
]
|
|
8131
|
+
},
|
|
8132
|
+
"CreateOrgSecretInput": {
|
|
8133
|
+
"type": "object",
|
|
8134
|
+
"additionalProperties": false,
|
|
8135
|
+
"description": "Body for POST /org/secrets.",
|
|
8136
|
+
"properties": {
|
|
8137
|
+
"key": {
|
|
8138
|
+
"type": "string",
|
|
8139
|
+
"pattern": "^[A-Z_][A-Z0-9_]*$",
|
|
8140
|
+
"description": "Uppercase letters, digits, and underscores. Must start with\na letter or underscore. System-managed keys are reserved.\n"
|
|
8141
|
+
},
|
|
8142
|
+
"value": {
|
|
8143
|
+
"type": "string",
|
|
8144
|
+
"minLength": 1,
|
|
8145
|
+
"maxLength": 4096,
|
|
8146
|
+
"description": "Secret value, up to 4096 UTF-8 bytes. Encrypted at rest.\nNever returned by any read endpoint.\n"
|
|
8147
|
+
}
|
|
8148
|
+
},
|
|
8149
|
+
"required": ["key", "value"]
|
|
8150
|
+
},
|
|
8151
|
+
"SetOrgSecretInput": {
|
|
8152
|
+
"type": "object",
|
|
8153
|
+
"additionalProperties": false,
|
|
8154
|
+
"description": "Body for PUT /org/secrets/{key}. Key comes from the path.",
|
|
8155
|
+
"properties": { "value": {
|
|
8156
|
+
"type": "string",
|
|
8157
|
+
"minLength": 1,
|
|
8158
|
+
"maxLength": 4096
|
|
8159
|
+
} },
|
|
8160
|
+
"required": ["value"]
|
|
8161
|
+
},
|
|
8162
|
+
"OrgSecretWriteResult": {
|
|
8163
|
+
"type": "object",
|
|
8164
|
+
"description": "Returned by POST and PUT org secret routes.",
|
|
8165
|
+
"properties": {
|
|
8166
|
+
"key": { "type": "string" },
|
|
8167
|
+
"created_at": {
|
|
8168
|
+
"type": "string",
|
|
8169
|
+
"format": "date-time"
|
|
8170
|
+
},
|
|
8171
|
+
"updated_at": {
|
|
8172
|
+
"type": "string",
|
|
8173
|
+
"format": "date-time"
|
|
8174
|
+
},
|
|
8175
|
+
"created": {
|
|
8176
|
+
"type": "boolean",
|
|
8177
|
+
"description": "True if this call inserted a new row, false if it updated an existing one."
|
|
8178
|
+
}
|
|
8179
|
+
},
|
|
8180
|
+
"required": [
|
|
8181
|
+
"key",
|
|
8182
|
+
"created_at",
|
|
8183
|
+
"updated_at",
|
|
8184
|
+
"created"
|
|
8185
|
+
]
|
|
7889
8186
|
}
|
|
7890
8187
|
}
|
|
7891
8188
|
}
|
|
@@ -7914,6 +8211,39 @@ const operationManifest = [
|
|
|
7914
8211
|
},
|
|
7915
8212
|
"email": { "type": "string" },
|
|
7916
8213
|
"plan": { "type": "string" },
|
|
8214
|
+
"limits": {
|
|
8215
|
+
"type": "object",
|
|
8216
|
+
"description": "Plan-derived quota limits for an account.",
|
|
8217
|
+
"properties": {
|
|
8218
|
+
"storage_mb": { "type": "number" },
|
|
8219
|
+
"send_per_hour": { "type": "number" },
|
|
8220
|
+
"send_per_day": { "type": "number" },
|
|
8221
|
+
"api_per_minute": { "type": "number" },
|
|
8222
|
+
"webhooks_max_global": { "type": ["number", "null"] },
|
|
8223
|
+
"webhooks_per_domain": { "type": "boolean" },
|
|
8224
|
+
"filters_per_domain": { "type": "boolean" },
|
|
8225
|
+
"spam_thresholds_per_domain": { "type": "boolean" }
|
|
8226
|
+
},
|
|
8227
|
+
"required": [
|
|
8228
|
+
"storage_mb",
|
|
8229
|
+
"send_per_hour",
|
|
8230
|
+
"send_per_day",
|
|
8231
|
+
"api_per_minute",
|
|
8232
|
+
"webhooks_max_global",
|
|
8233
|
+
"webhooks_per_domain",
|
|
8234
|
+
"filters_per_domain",
|
|
8235
|
+
"spam_thresholds_per_domain"
|
|
8236
|
+
]
|
|
8237
|
+
},
|
|
8238
|
+
"entitlements": {
|
|
8239
|
+
"type": "array",
|
|
8240
|
+
"items": { "type": "string" },
|
|
8241
|
+
"description": "Granted org entitlement keys (sorted). A headless caller reads its\ncapabilities here — e.g. an emailless agent seeing only\n[\"send_mail\", \"send_to_known_addresses\"] knows it is reply-only.\n"
|
|
8242
|
+
},
|
|
8243
|
+
"managed_inbox_address": {
|
|
8244
|
+
"type": ["string", "null"],
|
|
8245
|
+
"description": "The managed inbox FQDN to reply as, or null if the org has no managed inbox."
|
|
8246
|
+
},
|
|
7917
8247
|
"created_at": {
|
|
7918
8248
|
"type": "string",
|
|
7919
8249
|
"format": "date-time"
|
|
@@ -7941,6 +8271,9 @@ const operationManifest = [
|
|
|
7941
8271
|
"id",
|
|
7942
8272
|
"email",
|
|
7943
8273
|
"plan",
|
|
8274
|
+
"limits",
|
|
8275
|
+
"entitlements",
|
|
8276
|
+
"managed_inbox_address",
|
|
7944
8277
|
"created_at",
|
|
7945
8278
|
"discard_content_on_webhook_confirmed"
|
|
7946
8279
|
]
|
|
@@ -10397,7 +10730,23 @@ const operationManifest = [
|
|
|
10397
10730
|
"name": "date_to",
|
|
10398
10731
|
"required": false,
|
|
10399
10732
|
"type": "string"
|
|
10400
|
-
}
|
|
10733
|
+
},
|
|
10734
|
+
{
|
|
10735
|
+
"description": "Forward-tail cursor. Returns rows that became visible AFTER this\ncursor, oldest-first, so a caller can stream new inbound mail by\nre-passing the cursor from each response. Mutually exclusive with\n`cursor` (which pages history newest-first). Pass the `meta.cursor`\nfrom the previous `since` response; an empty page means caught up.\n",
|
|
10736
|
+
"enum": null,
|
|
10737
|
+
"name": "since",
|
|
10738
|
+
"required": false,
|
|
10739
|
+
"type": "string"
|
|
10740
|
+
},
|
|
10741
|
+
{
|
|
10742
|
+
"description": "Long-poll: hold the request up to this many seconds waiting for new\nmail past `since`, returning as soon as any arrives (or an empty\npage when the wait elapses). Requires `since`. Omitted means no wait\n(returns immediately); the server treats an absent value as 0. NOT\ngiven an OpenAPI `default` on purpose: a default makes some\ngenerators (e.g. openapi-python-client) send `wait=0` on every call,\nwhich then fails the `wait` requires `since` check for plain history\nlistings.\n",
|
|
10743
|
+
"enum": null,
|
|
10744
|
+
"maximum": 30,
|
|
10745
|
+
"minimum": 0,
|
|
10746
|
+
"name": "wait",
|
|
10747
|
+
"required": false,
|
|
10748
|
+
"type": "integer"
|
|
10749
|
+
}
|
|
10401
10750
|
],
|
|
10402
10751
|
"requestSchema": null,
|
|
10403
10752
|
"responseSchema": {
|
|
@@ -11406,7 +11755,7 @@ const operationManifest = [
|
|
|
11406
11755
|
"binaryResponse": false,
|
|
11407
11756
|
"bodyRequired": true,
|
|
11408
11757
|
"command": "create-function",
|
|
11409
|
-
"description": "Creates and deploys a new function. The handler must be a single\nESM module whose default export is an object with an async\n`fetch(request, env)` method (Workers-style). Primitive signs\neach delivery and forwards the `Primitive-Signature` header to\nthe handler. Verify the raw request body with\n`PRIMITIVE_WEBHOOK_SECRET` before parsing JSON; after verification\nthe request body parses to
|
|
11758
|
+
"description": "Creates and deploys a new function. The handler must be a single\nESM module whose default export is an object with an async\n`fetch(request, env)` method (Workers-style). Primitive signs\neach delivery and forwards the `Primitive-Signature` header to\nthe handler. Verify the raw request body with\n`PRIMITIVE_WEBHOOK_SECRET` before parsing JSON; after verification\nthe request body parses to a webhook event whose `event` field is\n`email.received` for normal inbound mail, or a machine-mail type\n(`email.bounced`, `email.tls_report`, `email.dmarc_report`,\n`email.dmarc_failure`) for bounces and reports. Code is bundled\nbefore being uploaded; ship a single self-contained file rather\nthan relying on external imports.\n\n**Code limits.** `code` is capped at 1 MiB UTF-8. `sourceMap`\n(optional) is capped at 5 MiB UTF-8, stored with each deployment\nattempt, and sent to the runtime so stack traces can resolve to\noriginal source files.\n\n**Routing.** On successful deploy, the function code is live\nin the runtime, but inbound mail will not reach it until at\nleast one route is bound. Routes are managed from the Primitive\ndashboard. A `deploy_status` of `deployed` means the script is\ninstalled, not that the function is receiving mail. The\ninternal runtime URL is not returned by the API and is not a\ncustomer-facing integration surface.\n\n**Secrets.** New functions ship with the managed secrets\n(`PRIMITIVE_WEBHOOK_SECRET`, `PRIMITIVE_API_KEY`,\n`PRIMITIVE_API_BASE_URL`) already bound. Add user-set secrets via\n`POST /functions/{id}/secrets`; secret writes only land in the\nrunning handler on the next redeploy.\n",
|
|
11410
11759
|
"hasJsonBody": true,
|
|
11411
11760
|
"method": "POST",
|
|
11412
11761
|
"operationId": "createFunction",
|
|
@@ -11538,6 +11887,66 @@ const operationManifest = [
|
|
|
11538
11887
|
"tag": "Functions",
|
|
11539
11888
|
"tagCommand": "functions"
|
|
11540
11889
|
},
|
|
11890
|
+
{
|
|
11891
|
+
"binaryResponse": false,
|
|
11892
|
+
"bodyRequired": true,
|
|
11893
|
+
"command": "create-org-secret",
|
|
11894
|
+
"description": "Idempotent insert-or-update keyed on `(org_id, key)`. Returns\n201 the first time the key is set, 200 on subsequent updates.\nValues are encrypted at rest. A changed value lands in a\nfunction only on that function's next deploy.\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",
|
|
11895
|
+
"hasJsonBody": true,
|
|
11896
|
+
"method": "POST",
|
|
11897
|
+
"operationId": "createOrgSecret",
|
|
11898
|
+
"path": "/org/secrets",
|
|
11899
|
+
"pathParams": [],
|
|
11900
|
+
"queryParams": [],
|
|
11901
|
+
"requestSchema": {
|
|
11902
|
+
"type": "object",
|
|
11903
|
+
"additionalProperties": false,
|
|
11904
|
+
"description": "Body for POST /org/secrets.",
|
|
11905
|
+
"properties": {
|
|
11906
|
+
"key": {
|
|
11907
|
+
"type": "string",
|
|
11908
|
+
"pattern": "^[A-Z_][A-Z0-9_]*$",
|
|
11909
|
+
"description": "Uppercase letters, digits, and underscores. Must start with\na letter or underscore. System-managed keys are reserved.\n"
|
|
11910
|
+
},
|
|
11911
|
+
"value": {
|
|
11912
|
+
"type": "string",
|
|
11913
|
+
"minLength": 1,
|
|
11914
|
+
"maxLength": 4096,
|
|
11915
|
+
"description": "Secret value, up to 4096 UTF-8 bytes. Encrypted at rest.\nNever returned by any read endpoint.\n"
|
|
11916
|
+
}
|
|
11917
|
+
},
|
|
11918
|
+
"required": ["key", "value"]
|
|
11919
|
+
},
|
|
11920
|
+
"responseSchema": {
|
|
11921
|
+
"type": "object",
|
|
11922
|
+
"description": "Returned by POST and PUT org secret routes.",
|
|
11923
|
+
"properties": {
|
|
11924
|
+
"key": { "type": "string" },
|
|
11925
|
+
"created_at": {
|
|
11926
|
+
"type": "string",
|
|
11927
|
+
"format": "date-time"
|
|
11928
|
+
},
|
|
11929
|
+
"updated_at": {
|
|
11930
|
+
"type": "string",
|
|
11931
|
+
"format": "date-time"
|
|
11932
|
+
},
|
|
11933
|
+
"created": {
|
|
11934
|
+
"type": "boolean",
|
|
11935
|
+
"description": "True if this call inserted a new row, false if it updated an existing one."
|
|
11936
|
+
}
|
|
11937
|
+
},
|
|
11938
|
+
"required": [
|
|
11939
|
+
"key",
|
|
11940
|
+
"created_at",
|
|
11941
|
+
"updated_at",
|
|
11942
|
+
"created"
|
|
11943
|
+
]
|
|
11944
|
+
},
|
|
11945
|
+
"sdkName": "createOrgSecret",
|
|
11946
|
+
"summary": "Create or update an org secret",
|
|
11947
|
+
"tag": "Functions",
|
|
11948
|
+
"tagCommand": "functions"
|
|
11949
|
+
},
|
|
11541
11950
|
{
|
|
11542
11951
|
"binaryResponse": false,
|
|
11543
11952
|
"bodyRequired": false,
|
|
@@ -11592,6 +12001,30 @@ const operationManifest = [
|
|
|
11592
12001
|
"tag": "Functions",
|
|
11593
12002
|
"tagCommand": "functions"
|
|
11594
12003
|
},
|
|
12004
|
+
{
|
|
12005
|
+
"binaryResponse": false,
|
|
12006
|
+
"bodyRequired": false,
|
|
12007
|
+
"command": "delete-org-secret",
|
|
12008
|
+
"description": "Removes the org secret. Functions keep the previous value until\neach is redeployed. Returns 404 if the key did not exist.\n",
|
|
12009
|
+
"hasJsonBody": false,
|
|
12010
|
+
"method": "DELETE",
|
|
12011
|
+
"operationId": "deleteOrgSecret",
|
|
12012
|
+
"path": "/org/secrets/{key}",
|
|
12013
|
+
"pathParams": [{
|
|
12014
|
+
"description": "Secret key. Must match `^[A-Z_][A-Z0-9_]*$`.",
|
|
12015
|
+
"enum": null,
|
|
12016
|
+
"name": "key",
|
|
12017
|
+
"required": true,
|
|
12018
|
+
"type": "string"
|
|
12019
|
+
}],
|
|
12020
|
+
"queryParams": [],
|
|
12021
|
+
"requestSchema": null,
|
|
12022
|
+
"responseSchema": null,
|
|
12023
|
+
"sdkName": "deleteOrgSecret",
|
|
12024
|
+
"summary": "Delete an org secret",
|
|
12025
|
+
"tag": "Functions",
|
|
12026
|
+
"tagCommand": "functions"
|
|
12027
|
+
},
|
|
11595
12028
|
{
|
|
11596
12029
|
"binaryResponse": false,
|
|
11597
12030
|
"bodyRequired": false,
|
|
@@ -12472,6 +12905,50 @@ const operationManifest = [
|
|
|
12472
12905
|
"tag": "Functions",
|
|
12473
12906
|
"tagCommand": "functions"
|
|
12474
12907
|
},
|
|
12908
|
+
{
|
|
12909
|
+
"binaryResponse": false,
|
|
12910
|
+
"bodyRequired": false,
|
|
12911
|
+
"command": "list-org-secrets",
|
|
12912
|
+
"description": "Returns metadata for every org-level secret. Org secrets apply\nto every function in the org and are read as `env.<KEY>` in\nhandlers. **Values are never returned.** Secret writes are\nwrite-only. A function-level secret of the same name overrides\nthe org-level value for that function.\n",
|
|
12913
|
+
"hasJsonBody": false,
|
|
12914
|
+
"method": "GET",
|
|
12915
|
+
"operationId": "listOrgSecrets",
|
|
12916
|
+
"path": "/org/secrets",
|
|
12917
|
+
"pathParams": [],
|
|
12918
|
+
"queryParams": [],
|
|
12919
|
+
"requestSchema": null,
|
|
12920
|
+
"responseSchema": {
|
|
12921
|
+
"type": "object",
|
|
12922
|
+
"properties": { "items": {
|
|
12923
|
+
"type": "array",
|
|
12924
|
+
"items": {
|
|
12925
|
+
"type": "object",
|
|
12926
|
+
"description": "One row from GET /org/secrets. Org secrets are always user-set\n(there are no managed org secrets), so `created_at` /\n`updated_at` are always present.\n",
|
|
12927
|
+
"properties": {
|
|
12928
|
+
"key": { "type": "string" },
|
|
12929
|
+
"created_at": {
|
|
12930
|
+
"type": "string",
|
|
12931
|
+
"format": "date-time"
|
|
12932
|
+
},
|
|
12933
|
+
"updated_at": {
|
|
12934
|
+
"type": "string",
|
|
12935
|
+
"format": "date-time"
|
|
12936
|
+
}
|
|
12937
|
+
},
|
|
12938
|
+
"required": [
|
|
12939
|
+
"key",
|
|
12940
|
+
"created_at",
|
|
12941
|
+
"updated_at"
|
|
12942
|
+
]
|
|
12943
|
+
}
|
|
12944
|
+
} },
|
|
12945
|
+
"required": ["items"]
|
|
12946
|
+
},
|
|
12947
|
+
"sdkName": "listOrgSecrets",
|
|
12948
|
+
"summary": "List org-level (global) secrets",
|
|
12949
|
+
"tag": "Functions",
|
|
12950
|
+
"tagCommand": "functions"
|
|
12951
|
+
},
|
|
12475
12952
|
{
|
|
12476
12953
|
"binaryResponse": false,
|
|
12477
12954
|
"bodyRequired": true,
|
|
@@ -12660,6 +13137,64 @@ const operationManifest = [
|
|
|
12660
13137
|
"tag": "Functions",
|
|
12661
13138
|
"tagCommand": "functions"
|
|
12662
13139
|
},
|
|
13140
|
+
{
|
|
13141
|
+
"binaryResponse": false,
|
|
13142
|
+
"bodyRequired": true,
|
|
13143
|
+
"command": "set-org-secret",
|
|
13144
|
+
"description": "Path-keyed companion to `POST /org/secrets`. Idempotent:\nreturns 201 the first time the key is set, 200 on subsequent\nupdates. Same validation and write-only guarantees as POST.\n",
|
|
13145
|
+
"hasJsonBody": true,
|
|
13146
|
+
"method": "PUT",
|
|
13147
|
+
"operationId": "setOrgSecret",
|
|
13148
|
+
"path": "/org/secrets/{key}",
|
|
13149
|
+
"pathParams": [{
|
|
13150
|
+
"description": "Secret key. Must match `^[A-Z_][A-Z0-9_]*$`.",
|
|
13151
|
+
"enum": null,
|
|
13152
|
+
"name": "key",
|
|
13153
|
+
"required": true,
|
|
13154
|
+
"type": "string"
|
|
13155
|
+
}],
|
|
13156
|
+
"queryParams": [],
|
|
13157
|
+
"requestSchema": {
|
|
13158
|
+
"type": "object",
|
|
13159
|
+
"additionalProperties": false,
|
|
13160
|
+
"description": "Body for PUT /org/secrets/{key}. Key comes from the path.",
|
|
13161
|
+
"properties": { "value": {
|
|
13162
|
+
"type": "string",
|
|
13163
|
+
"minLength": 1,
|
|
13164
|
+
"maxLength": 4096
|
|
13165
|
+
} },
|
|
13166
|
+
"required": ["value"]
|
|
13167
|
+
},
|
|
13168
|
+
"responseSchema": {
|
|
13169
|
+
"type": "object",
|
|
13170
|
+
"description": "Returned by POST and PUT org secret routes.",
|
|
13171
|
+
"properties": {
|
|
13172
|
+
"key": { "type": "string" },
|
|
13173
|
+
"created_at": {
|
|
13174
|
+
"type": "string",
|
|
13175
|
+
"format": "date-time"
|
|
13176
|
+
},
|
|
13177
|
+
"updated_at": {
|
|
13178
|
+
"type": "string",
|
|
13179
|
+
"format": "date-time"
|
|
13180
|
+
},
|
|
13181
|
+
"created": {
|
|
13182
|
+
"type": "boolean",
|
|
13183
|
+
"description": "True if this call inserted a new row, false if it updated an existing one."
|
|
13184
|
+
}
|
|
13185
|
+
},
|
|
13186
|
+
"required": [
|
|
13187
|
+
"key",
|
|
13188
|
+
"created_at",
|
|
13189
|
+
"updated_at",
|
|
13190
|
+
"created"
|
|
13191
|
+
]
|
|
13192
|
+
},
|
|
13193
|
+
"sdkName": "setOrgSecret",
|
|
13194
|
+
"summary": "Set an org secret by key",
|
|
13195
|
+
"tag": "Functions",
|
|
13196
|
+
"tagCommand": "functions"
|
|
13197
|
+
},
|
|
12663
13198
|
{
|
|
12664
13199
|
"binaryResponse": false,
|
|
12665
13200
|
"bodyRequired": false,
|
|
@@ -15344,6 +15879,76 @@ function canonicalizeCliReferences(description) {
|
|
|
15344
15879
|
return description.replaceAll("`primitive emails:latest`", "`primitive emails latest`").replaceAll("`primitive describe emails:get-email | jq '.responseSchema.properties'`", "`primitive describe emails:get | jq '.responseSchema.properties'`");
|
|
15345
15880
|
}
|
|
15346
15881
|
//#endregion
|
|
15882
|
+
//#region src/oclif/commands/agent-upgrade.ts
|
|
15883
|
+
/**
|
|
15884
|
+
* Interactive upgrade of an emailless agent account to a full developer
|
|
15885
|
+
* account: starts the email claim, prompts for the emailed code, and verifies
|
|
15886
|
+
* it. Combines the generated `agent:claim` (start) and `agent:claim-verify`
|
|
15887
|
+
* into one flow with a prompt, mirroring the `signup` interactive command.
|
|
15888
|
+
* Authenticated by the agent's own API key (the org is taken from the key).
|
|
15889
|
+
*/
|
|
15890
|
+
var AgentUpgradeCommand = class AgentUpgradeCommand extends Command {
|
|
15891
|
+
static description = "Upgrade an emailless agent account to a full developer account by confirming an email. Authenticated by the agent's own API key (PRIMITIVE_API_KEY).";
|
|
15892
|
+
static summary = "Upgrade an agent account to developer (email confirmation)";
|
|
15893
|
+
static examples = ["<%= config.bin %> agent upgrade --email you@example.com"];
|
|
15894
|
+
static flags = {
|
|
15895
|
+
email: Flags.string({ description: "Email to confirm. Prompted if omitted." }),
|
|
15896
|
+
code: Flags.string({ description: "Verification code from the email. Prompted if omitted." }),
|
|
15897
|
+
"api-key": Flags.string({
|
|
15898
|
+
env: "PRIMITIVE_API_KEY",
|
|
15899
|
+
description: "Agent API key (defaults to PRIMITIVE_API_KEY or saved credentials)."
|
|
15900
|
+
}),
|
|
15901
|
+
"api-base-url": Flags.string({ description: "Override the API base URL." })
|
|
15902
|
+
};
|
|
15903
|
+
async run() {
|
|
15904
|
+
const { flags } = await this.parse(AgentUpgradeCommand);
|
|
15905
|
+
const { apiClient } = await createAuthenticatedCliApiClient({
|
|
15906
|
+
apiKey: flags["api-key"],
|
|
15907
|
+
apiBaseUrl: flags["api-base-url"],
|
|
15908
|
+
configDir: this.config.configDir
|
|
15909
|
+
});
|
|
15910
|
+
const email = flags.email ?? await promptRequired$1("Email to confirm: ");
|
|
15911
|
+
const started = await startAgentClaim({
|
|
15912
|
+
body: { email },
|
|
15913
|
+
client: apiClient.client,
|
|
15914
|
+
responseStyle: "fields"
|
|
15915
|
+
});
|
|
15916
|
+
if (!started.data) {
|
|
15917
|
+
writeErrorWithHints(extractErrorPayload(started.error));
|
|
15918
|
+
this.exit(1);
|
|
15919
|
+
return;
|
|
15920
|
+
}
|
|
15921
|
+
process$1.stderr.write(`Verification code sent to ${email}.\n`);
|
|
15922
|
+
const verified = await verifyAgentClaim({
|
|
15923
|
+
body: { verification_code: flags.code ?? await promptRequired$1("Verification code: ") },
|
|
15924
|
+
client: apiClient.client,
|
|
15925
|
+
responseStyle: "fields"
|
|
15926
|
+
});
|
|
15927
|
+
const result = verified.data?.data;
|
|
15928
|
+
if (result) {
|
|
15929
|
+
this.log(JSON.stringify(result, null, 2));
|
|
15930
|
+
process$1.stderr.write(`Upgraded to ${result.plan}. Your API key and managed inbox carry over; the send cap is lifted.\n`);
|
|
15931
|
+
return;
|
|
15932
|
+
}
|
|
15933
|
+
writeErrorWithHints(extractErrorPayload(verified.error));
|
|
15934
|
+
this.exit(1);
|
|
15935
|
+
}
|
|
15936
|
+
};
|
|
15937
|
+
async function promptRequired$1(question) {
|
|
15938
|
+
const rl = createInterface({
|
|
15939
|
+
input: process$1.stdin,
|
|
15940
|
+
output: process$1.stderr
|
|
15941
|
+
});
|
|
15942
|
+
try {
|
|
15943
|
+
for (;;) {
|
|
15944
|
+
const answer = (await rl.question(question)).trim();
|
|
15945
|
+
if (answer) return answer;
|
|
15946
|
+
}
|
|
15947
|
+
} finally {
|
|
15948
|
+
rl.close();
|
|
15949
|
+
}
|
|
15950
|
+
}
|
|
15951
|
+
//#endregion
|
|
15347
15952
|
//#region src/oclif/attachments.ts
|
|
15348
15953
|
function readAttachmentBytes(path, readFile) {
|
|
15349
15954
|
try {
|
|
@@ -18777,8 +19382,8 @@ const PRIMITIVE_TEAM_AUTHOR = {
|
|
|
18777
19382
|
name: "Primitive Team",
|
|
18778
19383
|
url: "https://primitive.dev"
|
|
18779
19384
|
};
|
|
18780
|
-
const SDK_VERSION_RANGE = "^1.
|
|
18781
|
-
const CLI_VERSION_RANGE = "^1.
|
|
19385
|
+
const SDK_VERSION_RANGE = "^1.5.0";
|
|
19386
|
+
const CLI_VERSION_RANGE = "^1.5.0";
|
|
18782
19387
|
const ESBUILD_VERSION_RANGE = "^0.27.0";
|
|
18783
19388
|
function renderHandler() {
|
|
18784
19389
|
return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
|
|
@@ -21923,6 +22528,251 @@ var LogoutCommand = class LogoutCommand extends Command {
|
|
|
21923
22528
|
}
|
|
21924
22529
|
};
|
|
21925
22530
|
//#endregion
|
|
22531
|
+
//#region src/oclif/commands/org-secrets-shared.ts
|
|
22532
|
+
function orgSecretsUrl(baseUrl, key) {
|
|
22533
|
+
const base = `${baseUrl.replace(/\/$/, "")}/org/secrets`;
|
|
22534
|
+
return key ? `${base}/${encodeURIComponent(key)}` : base;
|
|
22535
|
+
}
|
|
22536
|
+
function orgSecretsAuthHeaders(requestHeaders, apiKey) {
|
|
22537
|
+
return {
|
|
22538
|
+
...requestHeaders ?? {},
|
|
22539
|
+
...apiKey ? { authorization: `Bearer ${apiKey}` } : {}
|
|
22540
|
+
};
|
|
22541
|
+
}
|
|
22542
|
+
async function orgSecretsErrorPayload(response) {
|
|
22543
|
+
if ((response.headers.get("content-type")?.toLowerCase() ?? "").includes("application/json")) return response.json().catch(() => ({
|
|
22544
|
+
code: "http_error",
|
|
22545
|
+
message: `HTTP ${response.status} ${response.statusText}`.trim()
|
|
22546
|
+
}));
|
|
22547
|
+
return {
|
|
22548
|
+
code: "http_error",
|
|
22549
|
+
message: (await response.text().catch(() => "")).trim() || `HTTP ${response.status} ${response.statusText}`.trim()
|
|
22550
|
+
};
|
|
22551
|
+
}
|
|
22552
|
+
async function runOrgSecretsRequest(fetchImpl, baseUrl, headers, op) {
|
|
22553
|
+
const url = op.kind === "remove" ? orgSecretsUrl(baseUrl, op.key) : orgSecretsUrl(baseUrl);
|
|
22554
|
+
const init = op.kind === "set" ? {
|
|
22555
|
+
method: "POST",
|
|
22556
|
+
headers: {
|
|
22557
|
+
...headers,
|
|
22558
|
+
"content-type": "application/json"
|
|
22559
|
+
},
|
|
22560
|
+
body: JSON.stringify({
|
|
22561
|
+
key: op.key,
|
|
22562
|
+
value: op.value
|
|
22563
|
+
})
|
|
22564
|
+
} : op.kind === "remove" ? {
|
|
22565
|
+
method: "DELETE",
|
|
22566
|
+
headers
|
|
22567
|
+
} : { headers };
|
|
22568
|
+
let response;
|
|
22569
|
+
try {
|
|
22570
|
+
response = await fetchImpl(url, init);
|
|
22571
|
+
} catch (error) {
|
|
22572
|
+
return {
|
|
22573
|
+
kind: "error",
|
|
22574
|
+
payload: extractErrorPayload(error)
|
|
22575
|
+
};
|
|
22576
|
+
}
|
|
22577
|
+
if (!response.ok) return {
|
|
22578
|
+
kind: "error",
|
|
22579
|
+
payload: extractErrorPayload(await orgSecretsErrorPayload(response))
|
|
22580
|
+
};
|
|
22581
|
+
if (op.kind === "remove") return {
|
|
22582
|
+
kind: "ok",
|
|
22583
|
+
data: null
|
|
22584
|
+
};
|
|
22585
|
+
const body = await response.json().catch(() => ({}));
|
|
22586
|
+
if (op.kind === "list") return {
|
|
22587
|
+
kind: "ok",
|
|
22588
|
+
data: body.data?.items ?? []
|
|
22589
|
+
};
|
|
22590
|
+
return {
|
|
22591
|
+
kind: "ok",
|
|
22592
|
+
data: body.data ?? {}
|
|
22593
|
+
};
|
|
22594
|
+
}
|
|
22595
|
+
//#endregion
|
|
22596
|
+
//#region src/oclif/commands/org-secrets-list.ts
|
|
22597
|
+
var OrgSecretsListCommand = class OrgSecretsListCommand extends Command {
|
|
22598
|
+
static description = `List your organization's global secrets.
|
|
22599
|
+
|
|
22600
|
+
Global secrets apply to every function in the org and are read as
|
|
22601
|
+
\`env.<KEY>\` in handlers. Only the keys and timestamps are returned;
|
|
22602
|
+
the values are encrypted at rest and never surfaced.`;
|
|
22603
|
+
static summary = "List global secrets (keys only; values never returned)";
|
|
22604
|
+
static examples = ["<%= config.bin %> org secrets list"];
|
|
22605
|
+
static flags = {
|
|
22606
|
+
"api-key": Flags.string({
|
|
22607
|
+
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
22608
|
+
env: "PRIMITIVE_API_KEY"
|
|
22609
|
+
}),
|
|
22610
|
+
"api-base-url": Flags.string({
|
|
22611
|
+
description: "Override the primary API base URL. Internal testing only; not documented to customers.",
|
|
22612
|
+
env: "PRIMITIVE_API_BASE_URL",
|
|
22613
|
+
hidden: true
|
|
22614
|
+
}),
|
|
22615
|
+
time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION })
|
|
22616
|
+
};
|
|
22617
|
+
async run() {
|
|
22618
|
+
const { flags } = await this.parse(OrgSecretsListCommand);
|
|
22619
|
+
await runWithTiming(flags.time, async () => {
|
|
22620
|
+
const { auth, baseUrlOverridden, requestConfig } = await createAuthenticatedCliApiClient({
|
|
22621
|
+
apiKey: flags["api-key"],
|
|
22622
|
+
apiBaseUrl: flags["api-base-url"],
|
|
22623
|
+
configDir: this.config.configDir
|
|
22624
|
+
});
|
|
22625
|
+
const outcome = await runOrgSecretsRequest(fetch, requestConfig.resolvedApiBaseUrl, orgSecretsAuthHeaders(requestConfig.headers, auth.apiKey), { kind: "list" });
|
|
22626
|
+
if (outcome.kind === "error") {
|
|
22627
|
+
writeErrorWithHints(outcome.payload);
|
|
22628
|
+
surfaceUnauthorizedHint({
|
|
22629
|
+
auth,
|
|
22630
|
+
baseUrlOverridden,
|
|
22631
|
+
configDir: this.config.configDir,
|
|
22632
|
+
payload: outcome.payload
|
|
22633
|
+
});
|
|
22634
|
+
process.exitCode = 1;
|
|
22635
|
+
return;
|
|
22636
|
+
}
|
|
22637
|
+
this.log(JSON.stringify(outcome.data, null, 2));
|
|
22638
|
+
});
|
|
22639
|
+
}
|
|
22640
|
+
};
|
|
22641
|
+
//#endregion
|
|
22642
|
+
//#region src/oclif/commands/org-secrets-remove.ts
|
|
22643
|
+
var OrgSecretsRemoveCommand = class OrgSecretsRemoveCommand extends Command {
|
|
22644
|
+
static description = `Delete a global secret.
|
|
22645
|
+
|
|
22646
|
+
Deployed functions keep the previous value until each is redeployed. A
|
|
22647
|
+
function that defines its own secret of the same name is unaffected.`;
|
|
22648
|
+
static summary = "Delete a global secret";
|
|
22649
|
+
static aliases = ["org:secrets:delete"];
|
|
22650
|
+
static examples = ["<%= config.bin %> org secrets remove --key STRIPE_KEY"];
|
|
22651
|
+
static flags = {
|
|
22652
|
+
"api-key": Flags.string({
|
|
22653
|
+
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
22654
|
+
env: "PRIMITIVE_API_KEY"
|
|
22655
|
+
}),
|
|
22656
|
+
"api-base-url": Flags.string({
|
|
22657
|
+
description: "Override the primary API base URL. Internal testing only; not documented to customers.",
|
|
22658
|
+
env: "PRIMITIVE_API_BASE_URL",
|
|
22659
|
+
hidden: true
|
|
22660
|
+
}),
|
|
22661
|
+
key: Flags.string({
|
|
22662
|
+
description: "Global secret key to delete.",
|
|
22663
|
+
required: true
|
|
22664
|
+
}),
|
|
22665
|
+
time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION })
|
|
22666
|
+
};
|
|
22667
|
+
async run() {
|
|
22668
|
+
const { flags } = await this.parse(OrgSecretsRemoveCommand);
|
|
22669
|
+
await runWithTiming(flags.time, async () => {
|
|
22670
|
+
const { auth, baseUrlOverridden, requestConfig } = await createAuthenticatedCliApiClient({
|
|
22671
|
+
apiKey: flags["api-key"],
|
|
22672
|
+
apiBaseUrl: flags["api-base-url"],
|
|
22673
|
+
configDir: this.config.configDir
|
|
22674
|
+
});
|
|
22675
|
+
const outcome = await runOrgSecretsRequest(fetch, requestConfig.resolvedApiBaseUrl, orgSecretsAuthHeaders(requestConfig.headers, auth.apiKey), {
|
|
22676
|
+
kind: "remove",
|
|
22677
|
+
key: flags.key
|
|
22678
|
+
});
|
|
22679
|
+
if (outcome.kind === "error") {
|
|
22680
|
+
writeErrorWithHints(outcome.payload);
|
|
22681
|
+
surfaceUnauthorizedHint({
|
|
22682
|
+
auth,
|
|
22683
|
+
baseUrlOverridden,
|
|
22684
|
+
configDir: this.config.configDir,
|
|
22685
|
+
payload: outcome.payload
|
|
22686
|
+
});
|
|
22687
|
+
process.exitCode = 1;
|
|
22688
|
+
return;
|
|
22689
|
+
}
|
|
22690
|
+
process.stderr.write(`Global secret ${flags.key} deleted. Deployed functions keep the previous value until each is redeployed.\n`);
|
|
22691
|
+
});
|
|
22692
|
+
}
|
|
22693
|
+
};
|
|
22694
|
+
//#endregion
|
|
22695
|
+
//#region src/oclif/commands/org-secrets-set.ts
|
|
22696
|
+
var OrgSecretsSetCommand = class OrgSecretsSetCommand extends Command {
|
|
22697
|
+
static description = `Set a global secret available to every function as \`env.<KEY>\`.
|
|
22698
|
+
|
|
22699
|
+
Global secrets are read into each function at deploy time, so a new or
|
|
22700
|
+
changed value lands in a function only on its next redeploy. A function
|
|
22701
|
+
secret with the same key overrides the global value for that function.
|
|
22702
|
+
|
|
22703
|
+
Keys must match \`^[A-Z_][A-Z0-9_]*$\` (uppercase letters, digits,
|
|
22704
|
+
underscores; first character a letter or underscore). System-managed keys
|
|
22705
|
+
are reserved and rejected. ${SINGLE_SECRET_VALUE_SOURCE_DESCRIPTION}`;
|
|
22706
|
+
static summary = "Set a global secret shared across all functions";
|
|
22707
|
+
static examples = [
|
|
22708
|
+
"<%= config.bin %> org secrets set --key STRIPE_KEY --value sk_live_...",
|
|
22709
|
+
"<%= config.bin %> org secrets set --key OPENAI_KEY --value-from-env OPENAI_KEY",
|
|
22710
|
+
"printf '%s' \"$OPENAI_KEY\" | <%= config.bin %> org secrets set --key OPENAI_KEY --stdin"
|
|
22711
|
+
];
|
|
22712
|
+
static flags = {
|
|
22713
|
+
"api-key": Flags.string({
|
|
22714
|
+
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
22715
|
+
env: "PRIMITIVE_API_KEY"
|
|
22716
|
+
}),
|
|
22717
|
+
"api-base-url": Flags.string({
|
|
22718
|
+
description: "Override the primary API base URL. Internal testing only; not documented to customers.",
|
|
22719
|
+
env: "PRIMITIVE_API_BASE_URL",
|
|
22720
|
+
hidden: true
|
|
22721
|
+
}),
|
|
22722
|
+
key: Flags.string({
|
|
22723
|
+
description: "Secret key. Uppercase letters, digits, underscores; must start with a letter or underscore. System-managed keys are reserved.",
|
|
22724
|
+
required: true
|
|
22725
|
+
}),
|
|
22726
|
+
value: Flags.string({ description: "Secret value (up to 4096 UTF-8 bytes). Encrypted at rest. Visible in shell history and process argv; prefer a non-argv source for sensitive values." }),
|
|
22727
|
+
"value-from-env": Flags.string({ description: "Environment variable to read as the secret value. Example: --value-from-env OPENAI_KEY reads process.env.OPENAI_KEY." }),
|
|
22728
|
+
"value-file": Flags.string({ description: "UTF-8 file to read as the secret value. The full file contents become the value." }),
|
|
22729
|
+
"value-from-env-file": Flags.string({ description: "Dotenv-style file to read as the secret value. Use FILE to read --key from that file, or FILE:KEY to read a different key." }),
|
|
22730
|
+
stdin: Flags.boolean({ description: "Read the secret value from stdin. A single trailing line ending is stripped." }),
|
|
22731
|
+
time: Flags.boolean({ description: TIME_FLAG_DESCRIPTION })
|
|
22732
|
+
};
|
|
22733
|
+
async run() {
|
|
22734
|
+
const { flags } = await this.parse(OrgSecretsSetCommand);
|
|
22735
|
+
await runWithTiming(flags.time, async () => {
|
|
22736
|
+
const { auth, baseUrlOverridden, requestConfig } = await createAuthenticatedCliApiClient({
|
|
22737
|
+
apiKey: flags["api-key"],
|
|
22738
|
+
apiBaseUrl: flags["api-base-url"],
|
|
22739
|
+
configDir: this.config.configDir
|
|
22740
|
+
});
|
|
22741
|
+
const resolved = resolveSingleSecretValue({
|
|
22742
|
+
key: flags.key,
|
|
22743
|
+
value: flags.value,
|
|
22744
|
+
valueFile: flags["value-file"],
|
|
22745
|
+
valueFromEnv: flags["value-from-env"],
|
|
22746
|
+
valueFromEnvFile: flags["value-from-env-file"],
|
|
22747
|
+
stdin: flags.stdin
|
|
22748
|
+
});
|
|
22749
|
+
if (resolved.kind === "error") {
|
|
22750
|
+
process.stderr.write(`${resolved.message}\n`);
|
|
22751
|
+
process.exitCode = 1;
|
|
22752
|
+
return;
|
|
22753
|
+
}
|
|
22754
|
+
const outcome = await runOrgSecretsRequest(fetch, requestConfig.resolvedApiBaseUrl, orgSecretsAuthHeaders(requestConfig.headers, auth.apiKey), {
|
|
22755
|
+
kind: "set",
|
|
22756
|
+
key: flags.key,
|
|
22757
|
+
value: resolved.value
|
|
22758
|
+
});
|
|
22759
|
+
if (outcome.kind === "error") {
|
|
22760
|
+
writeErrorWithHints(outcome.payload);
|
|
22761
|
+
surfaceUnauthorizedHint({
|
|
22762
|
+
auth,
|
|
22763
|
+
baseUrlOverridden,
|
|
22764
|
+
configDir: this.config.configDir,
|
|
22765
|
+
payload: outcome.payload
|
|
22766
|
+
});
|
|
22767
|
+
process.exitCode = 1;
|
|
22768
|
+
return;
|
|
22769
|
+
}
|
|
22770
|
+
this.log(JSON.stringify(outcome.data, null, 2));
|
|
22771
|
+
process.stderr.write(`Global secret ${flags.key} saved. Deployed functions pick it up on their next redeploy; a function secret of the same name overrides it.\n`);
|
|
22772
|
+
});
|
|
22773
|
+
}
|
|
22774
|
+
};
|
|
22775
|
+
//#endregion
|
|
21926
22776
|
//#region src/oclif/message-body-sources.ts
|
|
21927
22777
|
function defaultReadFile(path) {
|
|
21928
22778
|
return readFileSync(path, "utf8");
|
|
@@ -23358,6 +24208,7 @@ const OVERRIDDEN_OPERATION_IDS = new Set([
|
|
|
23358
24208
|
const generatedCommands = Object.fromEntries(operationManifest.filter((operation) => !OVERRIDDEN_OPERATION_IDS.has(operationId(operation))).map((operation) => [operationId(operation), createOperationCommand(operation)]));
|
|
23359
24209
|
const COMMANDS = {
|
|
23360
24210
|
completion: CompletionCommand,
|
|
24211
|
+
"agent:upgrade": AgentUpgradeCommand,
|
|
23361
24212
|
"list-operations": ListOperationsCommand,
|
|
23362
24213
|
config: ConfigCommand,
|
|
23363
24214
|
"config:list": ConfigListCommand,
|
|
@@ -23410,6 +24261,9 @@ const COMMANDS = {
|
|
|
23410
24261
|
"functions:deploy": FunctionsDeployCommand,
|
|
23411
24262
|
"functions:redeploy": FunctionsRedeployCommand,
|
|
23412
24263
|
"functions:set-secret": FunctionsSetSecretCommand,
|
|
24264
|
+
"org:secrets:list": OrgSecretsListCommand,
|
|
24265
|
+
"org:secrets:set": OrgSecretsSetCommand,
|
|
24266
|
+
"org:secrets:remove": OrgSecretsRemoveCommand,
|
|
23413
24267
|
"functions:test": FunctionsTestFunctionCommand,
|
|
23414
24268
|
"functions:test-function": FunctionsTestFunctionCommand,
|
|
23415
24269
|
"functions:route-set": FunctionsRouteSetCommand,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primitivedotdev/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Official Primitive CLI: deploy Primitive Functions, send and inspect mail, manage endpoints, all from the terminal. Wraps the @primitivedotdev/sdk runtime client with one-shot commands.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -97,6 +97,12 @@
|
|
|
97
97
|
},
|
|
98
98
|
"functions": {
|
|
99
99
|
"description": "Deploy JavaScript handlers that run on inbound mail. Prefer `primitive functions templates`, `primitive functions init`, `primitive functions deploy`, `primitive functions redeploy`, `primitive functions list`, `primitive functions get`, `primitive functions logs`, and `primitive functions set-secret`; generated API names remain available for compatibility."
|
|
100
|
+
},
|
|
101
|
+
"org": {
|
|
102
|
+
"description": "Manage org-level (global) resources shared across functions"
|
|
103
|
+
},
|
|
104
|
+
"org:secrets": {
|
|
105
|
+
"description": "Global secrets shared across every function. Use `primitive org secrets list|set|remove`. Changes land in a function on its next redeploy; a function secret of the same name overrides the global."
|
|
100
106
|
}
|
|
101
107
|
},
|
|
102
108
|
"topicSeparator": " "
|