@samva/cli 0.16.0 → 0.18.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/AGENTS.md +22 -7
- package/dist/bin.mjs +298 -99
- package/package.json +7 -7
package/AGENTS.md
CHANGED
|
@@ -21,9 +21,15 @@ response writes its body to stderr and exits `4` for 401 and 403, otherwise `1`.
|
|
|
21
21
|
is no built-in filter.
|
|
22
22
|
|
|
23
23
|
`samva api-keys` manages the organization's keys: `list`, `get`, `create`, `update`, `rotate`, and
|
|
24
|
-
`revoke`. `create` takes `--name` and
|
|
25
|
-
<resource>=read|write`
|
|
26
|
-
|
|
24
|
+
`revoke`. `create` takes `--name` and either `--full-access` or restricted access built from repeatable
|
|
25
|
+
`--grant <resource>=read|write` and mailbox access: repeatable `--mailbox-permission
|
|
26
|
+
read|update|send|quarantine.read`, optionally narrowed to repeatable `--mailbox <id>` (default:
|
|
27
|
+
every mailbox the owner reaches) with `--send-mode approval` (each send waits for a person other
|
|
28
|
+
than the key). `--namespace <id>` confines a restricted key to one namespace. Passing no access, or both
|
|
29
|
+
`--full-access` and restricted access, exits `2`, as does `--mailbox` or `--send-mode` without a
|
|
30
|
+
`--mailbox-permission`. `--description` and `--expires-at` are optional. `update` renames a key,
|
|
31
|
+
sets its description, or changes a mailbox key's `--send-mode` (a person signed in with `samva
|
|
32
|
+
login`); every other part of a key's access is fixed at creation. The API refuses a key with more access than the
|
|
27
33
|
caller holds. `create` and `rotate` return the secret once: `--json` carries `{apiKey, key,
|
|
28
34
|
displayOnce, warning}`, so `samva api-keys create ... --json | jq -r .data.key` yields the key, and
|
|
29
35
|
human mode prints it to stdout with the warning on stderr. `rotate` and `revoke` require
|
|
@@ -31,6 +37,12 @@ confirmation (`--yes` outside a terminal), and every mutation supports `--dry-ru
|
|
|
31
37
|
`SAMVA_API_KEY`, `samva org current` asks the API who the key is (`GET /v1/whoami`) and reports its
|
|
32
38
|
organization and key; with OAuth it reports the profile's selected organization.
|
|
33
39
|
|
|
40
|
+
`samva webhooks secret <id>` reads the current signing secret with `webhooks:update` permission.
|
|
41
|
+
Human output includes the secret, its creation time, and when the previous secret stops verifying
|
|
42
|
+
if one exists. `--json` returns `{secret, createdAt, previousExpiresAt}` inside the result envelope.
|
|
43
|
+
`create` and `rotate-secret` return readable secrets too; retrieve them again with `secret <id>`.
|
|
44
|
+
Their JSON results contain `secret` and `warning` (`create` also includes `endpoint`).
|
|
45
|
+
|
|
34
46
|
`samva templates export --out <dir>` renders every local template's fixtures to HTML
|
|
35
47
|
and text with the asset manifest, needing a Samva credential only to resolve a live `samva:brand`; `--asset-base <origin>` is for an
|
|
36
48
|
export that will be delivered, which cannot carry a relative reference.
|
|
@@ -136,7 +148,10 @@ calls to you, rather than to an installation. Read what exists with `list`, `ver
|
|
|
136
148
|
`run <id> <run-id>` (adds the handler's log lines); the list commands page with `--limit`,
|
|
137
149
|
`--cursor`, and `--all --jsonl`.
|
|
138
150
|
|
|
139
|
-
`samva mailboxes` reads and sends as a mailbox
|
|
151
|
+
`samva mailboxes` reads and sends as a mailbox. Every command except `list` and `create`
|
|
152
|
+
takes the mailbox ID as its first argument and the message, action, or endpoint ID second,
|
|
153
|
+
as in `read <mailbox-id> <message-id>` and `endpoints update <mailbox-id> <endpoint-id>`; `events`
|
|
154
|
+
takes any number of mailbox IDs, or none for every mailbox the credential reads. `list` pages with `--limit`, `--cursor`, `--after`,
|
|
140
155
|
and `--before`. `create --address <address> --name <name>` makes a mailbox with one email endpoint; the
|
|
141
156
|
slug defaults to the address's local part, and a collision asks for `--slug` rather than suffixing.
|
|
142
157
|
`get <id>` inspects a mailbox; `update <id> --data <JSON-or-@file>` changes
|
|
@@ -156,9 +171,9 @@ public SDK describes email only.
|
|
|
156
171
|
Quarantine `list` pages the same way, bounded by `--after` and `--before` on when a message was
|
|
157
172
|
held; `release` and `discard` take the held message's `id` and require a person signed in with
|
|
158
173
|
`samva login`. Discard requires confirmation (`--yes` outside a terminal) and supports `--dry-run`.
|
|
159
|
-
`actions list
|
|
160
|
-
`--all --jsonl`. `actions approve <
|
|
161
|
-
|
|
174
|
+
`actions list <mailbox-id>` filters by `--state` and pages with `--limit`, `--cursor`, and
|
|
175
|
+
`--all --jsonl`. `actions approve <mailbox-id> <action-id>` and `actions deny <mailbox-id>
|
|
176
|
+
<action-id> [--reason <text>]` require a person different from the proposer, confirmation
|
|
162
177
|
(`--yes` outside a terminal), and offer `--dry-run`.
|
|
163
178
|
Human mailbox and extension results retain the same facts as JSON: mailbox endpoints (channel, address,
|
|
164
179
|
sender name, default), thread state and activity, message bodies, attachments, authentication and actor,
|
package/dist/bin.mjs
CHANGED
|
@@ -14106,7 +14106,7 @@ var layer12 = /* @__PURE__ */ layer.pipe(/* @__PURE__ */ provideMerge(/* @__PURE
|
|
|
14106
14106
|
// package.json
|
|
14107
14107
|
var package_default = {
|
|
14108
14108
|
name: "@samva/cli",
|
|
14109
|
-
version: "0.
|
|
14109
|
+
version: "0.18.0",
|
|
14110
14110
|
description: "Samva CLI \u2014 email and platform operations from your terminal",
|
|
14111
14111
|
keywords: [
|
|
14112
14112
|
"cli",
|
|
@@ -14162,16 +14162,16 @@ var package_default = {
|
|
|
14162
14162
|
"@types/node": "catalog:",
|
|
14163
14163
|
"better-auth": "catalog:",
|
|
14164
14164
|
effect: "catalog:effect",
|
|
14165
|
-
samva: "workspace:0.
|
|
14165
|
+
samva: "workspace:0.21.0",
|
|
14166
14166
|
typescript: "catalog:",
|
|
14167
14167
|
vite: "~8.3.0",
|
|
14168
14168
|
vitest: "catalog:"
|
|
14169
14169
|
},
|
|
14170
14170
|
optionalDependencies: {
|
|
14171
|
-
"@samva/cli-darwin-arm64": "workspace:0.
|
|
14172
|
-
"@samva/cli-darwin-x64": "workspace:0.
|
|
14173
|
-
"@samva/cli-linux-arm64": "workspace:0.
|
|
14174
|
-
"@samva/cli-linux-x64": "workspace:0.
|
|
14171
|
+
"@samva/cli-darwin-arm64": "workspace:0.18.0",
|
|
14172
|
+
"@samva/cli-darwin-x64": "workspace:0.18.0",
|
|
14173
|
+
"@samva/cli-linux-arm64": "workspace:0.18.0",
|
|
14174
|
+
"@samva/cli-linux-x64": "workspace:0.18.0"
|
|
14175
14175
|
},
|
|
14176
14176
|
engines: {
|
|
14177
14177
|
node: ">=18"
|
|
@@ -19353,6 +19353,7 @@ var Literals4 = (name, choices) => Literals2(argumentKind, name, choices);
|
|
|
19353
19353
|
var optional5 = (arg) => optional3(arg);
|
|
19354
19354
|
var withDescription4 = /* @__PURE__ */ dual(2, (self, description) => withDescription(self, description));
|
|
19355
19355
|
var withDefault6 = withDefault4;
|
|
19356
|
+
var atLeast3 = /* @__PURE__ */ dual(2, (self, min) => atLeast(self, min));
|
|
19356
19357
|
var withSchema3 = /* @__PURE__ */ dual(2, (self, schema) => withSchema(self, schema));
|
|
19357
19358
|
var filterMap3 = /* @__PURE__ */ dual(3, (self, f, onNone) => filterMap2(self, f, onNone));
|
|
19358
19359
|
|
|
@@ -19595,6 +19596,9 @@ var ENTITY_PREFIXES = {
|
|
|
19595
19596
|
waflow: "WhatsAppFlowId",
|
|
19596
19597
|
wafver: "WhatsAppFlowVersionId",
|
|
19597
19598
|
wafreg: "WhatsAppFlowRegistrationId",
|
|
19599
|
+
wafkey: "WhatsAppFlowEncryptionKeyId",
|
|
19600
|
+
wafx: "WhatsAppFlowExchangeId",
|
|
19601
|
+
wasl: "WhatsAppSetupLinkId",
|
|
19598
19602
|
mbx: "MailboxId",
|
|
19599
19603
|
mbxep: "MailboxEndpointId",
|
|
19600
19604
|
thread: "MailboxThreadId",
|
|
@@ -19690,6 +19694,9 @@ var WhatsAppBusinessAccountId = entityId("waba").pipe(brand(ENTITY_PREFIXES.waba
|
|
|
19690
19694
|
var WhatsAppFlowId = entityId("waflow").pipe(brand(ENTITY_PREFIXES.waflow));
|
|
19691
19695
|
var WhatsAppFlowVersionId = entityId("wafver").pipe(brand(ENTITY_PREFIXES.wafver));
|
|
19692
19696
|
var WhatsAppFlowRegistrationId = entityId("wafreg").pipe(brand(ENTITY_PREFIXES.wafreg));
|
|
19697
|
+
var WhatsAppFlowEncryptionKeyId = entityId("wafkey").pipe(brand(ENTITY_PREFIXES.wafkey));
|
|
19698
|
+
var WhatsAppFlowExchangeId = entityId("wafx").pipe(brand(ENTITY_PREFIXES.wafx));
|
|
19699
|
+
var WhatsAppSetupLinkId = entityId("wasl").pipe(brand(ENTITY_PREFIXES.wasl));
|
|
19693
19700
|
var WhatsAppServiceWindowId = entityId("wasw").pipe(brand(ENTITY_PREFIXES.wasw));
|
|
19694
19701
|
var WebhookEndpointId = entityId("wep").pipe(brand(ENTITY_PREFIXES.wep));
|
|
19695
19702
|
var WebhookCredentialId = entityId("whcred").pipe(brand(ENTITY_PREFIXES.whcred));
|
|
@@ -20397,6 +20404,7 @@ var DOMAIN_WEBHOOK_EVENT_TYPE_VALUES = [
|
|
|
20397
20404
|
var domainWebhookEventTypeSchema = Literals(DOMAIN_WEBHOOK_EVENT_TYPE_VALUES);
|
|
20398
20405
|
var TEMPLATE_WEBHOOK_EVENT_TYPE_VALUES = ["template.registration.updated"];
|
|
20399
20406
|
var FLOW_WEBHOOK_EVENT_TYPE_VALUES = ["flow.registration.updated"];
|
|
20407
|
+
var WHATSAPP_NUMBER_WEBHOOK_EVENT_TYPE_VALUES = ["whatsapp.number.connected"];
|
|
20400
20408
|
var MAILBOX_WEBHOOK_EVENT_TYPE_VALUES = [
|
|
20401
20409
|
"mailbox.message.received",
|
|
20402
20410
|
"mailbox.message.sent",
|
|
@@ -20421,6 +20429,7 @@ var WEBHOOK_EVENT_TYPE_VALUES = [
|
|
|
20421
20429
|
...DOMAIN_WEBHOOK_EVENT_TYPE_VALUES,
|
|
20422
20430
|
...TEMPLATE_WEBHOOK_EVENT_TYPE_VALUES,
|
|
20423
20431
|
...FLOW_WEBHOOK_EVENT_TYPE_VALUES,
|
|
20432
|
+
...WHATSAPP_NUMBER_WEBHOOK_EVENT_TYPE_VALUES,
|
|
20424
20433
|
...MAILBOX_WEBHOOK_EVENT_TYPE_VALUES,
|
|
20425
20434
|
...JOURNEY_WEBHOOK_EVENT_TYPE_VALUES
|
|
20426
20435
|
];
|
|
@@ -24148,6 +24157,7 @@ var CreateTemplatePayload = /* @__PURE__ */ Struct({
|
|
|
24148
24157
|
]), Null2]), Null2])),
|
|
24149
24158
|
isActive: optionalKey2(Union2([Boolean3, Null2])),
|
|
24150
24159
|
namespaceId: optionalKey2(Union2([NamespaceId2, Null2]).annotate({ description: "The namespace the new template project belongs to; the project and every entry added to it share it. Omit for organization level. A namespace-scoped key always creates in its own namespace." })),
|
|
24160
|
+
shared: optionalKey2(Union2([Boolean3, Null2]).annotate({ description: "Share the new organization-level project with every namespace: namespace-scoped keys read and send its entries but cannot change them. Defaults to false. Not with `namespaceId`, and not from a namespace-scoped key." })),
|
|
24151
24161
|
idempotencyKey: String4.check(isMinLength(1).annotate({ expected: "a value with a length of at least 1" })).check(isMaxCodePoints(255).annotate({ expected: "a string with at most 255 code points" })).check(isMaxLength(255).annotate({ expected: "a value with a length of at most 255" }))
|
|
24152
24162
|
}).annotate({ identifier: "CreateTemplatePayload" });
|
|
24153
24163
|
var CreateWebhookPayload = /* @__PURE__ */ Struct({
|
|
@@ -24461,7 +24471,8 @@ var UpdateTemplatePayload = /* @__PURE__ */ Struct({ data: Struct({
|
|
|
24461
24471
|
]), Null2]), Null2])),
|
|
24462
24472
|
fromDefault: optionalKey2(Union2([Union2([TemplateFromDefault, Null2]), Null2])),
|
|
24463
24473
|
replyToDefault: optionalKey2(Union2([Union2([ArraySchema(String4), Null2]), Null2])),
|
|
24464
|
-
isActive: optionalKey2(Union2([Boolean3, Null2]))
|
|
24474
|
+
isActive: optionalKey2(Union2([Boolean3, Null2])),
|
|
24475
|
+
shared: optionalKey2(Union2([Boolean3, Null2]).annotate({ description: "Share the template's project with every namespace, or stop sharing it. Applies to every entry in the project. Only an organization-level project is shared." }))
|
|
24465
24476
|
}) }).annotate({ identifier: "UpdateTemplatePayload" });
|
|
24466
24477
|
var ApiKeyAccess = /* @__PURE__ */ Union2([Struct({ mode: Literal2("full") }), Struct({
|
|
24467
24478
|
mode: Literal2("restricted"),
|
|
@@ -24798,6 +24809,7 @@ var apiStatuses = {
|
|
|
24798
24809
|
MailboxSendConflictError: 409,
|
|
24799
24810
|
MailboxSendRefusedError: 403,
|
|
24800
24811
|
CursorExpiredError: 410,
|
|
24812
|
+
WhatsAppSetupLinkUnavailableError: 410,
|
|
24801
24813
|
MethodNotAllowedError: 405,
|
|
24802
24814
|
UpgradeRequiredError: 426,
|
|
24803
24815
|
RateLimitedError: 429,
|
|
@@ -25081,7 +25093,7 @@ var __exportAll = (all, no_symbols) => {
|
|
|
25081
25093
|
};
|
|
25082
25094
|
|
|
25083
25095
|
// ../sdk/dist/package.js
|
|
25084
|
-
var version = "0.
|
|
25096
|
+
var version = "0.21.0";
|
|
25085
25097
|
|
|
25086
25098
|
// ../sdk/dist/client-attribution.js
|
|
25087
25099
|
var SDK_VERSION = version;
|
|
@@ -25472,6 +25484,7 @@ var commandTree = {
|
|
|
25472
25484
|
webhooks: {
|
|
25473
25485
|
list: {},
|
|
25474
25486
|
get: {},
|
|
25487
|
+
secret: {},
|
|
25475
25488
|
create: {},
|
|
25476
25489
|
update: {},
|
|
25477
25490
|
test: {},
|
|
@@ -25902,7 +25915,12 @@ var getAuthenticatedJsonForContext = fn2("CliClient.getAuthenticatedJson")(funct
|
|
|
25902
25915
|
};
|
|
25903
25916
|
const url = `${config.baseUrl.replace(/\/$/, "")}${path}`;
|
|
25904
25917
|
const response = yield* tryPromise2({
|
|
25905
|
-
try: (signal) => fetch(url, request === undefined ? { headers, signal } : {
|
|
25918
|
+
try: (signal) => fetch(url, request === undefined ? { headers, signal } : {
|
|
25919
|
+
method: request.method ?? "POST",
|
|
25920
|
+
headers,
|
|
25921
|
+
body: JSON.stringify(request.body),
|
|
25922
|
+
signal
|
|
25923
|
+
}),
|
|
25906
25924
|
catch: (cause) => new SamvaCliError({ message: `Request to ${url} failed: ${String(cause)}` })
|
|
25907
25925
|
});
|
|
25908
25926
|
const body = yield* tryPromise2({
|
|
@@ -26569,6 +26587,7 @@ var API_KEY_STATEMENT = {
|
|
|
26569
26587
|
};
|
|
26570
26588
|
var API_KEY_RESOURCES = Object.keys(API_KEY_STATEMENT);
|
|
26571
26589
|
var API_KEY_LEVEL_RESOURCES = API_KEY_RESOURCES.filter((resource) => resource !== "mailboxes");
|
|
26590
|
+
var API_KEY_MAILBOX_ACTIONS = mailboxKeyActions;
|
|
26572
26591
|
function apiKeyAccessLevels(resource) {
|
|
26573
26592
|
return API_KEY_STATEMENT[resource].some((action) => action !== "read") ? ["read", "write"] : ["read"];
|
|
26574
26593
|
}
|
|
@@ -27164,6 +27183,10 @@ var SDK_OPERATION_CALLS = {
|
|
|
27164
27183
|
whoamiGet: { kind: "none" },
|
|
27165
27184
|
webhooksList: { kind: "params" },
|
|
27166
27185
|
webhooksCreate: { kind: "payload" },
|
|
27186
|
+
webhooksGetSecret: {
|
|
27187
|
+
kind: "path",
|
|
27188
|
+
paths: ["id"]
|
|
27189
|
+
},
|
|
27167
27190
|
webhooksGet: {
|
|
27168
27191
|
kind: "path",
|
|
27169
27192
|
paths: ["id"]
|
|
@@ -28556,6 +28579,7 @@ var SamvaOperations = {
|
|
|
28556
28579
|
webhooksRetryDelivery: operationMetadata96,
|
|
28557
28580
|
webhooksGetLogs: operationMetadata95,
|
|
28558
28581
|
webhooksRegenerateSecret: operationMetadata96,
|
|
28582
|
+
webhooksGetSecret: operationMetadata97,
|
|
28559
28583
|
webhooksGetStats: operationMetadata97,
|
|
28560
28584
|
webhooksTest: operationMetadata96,
|
|
28561
28585
|
whoamiGet: {
|
|
@@ -28802,6 +28826,7 @@ var ApiKey = /* @__PURE__ */ Struct({
|
|
|
28802
28826
|
name: String4,
|
|
28803
28827
|
key: optionalKey2(Union2([String4, Null2])),
|
|
28804
28828
|
start: Union2([String4, Null2]),
|
|
28829
|
+
end: Union2([String4, Null2]),
|
|
28805
28830
|
description: optionalKey2(Union2([String4, Null2])),
|
|
28806
28831
|
createdAt: String4,
|
|
28807
28832
|
expiresAt: Union2([String4, Null2]),
|
|
@@ -28815,6 +28840,7 @@ var ApiKeyWithSecret = /* @__PURE__ */ Struct({
|
|
|
28815
28840
|
name: String4,
|
|
28816
28841
|
key: SensitiveString,
|
|
28817
28842
|
start: Union2([String4, Null2]),
|
|
28843
|
+
end: Union2([String4, Null2]),
|
|
28818
28844
|
description: optionalKey2(Union2([String4, Null2])),
|
|
28819
28845
|
createdAt: String4,
|
|
28820
28846
|
expiresAt: Union2([String4, Null2]),
|
|
@@ -29066,7 +29092,7 @@ var parseGrant = (raw) => {
|
|
|
29066
29092
|
if (resource === "mailboxes") {
|
|
29067
29093
|
return new CliUsageError({
|
|
29068
29094
|
code: "invalid_grant",
|
|
29069
|
-
message: "--grant does not cover mailboxes; mailbox
|
|
29095
|
+
message: "--grant does not cover mailboxes; use --mailbox-permission <action> (with optional --mailbox and --send-mode) instead."
|
|
29070
29096
|
});
|
|
29071
29097
|
}
|
|
29072
29098
|
if (!isLevelResource(resource) || !isGrantLevel(level)) {
|
|
@@ -29083,19 +29109,52 @@ var parseGrant = (raw) => {
|
|
|
29083
29109
|
}
|
|
29084
29110
|
return { resource, level };
|
|
29085
29111
|
};
|
|
29086
|
-
var
|
|
29087
|
-
|
|
29112
|
+
var repeated = (values) => values.find((value, index) => values.indexOf(value) !== index);
|
|
29113
|
+
var mailboxAccessFromFlags = (flags) => gen2(function* () {
|
|
29114
|
+
if (flags.permissions.length === 0) {
|
|
29115
|
+
if (flags.mailboxIds.length > 0 || isSome2(flags.sendMode)) {
|
|
29116
|
+
return yield* new CliUsageError({
|
|
29117
|
+
code: "mailbox_permission_required",
|
|
29118
|
+
message: `--mailbox and --send-mode narrow mailbox access; also pass --mailbox-permission ${API_KEY_MAILBOX_ACTIONS.join("|")}.`
|
|
29119
|
+
});
|
|
29120
|
+
}
|
|
29121
|
+
return;
|
|
29122
|
+
}
|
|
29123
|
+
const duplicatePermission = repeated(flags.permissions);
|
|
29124
|
+
if (duplicatePermission !== undefined) {
|
|
29125
|
+
return yield* new CliUsageError({
|
|
29126
|
+
code: "invalid_mailbox_access",
|
|
29127
|
+
message: `--mailbox-permission names ${duplicatePermission} more than once.`
|
|
29128
|
+
});
|
|
29129
|
+
}
|
|
29130
|
+
const duplicateMailbox = repeated(flags.mailboxIds);
|
|
29131
|
+
if (duplicateMailbox !== undefined) {
|
|
29132
|
+
return yield* new CliUsageError({
|
|
29133
|
+
code: "invalid_mailbox_access",
|
|
29134
|
+
message: `--mailbox names ${duplicateMailbox} more than once.`
|
|
29135
|
+
});
|
|
29136
|
+
}
|
|
29137
|
+
return {
|
|
29138
|
+
permissions: flags.permissions,
|
|
29139
|
+
...flags.mailboxIds.length > 0 ? { mailboxIds: flags.mailboxIds } : {},
|
|
29140
|
+
...isSome2(flags.sendMode) ? { sendMode: flags.sendMode.value } : {}
|
|
29141
|
+
};
|
|
29142
|
+
});
|
|
29143
|
+
var accessFromFlags = (grants, fullAccess, mailbox, namespace) => gen2(function* () {
|
|
29144
|
+
const restrictedFlags = grants.length > 0 || mailbox.permissions.length > 0 || mailbox.mailboxIds.length > 0 || isSome2(mailbox.sendMode) || isSome2(namespace);
|
|
29145
|
+
if (fullAccess && restrictedFlags) {
|
|
29088
29146
|
return yield* new CliUsageError({
|
|
29089
29147
|
code: "access_conflict",
|
|
29090
|
-
message: "Pass either --full-access or --grant
|
|
29148
|
+
message: "Pass either --full-access or restricted access (--grant, --mailbox-permission, --namespace), not both."
|
|
29091
29149
|
});
|
|
29092
29150
|
}
|
|
29093
29151
|
if (fullAccess)
|
|
29094
29152
|
return { mode: "full" };
|
|
29095
|
-
|
|
29153
|
+
const mailboxes = yield* mailboxAccessFromFlags(mailbox);
|
|
29154
|
+
if (grants.length === 0 && mailboxes === undefined) {
|
|
29096
29155
|
return yield* new CliUsageError({
|
|
29097
29156
|
code: "access_required",
|
|
29098
|
-
message: "Choose the key's access: --full-access, or one or more --grant <resource>=read|write
|
|
29157
|
+
message: "Choose the key's access: --full-access, or one or more --grant <resource>=read|write and/or --mailbox-permission <action>."
|
|
29099
29158
|
});
|
|
29100
29159
|
}
|
|
29101
29160
|
const resources = {};
|
|
@@ -29111,7 +29170,12 @@ var accessFromFlags = (grants, fullAccess) => gen2(function* () {
|
|
|
29111
29170
|
}
|
|
29112
29171
|
resources[grant.resource] = grant.level;
|
|
29113
29172
|
}
|
|
29114
|
-
return {
|
|
29173
|
+
return {
|
|
29174
|
+
mode: "restricted",
|
|
29175
|
+
resources,
|
|
29176
|
+
...mailboxes === undefined ? {} : { mailboxes },
|
|
29177
|
+
...isSome2(namespace) ? { namespaceId: namespace.value } : {}
|
|
29178
|
+
};
|
|
29115
29179
|
});
|
|
29116
29180
|
var parseExpiresAt = (raw) => Number.isNaN(Date.parse(raw)) ? fail6(new CliUsageError({
|
|
29117
29181
|
code: "invalid_expires_at",
|
|
@@ -29125,7 +29189,12 @@ var describeAccess = (access) => {
|
|
|
29125
29189
|
return "full";
|
|
29126
29190
|
const grants = Object.entries(access.resources).filter(([, level]) => level !== undefined).map(([resource, level]) => `${resource}:${level}`);
|
|
29127
29191
|
if (access.mailboxes !== undefined && access.mailboxes !== null) {
|
|
29128
|
-
|
|
29192
|
+
const { permissions, mailboxIds, sendMode } = access.mailboxes;
|
|
29193
|
+
const scope = [
|
|
29194
|
+
...mailboxIds === undefined || mailboxIds === null ? [] : [mailboxIds.join("+")],
|
|
29195
|
+
...sendMode === undefined || sendMode === "send" ? [] : [`${sendMode} sends`]
|
|
29196
|
+
];
|
|
29197
|
+
grants.push(`mailboxes:${permissions.join("+")}${scope.length === 0 ? "" : ` [${scope.join("; ")}]`}`);
|
|
29129
29198
|
}
|
|
29130
29199
|
if (access.namespaceId !== undefined && access.namespaceId !== null)
|
|
29131
29200
|
grants.push(`namespace:${access.namespaceId}`);
|
|
@@ -29204,11 +29273,19 @@ var create2 = make29("create", {
|
|
|
29204
29273
|
description: String9("description").pipe(withDescription2("What the key is for"), optional4),
|
|
29205
29274
|
expiresAt: String9("expires-at").pipe(withDescription2("When the key stops working, an ISO 8601 instant"), optional4),
|
|
29206
29275
|
grant: String9("grant").pipe(withDescription2(`Give a restricted key a resource at a level, <resource>=read|write (repeatable). Resources: ${GRANTABLE_RESOURCES.join(", ")}`), atLeast2(0)),
|
|
29207
|
-
|
|
29276
|
+
mailboxPermission: Literals3("mailbox-permission", API_KEY_MAILBOX_ACTIONS).pipe(withDescription2(`Let a restricted key work in mailboxes with this action (repeatable): ${API_KEY_MAILBOX_ACTIONS.join(", ")}`), atLeast2(0)),
|
|
29277
|
+
mailbox: String9("mailbox").pipe(withSchema2(MailboxId), withDescription2("Confine the mailbox access to this mailbox (repeatable); omit for every mailbox the owner reaches"), atLeast2(0)),
|
|
29278
|
+
sendMode: Literals3("send-mode", mailboxSendModes).pipe(withDescription2("With approval, each send waits until a person other than the key approves it (default send)"), optional4),
|
|
29279
|
+
namespace: String9("namespace").pipe(withSchema2(NamespaceId), withDescription2("Confine a restricted key to one namespace (ns_...)"), optional4),
|
|
29280
|
+
fullAccess: Boolean6("full-access").pipe(withDescription2("Give the key its owner's full access instead of restricted access"), withDefault5(false)),
|
|
29208
29281
|
dryRun: dryRunFlag,
|
|
29209
29282
|
json: jsonFlag
|
|
29210
29283
|
}).pipe(withDescription3("Create an API key. The secret is shown once; the API refuses access you do not hold."), withExamples([
|
|
29211
29284
|
{ command: "samva api-keys create --name ci --grant email=write --dry-run" },
|
|
29285
|
+
{
|
|
29286
|
+
command: "samva api-keys create --name agent --mailbox-permission read --mailbox-permission send --mailbox mbx_1234567890123456 --send-mode approval",
|
|
29287
|
+
description: "A key that works in one mailbox and needs a person to approve each send"
|
|
29288
|
+
},
|
|
29212
29289
|
{
|
|
29213
29290
|
command: "samva api-keys create --name ci --grant email=write --json | jq -r .data.key",
|
|
29214
29291
|
description: "Pipe the secret into another tool"
|
|
@@ -29216,8 +29293,20 @@ var create2 = make29("create", {
|
|
|
29216
29293
|
{
|
|
29217
29294
|
command: "samva api-keys create --name deploy --full-access --expires-at 2027-01-01T00:00:00Z"
|
|
29218
29295
|
}
|
|
29219
|
-
]), withHandler(({
|
|
29220
|
-
|
|
29296
|
+
]), withHandler(({
|
|
29297
|
+
name,
|
|
29298
|
+
description,
|
|
29299
|
+
expiresAt,
|
|
29300
|
+
grant,
|
|
29301
|
+
mailboxPermission,
|
|
29302
|
+
mailbox,
|
|
29303
|
+
sendMode,
|
|
29304
|
+
namespace,
|
|
29305
|
+
fullAccess,
|
|
29306
|
+
dryRun,
|
|
29307
|
+
json
|
|
29308
|
+
}) => withJsonQuiet(json, gen2(function* () {
|
|
29309
|
+
const access = yield* accessFromFlags(grant, fullAccess, { permissions: mailboxPermission, mailboxIds: mailbox, sendMode }, namespace);
|
|
29221
29310
|
const expires = yield* match(expiresAt, {
|
|
29222
29311
|
onNone: () => void_3,
|
|
29223
29312
|
onSome: parseExpiresAt
|
|
@@ -29233,7 +29322,11 @@ var create2 = make29("create", {
|
|
|
29233
29322
|
});
|
|
29234
29323
|
if (dryRun) {
|
|
29235
29324
|
if (json) {
|
|
29236
|
-
return yield* printJson({
|
|
29325
|
+
return yield* printJson({
|
|
29326
|
+
dryRun: true,
|
|
29327
|
+
action: "api-keys.create",
|
|
29328
|
+
request: payload
|
|
29329
|
+
});
|
|
29237
29330
|
}
|
|
29238
29331
|
return yield* printFields([
|
|
29239
29332
|
["Action", "api-keys.create"],
|
|
@@ -29256,13 +29349,17 @@ var update3 = make29("update", {
|
|
|
29256
29349
|
id: idArgument,
|
|
29257
29350
|
name: String9("name").pipe(withDescription2("New key name"), optional4),
|
|
29258
29351
|
description: String9("description").pipe(withDescription2("New description"), optional4),
|
|
29352
|
+
sendMode: Literals3("send-mode", mailboxSendModes).pipe(withDescription2("Change a mailbox key's send mode: approval holds each send for a person other than the key, send releases them. Takes a person signed in with samva login"), optional4),
|
|
29259
29353
|
dryRun: dryRunFlag,
|
|
29260
29354
|
json: jsonFlag
|
|
29261
|
-
}).pipe(withDescription3("Rename an API key or change
|
|
29262
|
-
|
|
29355
|
+
}).pipe(withDescription3("Rename an API key, change its description, or change a mailbox key's send mode. Its other access is fixed at creation; create a new key to change it."), withExamples([
|
|
29356
|
+
{ command: "samva api-keys update key_abc123 --name ci-prod --dry-run" },
|
|
29357
|
+
{ command: "samva api-keys update key_abc123 --send-mode approval" }
|
|
29358
|
+
]), withHandler(({ id, name, description, sendMode, dryRun, json }) => withJsonQuiet(json, gen2(function* () {
|
|
29359
|
+
if (isNone2(name) && isNone2(description) && isNone2(sendMode)) {
|
|
29263
29360
|
return yield* new CliUsageError({
|
|
29264
29361
|
code: "update_required",
|
|
29265
|
-
message: "Pass --name, --description, or
|
|
29362
|
+
message: "Pass --name, --description, --send-mode, or a combination."
|
|
29266
29363
|
});
|
|
29267
29364
|
}
|
|
29268
29365
|
const payload = yield* decodeRequest(ApiKeysUpdateRequestJson, {
|
|
@@ -29270,6 +29367,10 @@ var update3 = make29("update", {
|
|
|
29270
29367
|
...match(description, {
|
|
29271
29368
|
onNone: () => ({}),
|
|
29272
29369
|
onSome: (value) => ({ description: value })
|
|
29370
|
+
}),
|
|
29371
|
+
...match(sendMode, {
|
|
29372
|
+
onNone: () => ({}),
|
|
29373
|
+
onSome: (value) => ({ mailboxes: { sendMode: value } })
|
|
29273
29374
|
})
|
|
29274
29375
|
});
|
|
29275
29376
|
if (dryRun) {
|
|
@@ -29285,7 +29386,8 @@ var update3 = make29("update", {
|
|
|
29285
29386
|
["Action", "api-keys.update"],
|
|
29286
29387
|
["API key", id],
|
|
29287
29388
|
["Name", payload.name],
|
|
29288
|
-
["Description", payload.description]
|
|
29389
|
+
["Description", payload.description],
|
|
29390
|
+
["Send mode", payload.mailboxes?.sendMode]
|
|
29289
29391
|
]);
|
|
29290
29392
|
}
|
|
29291
29393
|
const client = yield* getClientProvider;
|
|
@@ -54128,6 +54230,7 @@ var CampaignLatestRun = /* @__PURE__ */ Struct({
|
|
|
54128
54230
|
dispatchedCount: Finite.check(isFinite4().annotate({ expected: "a finite number" })),
|
|
54129
54231
|
failedCount: Finite.check(isFinite4().annotate({ expected: "a finite number" })),
|
|
54130
54232
|
skippedCount: Finite.check(isFinite4().annotate({ expected: "a finite number" })),
|
|
54233
|
+
pendingCount: Finite.check(isFinite4().annotate({ expected: "a finite number" })),
|
|
54131
54234
|
estimatedCompletionAt: Union2([String4, Null2])
|
|
54132
54235
|
}).annotate({ identifier: "CampaignLatestRun" });
|
|
54133
54236
|
var CampaignRecipientPage = /* @__PURE__ */ Struct({
|
|
@@ -54226,11 +54329,14 @@ var CampaignRun = /* @__PURE__ */ Struct({
|
|
|
54226
54329
|
dispatchedCount: Finite.check(isFinite4().annotate({ expected: "a finite number" })),
|
|
54227
54330
|
failedCount: Finite.check(isFinite4().annotate({ expected: "a finite number" })),
|
|
54228
54331
|
skippedCount: Finite.check(isFinite4().annotate({ expected: "a finite number" })),
|
|
54332
|
+
pendingCount: Finite.check(isFinite4().annotate({ expected: "a finite number" })),
|
|
54229
54333
|
skippedReasons: ArraySchema(CampaignRunSkippedReason),
|
|
54230
54334
|
estimatedCompletionAt: Union2([String4, Null2]),
|
|
54231
54335
|
failureReason: Union2([String4, Null2]),
|
|
54232
54336
|
holdReason: Union2([String4, Null2]),
|
|
54233
54337
|
holdDomainId: Union2([EmailDomainId2, Null2]),
|
|
54338
|
+
holdUntil: Union2([String4, Null2]),
|
|
54339
|
+
capacityWarning: Union2([String4, Null2]),
|
|
54234
54340
|
lastContactId: Union2([String4, Null2]),
|
|
54235
54341
|
createdBy: Union2([String4, Null2]),
|
|
54236
54342
|
actorEmail: String4,
|
|
@@ -54581,6 +54687,23 @@ var resumeRun = /* @__PURE__ */ make42("campaignsResumeRun");
|
|
|
54581
54687
|
var cancelRun = /* @__PURE__ */ make42("campaignsCancelRun");
|
|
54582
54688
|
var listRecipients = /* @__PURE__ */ make42("campaignsListRecipients");
|
|
54583
54689
|
|
|
54690
|
+
// src/lib/run-hold.ts
|
|
54691
|
+
var WHATSAPP_MESSAGING_LIMIT_HOLD = "whatsapp_messaging_limit";
|
|
54692
|
+
var holdLabel = (reason) => reason === null || reason === undefined ? null : reason === WHATSAPP_MESSAGING_LIMIT_HOLD ? `${reason} (the number's messaging limit; the run resumes on its own)` : reason;
|
|
54693
|
+
var holdFields = (run) => [
|
|
54694
|
+
["Held", holdLabel(run.holdReason)],
|
|
54695
|
+
["Resumes at", run.holdUntil]
|
|
54696
|
+
];
|
|
54697
|
+
var campaignPacingFields = (run, options) => [
|
|
54698
|
+
...holdFields(run),
|
|
54699
|
+
[
|
|
54700
|
+
"Pending",
|
|
54701
|
+
run.pendingCount !== undefined && (run.pendingCount > 0 || run.holdReason != null) ? String(run.pendingCount) : null
|
|
54702
|
+
],
|
|
54703
|
+
["Est. completion", run.estimatedCompletionAt],
|
|
54704
|
+
...options.warning ? [["Capacity warning", run.capacityWarning]] : []
|
|
54705
|
+
];
|
|
54706
|
+
|
|
54584
54707
|
// src/lib/template-reference.ts
|
|
54585
54708
|
var publicationIdFlag = String9("publication-id").pipe(withDescription2("Pin one exact publication, so nothing published later changes what this renders"), optional4);
|
|
54586
54709
|
var inputContractIdFlag = String9("input-contract-id").pipe(withDescription2("Follow the newest publication that still validates input identically to this contract"), optional4);
|
|
@@ -55053,7 +55176,7 @@ var archive2 = make29("archive", {
|
|
|
55053
55176
|
["Definition", data.definition.state]
|
|
55054
55177
|
]);
|
|
55055
55178
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
55056
|
-
var printRun = (run) => printFields([
|
|
55179
|
+
var printRun = (run, options = { warning: true }) => printFields([
|
|
55057
55180
|
["Run ID", run.id],
|
|
55058
55181
|
["Campaign", run.campaignId],
|
|
55059
55182
|
["Status", run.status],
|
|
@@ -55068,8 +55191,10 @@ var printRun = (run) => printFields([
|
|
|
55068
55191
|
"Skipped by reason",
|
|
55069
55192
|
(run.skippedReasons ?? []).map(({ reason, count }) => `${reason} ${count}`).join(", ")
|
|
55070
55193
|
],
|
|
55071
|
-
["Failure", run.failureReason]
|
|
55194
|
+
["Failure", run.failureReason],
|
|
55195
|
+
...campaignPacingFields(run, options)
|
|
55072
55196
|
]);
|
|
55197
|
+
var warnCapacity = (run) => run.capacityWarning ? error(`Warning: ${run.capacityWarning}`) : void_3;
|
|
55073
55198
|
var runCreate = make29("create", {
|
|
55074
55199
|
campaignId: String10("campaignId"),
|
|
55075
55200
|
at: atFlag,
|
|
@@ -55108,7 +55233,8 @@ var runCreate = make29("create", {
|
|
|
55108
55233
|
return yield* printJson(data);
|
|
55109
55234
|
yield* logInfo(`Run scheduled.
|
|
55110
55235
|
`);
|
|
55111
|
-
yield* printRun(data);
|
|
55236
|
+
yield* printRun(data, { warning: false });
|
|
55237
|
+
yield* warnCapacity(data);
|
|
55112
55238
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
55113
55239
|
var runList = make29("list", {
|
|
55114
55240
|
campaignId: String10("campaignId"),
|
|
@@ -66402,7 +66528,7 @@ var refusalNext = (failure) => {
|
|
|
66402
66528
|
case "ForbiddenError":
|
|
66403
66529
|
return "Use a credential that may read mailboxes and follow the API message.";
|
|
66404
66530
|
case "ResourceNotFoundError":
|
|
66405
|
-
return "Run samva mailboxes list to find the mailboxes this credential can read, then retry with those
|
|
66531
|
+
return "Run samva mailboxes list to find the mailboxes this credential can read, then retry with those mailbox ids.";
|
|
66406
66532
|
case "CursorExpiredError":
|
|
66407
66533
|
return "Events after your cursor expired. Read current state from the API and reconnect without --cursor.";
|
|
66408
66534
|
case "ValidationError":
|
|
@@ -66529,12 +66655,16 @@ var tailEvents = (options) => gen2(function* () {
|
|
|
66529
66655
|
})), mapError4(streamError), options.limit === undefined ? (stream) => stream : take3(options.limit), interruptWhen2(interrupted), runForEach2(options.onEvent), raceFirst2(interrupted.pipe(andThen2(sleep2(HANDLER_DRAIN)))))));
|
|
66530
66656
|
});
|
|
66531
66657
|
var mailboxesEventsCommand = make29("events", {
|
|
66658
|
+
mailbox: String10("mailbox-id").pipe(withDescription4("Mailboxes to follow; omit to follow every mailbox the credential reads"), withSchema3(MailboxId), atLeast3(0)),
|
|
66532
66659
|
cursor: String9("cursor").pipe(withDescription2("Replay events after a cursor from an earlier event frame, then go live"), optional4),
|
|
66533
|
-
mailbox: String9("mailbox").pipe(withSchema2(MailboxId), atLeast2(0)),
|
|
66534
66660
|
limit: Int5("limit").pipe(optional4),
|
|
66535
66661
|
noReconnect: Boolean6("no-reconnect").pipe(withDefault5(false), withDescription2("Exit non-zero with the last cursor when the connection drops, instead of reconnecting from it"))
|
|
66536
66662
|
}).pipe(withDescription3("Tail mailbox events, one record per line; --jsonl wraps each in a result envelope; a dropped connection reconnects from the last cursor; Ctrl+C exits cleanly"), withExamples([
|
|
66537
|
-
{ command: "samva mailboxes events
|
|
66663
|
+
{ command: "samva mailboxes events mbx_1234567890123456 --limit 10" },
|
|
66664
|
+
{
|
|
66665
|
+
command: "samva mailboxes events mbx_1234567890123456 mbx_6543210987654321 --jsonl",
|
|
66666
|
+
description: "Follow several mailboxes"
|
|
66667
|
+
},
|
|
66538
66668
|
{ command: "samva mailboxes events --jsonl", description: "Stream envelopes for automation" },
|
|
66539
66669
|
{ command: "samva mailboxes events --cursor <cursor-from-an-event-frame>" },
|
|
66540
66670
|
{
|
|
@@ -67054,6 +67184,18 @@ class WhatsAppTemplateIneligibleError extends TaggedError3()("WhatsAppTemplateIn
|
|
|
67054
67184
|
message: String4
|
|
67055
67185
|
}, { httpApiStatus: 422 }) {
|
|
67056
67186
|
}
|
|
67187
|
+
|
|
67188
|
+
class WhatsAppSetupLinkUnavailableError extends TaggedError3()("WhatsAppSetupLinkUnavailableError", {
|
|
67189
|
+
reason: Literals(["completed", "revoked", "expired"]),
|
|
67190
|
+
message: String4
|
|
67191
|
+
}, { httpApiStatus: 410 }) {
|
|
67192
|
+
static new(reason) {
|
|
67193
|
+
return new WhatsAppSetupLinkUnavailableError({
|
|
67194
|
+
reason,
|
|
67195
|
+
message: reason === "completed" ? "This setup link already connected a WhatsApp number. Ask for a new link to connect another." : reason === "revoked" ? "This setup link was revoked. Ask for a new link." : "This setup link expired. Ask for a new link."
|
|
67196
|
+
});
|
|
67197
|
+
}
|
|
67198
|
+
}
|
|
67057
67199
|
var EmailChannelErrorReason = Literals([
|
|
67058
67200
|
"transport",
|
|
67059
67201
|
"rejected",
|
|
@@ -67596,6 +67738,8 @@ var JourneyRun = /* @__PURE__ */ Struct({
|
|
|
67596
67738
|
exitReason: Union2([JourneyRunExitReason, Null2]),
|
|
67597
67739
|
failureReason: Union2([String4, Null2]),
|
|
67598
67740
|
currentNodeId: Union2([JourneyNodeId, Null2]),
|
|
67741
|
+
holdReason: Union2([String4, Null2]),
|
|
67742
|
+
holdUntil: Union2([String4, Null2]),
|
|
67599
67743
|
trigger: JourneyRunTrigger,
|
|
67600
67744
|
enteredAt: String4,
|
|
67601
67745
|
endedAt: Union2([String4, Null2])
|
|
@@ -67619,6 +67763,8 @@ var JourneyRunDetail = /* @__PURE__ */ Struct({
|
|
|
67619
67763
|
exitReason: Union2([JourneyRunExitReason, Null2]),
|
|
67620
67764
|
failureReason: Union2([String4, Null2]),
|
|
67621
67765
|
currentNodeId: Union2([JourneyNodeId, Null2]),
|
|
67766
|
+
holdReason: Union2([String4, Null2]),
|
|
67767
|
+
holdUntil: Union2([String4, Null2]),
|
|
67622
67768
|
trigger: JourneyRunTrigger,
|
|
67623
67769
|
enteredAt: String4,
|
|
67624
67770
|
endedAt: Union2([String4, Null2]),
|
|
@@ -68247,6 +68393,7 @@ var printRun2 = (run) => printFields([
|
|
|
68247
68393
|
["Exit reason", run.exitReason],
|
|
68248
68394
|
["Failure", run.failureReason],
|
|
68249
68395
|
["Current node", run.currentNodeId],
|
|
68396
|
+
...holdFields(run),
|
|
68250
68397
|
["Entered", run.enteredAt],
|
|
68251
68398
|
["Ended", run.endedAt]
|
|
68252
68399
|
]);
|
|
@@ -71573,7 +71720,7 @@ var decodeThreadPage = decoder3(WireThreadPage, "thread page");
|
|
|
71573
71720
|
var decodeMessage = decoder3(WireMessage, "message");
|
|
71574
71721
|
|
|
71575
71722
|
// src/commands/mailboxes.ts
|
|
71576
|
-
var
|
|
71723
|
+
var mailboxIdArgument = String10("mailbox-id").pipe(withSchema3(MailboxId));
|
|
71577
71724
|
var messageIdArgument = String10("message-id").pipe(withSchema3(MessageId));
|
|
71578
71725
|
var optional6 = (name) => String9(name).pipe(optional4);
|
|
71579
71726
|
var pageFlags2 = {
|
|
@@ -71616,7 +71763,7 @@ var chatContent = (channel, flags) => gen2(function* () {
|
|
|
71616
71763
|
}
|
|
71617
71764
|
if (channel !== "whatsapp")
|
|
71618
71765
|
return yield* usage2("mailbox_chat_template", "A template sends on WhatsApp only.");
|
|
71619
|
-
const templateId = yield*
|
|
71766
|
+
const templateId = yield* decodeEffect2(TemplateId)(flags.template.value).pipe(mapError2(() => usage2("mailbox_chat_template", "--template must be an approved template id (tmpl_\u2026).")));
|
|
71620
71767
|
const dataText = getOrUndefined(flags.data);
|
|
71621
71768
|
if (dataText === undefined)
|
|
71622
71769
|
return { templateId };
|
|
@@ -71734,7 +71881,6 @@ var create9 = make29("create", {
|
|
|
71734
71881
|
return yield* printJson(data);
|
|
71735
71882
|
yield* printMailbox(data);
|
|
71736
71883
|
})));
|
|
71737
|
-
var mailboxIdArgument = String10("mailbox-id").pipe(withSchema3(MailboxId));
|
|
71738
71884
|
var get22 = make29("get", { id: mailboxIdArgument, json: jsonFlag }).pipe(withDescription3("Inspect a mailbox's endpoints and settings"), withHandler(({ id, json }) => gen2(function* () {
|
|
71739
71885
|
const raw = yield* getMailboxJson("Could not read mailbox", `/v1/mailboxes/${id}`);
|
|
71740
71886
|
const result = yield* decodeMailbox(raw);
|
|
@@ -71793,7 +71939,7 @@ var update9 = make29("update", {
|
|
|
71793
71939
|
yield* json ? printJson(result) : printMailbox(result);
|
|
71794
71940
|
})));
|
|
71795
71941
|
var endpointAdd = make29("add", {
|
|
71796
|
-
mailbox:
|
|
71942
|
+
mailbox: mailboxIdArgument,
|
|
71797
71943
|
channel: channelFlag2,
|
|
71798
71944
|
address: String9("address").pipe(withDescription2("The address to add: an email address such as billing@acme.samva.email, or on whatsapp and sms a number you connected, in E.164 form such as +14155550123")),
|
|
71799
71945
|
displayName: String9("display-name").pipe(withDescription2("The sender name messages from this endpoint carry"), optional4),
|
|
@@ -71801,10 +71947,10 @@ var endpointAdd = make29("add", {
|
|
|
71801
71947
|
json: jsonFlag
|
|
71802
71948
|
}).pipe(withDescription3("Add an endpoint on a channel (email by default) to a mailbox"), withExamples([
|
|
71803
71949
|
{
|
|
71804
|
-
command: "samva mailboxes endpoints add
|
|
71950
|
+
command: "samva mailboxes endpoints add mbx_1234567890123456 --address billing@acme.samva.email"
|
|
71805
71951
|
},
|
|
71806
71952
|
{
|
|
71807
|
-
command: "samva mailboxes endpoints add
|
|
71953
|
+
command: "samva mailboxes endpoints add mbx_1234567890123456 --channel whatsapp --address +14155550123",
|
|
71808
71954
|
description: "Add a connected WhatsApp number"
|
|
71809
71955
|
}
|
|
71810
71956
|
]), withHandler(({ mailbox, channel, address, displayName, dryRun, json }) => gen2(function* () {
|
|
@@ -71836,8 +71982,8 @@ var endpointAdd = make29("add", {
|
|
|
71836
71982
|
})));
|
|
71837
71983
|
var endpointIdArgument = String10("endpoint-id").pipe(withSchema3(MailboxEndpointId));
|
|
71838
71984
|
var endpointUpdate = make29("update", {
|
|
71985
|
+
mailbox: mailboxIdArgument,
|
|
71839
71986
|
endpointId: endpointIdArgument,
|
|
71840
|
-
mailbox: mailboxFlag,
|
|
71841
71987
|
displayName: String9("display-name").pipe(withDescription2("The sender name messages from this endpoint carry"), optional4),
|
|
71842
71988
|
clearDisplayName: Boolean6("clear-display-name").pipe(withDescription2("Send under the mailbox's name again"), withDefault5(false)),
|
|
71843
71989
|
makeDefault: Boolean6("default").pipe(withDescription2("Start new conversations from this endpoint on its channel"), withDefault5(false)),
|
|
@@ -71845,7 +71991,7 @@ var endpointUpdate = make29("update", {
|
|
|
71845
71991
|
json: jsonFlag
|
|
71846
71992
|
}).pipe(withDescription3("Rename an endpoint's sender or make it the mailbox's default"), withExamples([
|
|
71847
71993
|
{
|
|
71848
|
-
command: 'samva mailboxes endpoints update mbxep_1234567890123456 --
|
|
71994
|
+
command: 'samva mailboxes endpoints update mbx_1234567890123456 mbxep_1234567890123456 --display-name "Acme Billing" --default'
|
|
71849
71995
|
}
|
|
71850
71996
|
]), withHandler(({ endpointId, mailbox, displayName, clearDisplayName, makeDefault, dryRun, json }) => gen2(function* () {
|
|
71851
71997
|
if (isSome2(displayName) && clearDisplayName)
|
|
@@ -71879,14 +72025,14 @@ var endpointUpdate = make29("update", {
|
|
|
71879
72025
|
yield* json ? printJson(result) : printMailbox(result);
|
|
71880
72026
|
})));
|
|
71881
72027
|
var endpointRemove = make29("remove", {
|
|
72028
|
+
mailbox: mailboxIdArgument,
|
|
71882
72029
|
endpointId: endpointIdArgument,
|
|
71883
|
-
mailbox: mailboxFlag,
|
|
71884
72030
|
dryRun: Boolean6("dry-run").pipe(withDefault5(false)),
|
|
71885
72031
|
yes: Boolean6("yes").pipe(withDefault5(false)),
|
|
71886
72032
|
json: jsonFlag
|
|
71887
72033
|
}).pipe(withDescription3("Remove an endpoint from a mailbox; mail sent to it stops reaching the mailbox"), withExamples([
|
|
71888
72034
|
{
|
|
71889
|
-
command: "samva mailboxes endpoints remove mbxep_1234567890123456 --
|
|
72035
|
+
command: "samva mailboxes endpoints remove mbx_1234567890123456 mbxep_1234567890123456 --yes"
|
|
71890
72036
|
}
|
|
71891
72037
|
]), withHandler(({ endpointId, mailbox, dryRun, yes, json }) => gen2(function* () {
|
|
71892
72038
|
if (dryRun)
|
|
@@ -71918,7 +72064,7 @@ var lifecycle = (verb) => make29(verb, {
|
|
|
71918
72064
|
yield* json ? printJson(result) : printMailbox(result);
|
|
71919
72065
|
})));
|
|
71920
72066
|
var actionsList = make29("list", {
|
|
71921
|
-
mailbox:
|
|
72067
|
+
mailbox: mailboxIdArgument,
|
|
71922
72068
|
...pageFlags2,
|
|
71923
72069
|
state: Literals3("state", MailboxActionState.literals).pipe(optional4),
|
|
71924
72070
|
after: instantFlag("after", "Only actions created after this ISO 8601 instant"),
|
|
@@ -71943,8 +72089,8 @@ var actionsList = make29("list", {
|
|
|
71943
72089
|
});
|
|
71944
72090
|
})));
|
|
71945
72091
|
var actionDecision = (verb) => make29(verb, {
|
|
72092
|
+
mailbox: mailboxIdArgument,
|
|
71946
72093
|
actionId: String10("action-id").pipe(withSchema3(MailboxActionId)),
|
|
71947
|
-
mailbox: mailboxFlag,
|
|
71948
72094
|
...verb === "deny" ? {
|
|
71949
72095
|
reason: optional6("reason").pipe(withDescription2("Denial reason; defaults to Denied by reviewer."))
|
|
71950
72096
|
} : {},
|
|
@@ -71999,7 +72145,7 @@ var remove9 = make29("remove", {
|
|
|
71999
72145
|
yield* log(`Removed mailbox ${id}. The messages it received stay with the organization.`);
|
|
72000
72146
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
72001
72147
|
var threads = make29("threads", {
|
|
72002
|
-
mailbox:
|
|
72148
|
+
mailbox: mailboxIdArgument,
|
|
72003
72149
|
...pageFlags2,
|
|
72004
72150
|
query: optional6("query"),
|
|
72005
72151
|
folder: Literals3("folder", MailboxThreadFolder2.literals).pipe(optional4),
|
|
@@ -72010,37 +72156,35 @@ var threads = make29("threads", {
|
|
|
72010
72156
|
before: instantFlag("before", "Only threads whose last activity is before this ISO 8601 instant"),
|
|
72011
72157
|
json: jsonFlag
|
|
72012
72158
|
}).pipe(withDescription3("Search and list mailbox threads"), withExamples([
|
|
72013
|
-
{ command: "samva mailboxes threads
|
|
72159
|
+
{ command: "samva mailboxes threads mbx_1234567890123456 --query invoice --json" },
|
|
72014
72160
|
{
|
|
72015
|
-
command: "samva mailboxes threads
|
|
72161
|
+
command: "samva mailboxes threads mbx_1234567890123456 --starred --after 2026-10-01T00:00:00Z"
|
|
72016
72162
|
},
|
|
72017
|
-
{ command: "samva mailboxes threads
|
|
72018
|
-
]), withHandler(({ mailbox, limit, cursor, all, query, folder, label, unread, starred, after, before, json }) =>
|
|
72019
|
-
|
|
72020
|
-
|
|
72021
|
-
|
|
72022
|
-
|
|
72023
|
-
|
|
72024
|
-
|
|
72025
|
-
|
|
72026
|
-
|
|
72027
|
-
|
|
72028
|
-
|
|
72029
|
-
|
|
72030
|
-
|
|
72031
|
-
|
|
72032
|
-
|
|
72033
|
-
|
|
72034
|
-
|
|
72035
|
-
human: printThread
|
|
72036
|
-
});
|
|
72163
|
+
{ command: "samva mailboxes threads mbx_1234567890123456 --all --jsonl" }
|
|
72164
|
+
]), withHandler(({ mailbox, limit, cursor, all, query, folder, label, unread, starred, after, before, json }) => followPages({
|
|
72165
|
+
all,
|
|
72166
|
+
json,
|
|
72167
|
+
cursor,
|
|
72168
|
+
page: (pageCursor) => getMailboxJson("Could not list threads", `/v1/mailboxes/${mailbox}/threads${searchParams({
|
|
72169
|
+
cursor: pageCursor,
|
|
72170
|
+
limit: pageLimit(limit),
|
|
72171
|
+
q: getOrUndefined(query),
|
|
72172
|
+
folder: getOrUndefined(folder),
|
|
72173
|
+
label: getOrUndefined(label),
|
|
72174
|
+
unread: unread ? "true" : undefined,
|
|
72175
|
+
starred: starred ? "true" : undefined,
|
|
72176
|
+
after: getOrUndefined(after),
|
|
72177
|
+
before: getOrUndefined(before)
|
|
72178
|
+
})}`).pipe(flatMap3(decodeThreadPage)),
|
|
72179
|
+
empty: "No threads found.",
|
|
72180
|
+
human: printThread
|
|
72037
72181
|
})));
|
|
72038
72182
|
var read2 = make29("read", {
|
|
72183
|
+
mailbox: mailboxIdArgument,
|
|
72039
72184
|
messageId: messageIdArgument,
|
|
72040
|
-
mailbox: mailboxFlag,
|
|
72041
72185
|
json: jsonFlag
|
|
72042
72186
|
}).pipe(withDescription3("Read a mailbox message"), withExamples([
|
|
72043
|
-
{ command: "samva mailboxes read msg_1234567890123456 --
|
|
72187
|
+
{ command: "samva mailboxes read mbx_1234567890123456 msg_1234567890123456 --json" }
|
|
72044
72188
|
]), withHandler(({ messageId, mailbox, json }) => gen2(function* () {
|
|
72045
72189
|
const raw = yield* getMailboxJson("Could not read message", `/v1/mailboxes/${mailbox}/messages/${messageId}`);
|
|
72046
72190
|
const data = yield* decodeMessage(raw);
|
|
@@ -72049,7 +72193,7 @@ var read2 = make29("read", {
|
|
|
72049
72193
|
yield* printMessage2(data);
|
|
72050
72194
|
})));
|
|
72051
72195
|
var send7 = make29("send", {
|
|
72052
|
-
mailbox:
|
|
72196
|
+
mailbox: mailboxIdArgument,
|
|
72053
72197
|
channel: channelFlag2,
|
|
72054
72198
|
to: String9("to").pipe(withDescription2("Recipient email address (repeatable), or one phone number in E.164 form"), atLeast2(1)),
|
|
72055
72199
|
subject: String9("subject").pipe(withDescription2("Email only"), optional4),
|
|
@@ -72060,14 +72204,14 @@ var send7 = make29("send", {
|
|
|
72060
72204
|
json: jsonFlag
|
|
72061
72205
|
}).pipe(withDescription3("Send a message from a mailbox: email by default, or to one phone number with --channel whatsapp or sms"), withExamples([
|
|
72062
72206
|
{
|
|
72063
|
-
command: 'samva mailboxes send
|
|
72207
|
+
command: 'samva mailboxes send mbx_1234567890123456 --to recipient@example.com --subject Hello --text "Hello"'
|
|
72064
72208
|
},
|
|
72065
72209
|
{
|
|
72066
|
-
command: `samva mailboxes send
|
|
72210
|
+
command: `samva mailboxes send mbx_1234567890123456 --channel whatsapp --to +14155550123 --template tmpl_1234567890123456 --data '{"name":"Ada"}'`,
|
|
72067
72211
|
description: "Open a WhatsApp conversation with an approved template"
|
|
72068
72212
|
},
|
|
72069
72213
|
{
|
|
72070
|
-
command: 'samva mailboxes send
|
|
72214
|
+
command: 'samva mailboxes send mbx_1234567890123456 --channel sms --to +14155550123 --text "Your order shipped."'
|
|
72071
72215
|
}
|
|
72072
72216
|
]), withHandler(({
|
|
72073
72217
|
mailbox,
|
|
@@ -72119,18 +72263,18 @@ var send7 = make29("send", {
|
|
|
72119
72263
|
})));
|
|
72120
72264
|
var messageChannel = (mailbox, messageId) => getMailboxJson("Could not read message", `/v1/mailboxes/${mailbox}/messages/${messageId}`).pipe(flatMap3((raw) => decodeUnknownEffect2(Struct({ channel: Literals(["email", "whatsapp", "sms"]) }))(raw).pipe(map7(({ channel }) => channel), mapError2(() => new SamvaCliError({ message: "The API answered with an unreadable message." })))));
|
|
72121
72265
|
var reply2 = make29("reply", {
|
|
72266
|
+
mailbox: mailboxIdArgument,
|
|
72122
72267
|
messageId: messageIdArgument,
|
|
72123
|
-
mailbox: mailboxFlag,
|
|
72124
72268
|
...bodyFlags,
|
|
72125
72269
|
...chatOnlyFlags,
|
|
72126
72270
|
all: Boolean6("all").pipe(withDefault5(false)),
|
|
72127
72271
|
json: jsonFlag
|
|
72128
72272
|
}).pipe(withDescription3("Reply to a message; --all includes the other recipients. A WhatsApp or SMS message is answered on its thread, with --text or a WhatsApp --template"), withExamples([
|
|
72129
72273
|
{
|
|
72130
|
-
command: 'samva mailboxes reply msg_1234567890123456 --
|
|
72274
|
+
command: 'samva mailboxes reply mbx_1234567890123456 msg_1234567890123456 --text "Thanks" --all'
|
|
72131
72275
|
},
|
|
72132
72276
|
{
|
|
72133
|
-
command: "samva mailboxes reply msg_1234567890123456 --
|
|
72277
|
+
command: "samva mailboxes reply mbx_1234567890123456 msg_1234567890123456 --template tmpl_1234567890123456",
|
|
72134
72278
|
description: "Answer a WhatsApp thread whose 24-hour service window has closed"
|
|
72135
72279
|
}
|
|
72136
72280
|
]), withHandler(({ messageId, mailbox, text, html, template, data, idempotencyKey, all, json }) => gen2(function* () {
|
|
@@ -72158,8 +72302,8 @@ var reply2 = make29("reply", {
|
|
|
72158
72302
|
})));
|
|
72159
72303
|
var actionIdArgument = String10("action-id").pipe(withSchema3(MailboxActionId));
|
|
72160
72304
|
var actionGet = make29("get", {
|
|
72305
|
+
mailbox: mailboxIdArgument,
|
|
72161
72306
|
actionId: actionIdArgument,
|
|
72162
|
-
mailbox: mailboxFlag,
|
|
72163
72307
|
json: jsonFlag
|
|
72164
72308
|
}).pipe(withDescription3("Read a mailbox action and its current send progress"), withHandler(({ actionId, mailbox, json }) => gen2(function* () {
|
|
72165
72309
|
const client = yield* getClientProvider;
|
|
@@ -72169,8 +72313,8 @@ var actionGet = make29("get", {
|
|
|
72169
72313
|
yield* printAction(data);
|
|
72170
72314
|
})));
|
|
72171
72315
|
var actionCancel = make29("cancel", {
|
|
72316
|
+
mailbox: mailboxIdArgument,
|
|
72172
72317
|
actionId: actionIdArgument,
|
|
72173
|
-
mailbox: mailboxFlag,
|
|
72174
72318
|
json: jsonFlag
|
|
72175
72319
|
}).pipe(withDescription3("Cancel an unaccepted send as a permitted person signed in with samva login"), withHandler(({ actionId, mailbox, json }) => gen2(function* () {
|
|
72176
72320
|
const client = yield* getClientProvider;
|
|
@@ -72184,8 +72328,8 @@ var actionCancel = make29("cancel", {
|
|
|
72184
72328
|
]);
|
|
72185
72329
|
})));
|
|
72186
72330
|
var actionRetry = make29("retry", {
|
|
72331
|
+
mailbox: mailboxIdArgument,
|
|
72187
72332
|
actionId: actionIdArgument,
|
|
72188
|
-
mailbox: mailboxFlag,
|
|
72189
72333
|
json: jsonFlag
|
|
72190
72334
|
}).pipe(withDescription3("Resume an eligible ended execution as a permitted person; preserves content and deadline"), withHandler(({ actionId, mailbox, json }) => gen2(function* () {
|
|
72191
72335
|
const client = yield* getClientProvider;
|
|
@@ -72199,14 +72343,14 @@ var actionRetry = make29("retry", {
|
|
|
72199
72343
|
]);
|
|
72200
72344
|
})));
|
|
72201
72345
|
var quarantineList = make29("list", {
|
|
72202
|
-
mailbox:
|
|
72346
|
+
mailbox: mailboxIdArgument,
|
|
72203
72347
|
...pageFlags2,
|
|
72204
72348
|
after: instantFlag("after", "Only messages held after this ISO 8601 instant"),
|
|
72205
72349
|
before: instantFlag("before", "Only messages held before this ISO 8601 instant"),
|
|
72206
72350
|
json: jsonFlag
|
|
72207
72351
|
}).pipe(withDescription3("List held messages without their bodies"), withExamples([
|
|
72208
|
-
{ command: "samva mailboxes quarantine list
|
|
72209
|
-
{ command: "samva mailboxes quarantine list
|
|
72352
|
+
{ command: "samva mailboxes quarantine list mbx_1234567890123456 --json" },
|
|
72353
|
+
{ command: "samva mailboxes quarantine list mbx_1234567890123456 --all --jsonl" }
|
|
72210
72354
|
]), withHandler(({ mailbox, limit, cursor, all, after, before, json }) => gen2(function* () {
|
|
72211
72355
|
const client = yield* getClientProvider;
|
|
72212
72356
|
yield* followPages({
|
|
@@ -72225,12 +72369,12 @@ var quarantineList = make29("list", {
|
|
|
72225
72369
|
});
|
|
72226
72370
|
})));
|
|
72227
72371
|
var release2 = make29("release", {
|
|
72372
|
+
mailbox: mailboxIdArgument,
|
|
72228
72373
|
messageId: messageIdArgument,
|
|
72229
|
-
mailbox: mailboxFlag,
|
|
72230
72374
|
json: jsonFlag
|
|
72231
72375
|
}).pipe(withDescription3("Release a held message as a person signed in with samva login"), withExamples([
|
|
72232
72376
|
{
|
|
72233
|
-
command: "samva mailboxes quarantine release msg_1234567890123456
|
|
72377
|
+
command: "samva mailboxes quarantine release mbx_1234567890123456 msg_1234567890123456"
|
|
72234
72378
|
}
|
|
72235
72379
|
]), withHandler(({ messageId, mailbox, json }) => gen2(function* () {
|
|
72236
72380
|
const client = yield* getClientProvider;
|
|
@@ -72242,12 +72386,12 @@ var release2 = make29("release", {
|
|
|
72242
72386
|
var discard = make29("discard", {
|
|
72243
72387
|
dryRun: Boolean6("dry-run").pipe(withDefault5(false)),
|
|
72244
72388
|
yes: Boolean6("yes").pipe(withDefault5(false)),
|
|
72389
|
+
mailbox: mailboxIdArgument,
|
|
72245
72390
|
messageId: messageIdArgument,
|
|
72246
|
-
mailbox: mailboxFlag,
|
|
72247
72391
|
json: jsonFlag
|
|
72248
72392
|
}).pipe(withDescription3("Discard a held message for good as a person signed in with samva login"), withExamples([
|
|
72249
72393
|
{
|
|
72250
|
-
command: "samva mailboxes quarantine discard msg_1234567890123456
|
|
72394
|
+
command: "samva mailboxes quarantine discard mbx_1234567890123456 msg_1234567890123456"
|
|
72251
72395
|
}
|
|
72252
72396
|
]), withHandler(({ messageId, mailbox, dryRun, yes, json }) => gen2(function* () {
|
|
72253
72397
|
if (dryRun)
|
|
@@ -73772,7 +73916,8 @@ var TemplateFamilyId2 = /* @__PURE__ */ String4.check(isPattern2(/* @__PURE__ */
|
|
|
73772
73916
|
var VersionCursor2 = /* @__PURE__ */ String4.annotate({ identifier: "VersionCursor" });
|
|
73773
73917
|
var BrandFooterBlock = /* @__PURE__ */ Struct({
|
|
73774
73918
|
html: String4,
|
|
73775
|
-
text: String4
|
|
73919
|
+
text: String4,
|
|
73920
|
+
headCss: optionalKey2(Union2([String4, Null2]))
|
|
73776
73921
|
}).annotate({ identifier: "BrandFooterBlock" });
|
|
73777
73922
|
var TemplatePublicationRender = /* @__PURE__ */ Struct({
|
|
73778
73923
|
subject: String4,
|
|
@@ -73815,7 +73960,8 @@ var TemplateSummary = /* @__PURE__ */ Struct({
|
|
|
73815
73960
|
name: String4,
|
|
73816
73961
|
channel: Literal2("email"),
|
|
73817
73962
|
projectId: TemplateProjectId2,
|
|
73818
|
-
namespaceId: Union2([NamespaceId2, Null2]).annotate({ description: "The namespace the template's project belongs to; every entry in a project shares it. Null at organization level. A namespace-scoped key reaches only its own namespace's templates." }),
|
|
73963
|
+
namespaceId: Union2([NamespaceId2, Null2]).annotate({ description: "The namespace the template's project belongs to; every entry in a project shares it. Null at organization level. A namespace-scoped key reaches only its own namespace's templates and shared ones." }),
|
|
73964
|
+
shared: Boolean3.annotate({ description: "Whether the template's project is shared with every namespace. Every entry in a project shares it. A namespace-scoped key reads and sends a shared template in its own namespace but cannot change it. Only an organization-level project is shared." }),
|
|
73819
73965
|
entryPath: String4.check(isMaxCodePoints(1024).annotate({ expected: "a string with at most 1024 code points" })).check(isPattern2(/* @__PURE__ */ new RegExp("^(?!\\/)(?!.*\\\\)(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))(?!.*(?:^|\\/)\\.git(?:\\/|$))(?:templates|emails)\\/.+\\.tsx$", "u")).annotate({ expected: "a string matching the RegExp ^(?!\\/)(?!.*\\\\)(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))(?!.*(?:^|\\/)\\.git(?:\\/|$))(?:templates|emails)\\/.+\\.tsx$" })).check(isMaxLength(1024).annotate({ expected: "a value with a length of at most 1024" })),
|
|
73820
73966
|
status: Union2([
|
|
73821
73967
|
Literal2("draft"),
|
|
@@ -73840,7 +73986,8 @@ var Template = /* @__PURE__ */ Struct({
|
|
|
73840
73986
|
name: String4,
|
|
73841
73987
|
channel: Literal2("email"),
|
|
73842
73988
|
projectId: TemplateProjectId2,
|
|
73843
|
-
namespaceId: Union2([NamespaceId2, Null2]).annotate({ description: "The namespace the template's project belongs to; every entry in a project shares it. Null at organization level. A namespace-scoped key reaches only its own namespace's templates." }),
|
|
73989
|
+
namespaceId: Union2([NamespaceId2, Null2]).annotate({ description: "The namespace the template's project belongs to; every entry in a project shares it. Null at organization level. A namespace-scoped key reaches only its own namespace's templates and shared ones." }),
|
|
73990
|
+
shared: Boolean3.annotate({ description: "Whether the template's project is shared with every namespace. Every entry in a project shares it. A namespace-scoped key reads and sends a shared template in its own namespace but cannot change it. Only an organization-level project is shared." }),
|
|
73844
73991
|
entryPath: String4.check(isMaxCodePoints(1024).annotate({ expected: "a string with at most 1024 code points" })).check(isPattern2(/* @__PURE__ */ new RegExp("^(?!\\/)(?!.*\\\\)(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))(?!.*(?:^|\\/)\\.git(?:\\/|$))(?:templates|emails)\\/.+\\.tsx$", "u")).annotate({ expected: "a string matching the RegExp ^(?!\\/)(?!.*\\\\)(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))(?!.*(?:^|\\/)\\.git(?:\\/|$))(?:templates|emails)\\/.+\\.tsx$" })).check(isMaxLength(1024).annotate({ expected: "a value with a length of at most 1024" })),
|
|
73845
73992
|
status: Union2([
|
|
73846
73993
|
Literal2("draft"),
|
|
@@ -73925,7 +74072,8 @@ var TemplatesListQuery = /* @__PURE__ */ Struct({
|
|
|
73925
74072
|
]), Null2])),
|
|
73926
74073
|
search: optionalKey2(Union2([String4, Null2])),
|
|
73927
74074
|
projectId: optionalKey2(Union2([TemplateProjectId2, Null2])),
|
|
73928
|
-
namespaceId: optionalKey2(Union2([NamespaceId2, Null2]).annotate({ description: "Only templates
|
|
74075
|
+
namespaceId: optionalKey2(Union2([NamespaceId2, Null2]).annotate({ description: "Only the templates this namespace uses: its own and those shared with every namespace (add `shared=false` for its own only). A namespace-scoped key lists its own namespace's and shared templates." })),
|
|
74076
|
+
shared: optionalKey2(Union2([Union2([Literal2("true"), Literal2("false")]), Null2]).annotate({ description: "Only templates whose project is shared with every namespace (true), or only unshared ones (false)." }))
|
|
73929
74077
|
});
|
|
73930
74078
|
var TemplatesList200 = TemplatePage;
|
|
73931
74079
|
var TemplatesList401 = UnauthorizedError2;
|
|
@@ -73951,6 +74099,7 @@ var TemplatesCreateRequestJson = /* @__PURE__ */ Struct({
|
|
|
73951
74099
|
]), Null2]), Null2])),
|
|
73952
74100
|
isActive: optionalKey2(Union2([Boolean3, Null2])),
|
|
73953
74101
|
namespaceId: optionalKey2(Union2([NamespaceId2, Null2]).annotate({ description: "The namespace the new template project belongs to; the project and every entry added to it share it. Omit for organization level. A namespace-scoped key always creates in its own namespace." })),
|
|
74102
|
+
shared: optionalKey2(Union2([Boolean3, Null2]).annotate({ description: "Share the new organization-level project with every namespace: namespace-scoped keys read and send its entries but cannot change them. Defaults to false. Not with `namespaceId`, and not from a namespace-scoped key." })),
|
|
73954
74103
|
idempotencyKey: String4.check(isMinLength(1).annotate({ expected: "a value with a length of at least 1" })).check(isMaxCodePoints(255).annotate({ expected: "a string with at most 255 code points" })).check(isMaxLength(255).annotate({ expected: "a value with a length of at most 255" }))
|
|
73955
74104
|
});
|
|
73956
74105
|
var TemplatesCreate201 = Template;
|
|
@@ -73994,7 +74143,8 @@ var TemplatesUpdateRequestJson = /* @__PURE__ */ Struct({ data: Struct({
|
|
|
73994
74143
|
]), Null2]), Null2])),
|
|
73995
74144
|
fromDefault: optionalKey2(Union2([Union2([TemplateFromDefault, Null2]), Null2])),
|
|
73996
74145
|
replyToDefault: optionalKey2(Union2([Union2([ArraySchema(String4), Null2]), Null2])),
|
|
73997
|
-
isActive: optionalKey2(Union2([Boolean3, Null2]))
|
|
74146
|
+
isActive: optionalKey2(Union2([Boolean3, Null2])),
|
|
74147
|
+
shared: optionalKey2(Union2([Boolean3, Null2]).annotate({ description: "Share the template's project with every namespace, or stop sharing it. Applies to every entry in the project. Only an organization-level project is shared." }))
|
|
73998
74148
|
}) });
|
|
73999
74149
|
var TemplatesUpdate200 = Template;
|
|
74000
74150
|
var TemplatesUpdate401 = UnauthorizedError2;
|
|
@@ -75659,7 +75809,7 @@ var TemplatesGroup = class extends make37("Templates").add(get5("templatesList",
|
|
|
75659
75809
|
TemplatesPublish500,
|
|
75660
75810
|
TemplatesPublish504.pipe(status(504))
|
|
75661
75811
|
]
|
|
75662
|
-
}).middleware(ApiKeySecurityMiddleware).annotate(Identifier, "templates.publish").annotate(Summary, "Publish an exact template commit").annotate(Description, "Builds an exact Git commit and entry path, stores the immutable compiled IR and its assets, records the input contract it validates against, and makes that publication current."), get5("templatesGetPublication", "/v1/templates/:id/publications/:publicationId", {
|
|
75812
|
+
}).middleware(ApiKeySecurityMiddleware).annotate(Identifier, "templates.publish").annotate(Summary, "Publish an exact template commit").annotate(Description, "Builds an exact Git commit and entry path, stores the immutable compiled IR and its assets, records the input contract it validates against, and makes that publication current. A commit that compiles to the same build as an existing publication makes that publication current again instead of recording another."), get5("templatesGetPublication", "/v1/templates/:id/publications/:publicationId", {
|
|
75663
75813
|
params: TemplatesGetPublicationPathParams,
|
|
75664
75814
|
success: TemplatesGetPublication200,
|
|
75665
75815
|
error: [
|
|
@@ -78981,6 +79131,11 @@ var WebhookDailyDeliveries = /* @__PURE__ */ Struct({
|
|
|
78981
79131
|
exhausted: Finite.check(isInt().annotate({ expected: "an integer" })).check(isGreaterThanOrEqualTo2(0).annotate({ expected: "a value greater than or equal to 0" })),
|
|
78982
79132
|
cancelled: Finite.check(isInt().annotate({ expected: "an integer" })).check(isGreaterThanOrEqualTo2(0).annotate({ expected: "a value greater than or equal to 0" }))
|
|
78983
79133
|
}).annotate({ identifier: "WebhookDailyDeliveries" });
|
|
79134
|
+
var WebhookSigningSecret = /* @__PURE__ */ Struct({
|
|
79135
|
+
secret: SensitiveString,
|
|
79136
|
+
createdAt: String4,
|
|
79137
|
+
previousExpiresAt: Union2([String4, Null2])
|
|
79138
|
+
}).annotate({ identifier: "WebhookSigningSecret" });
|
|
78984
79139
|
var WebhookEndpoint = /* @__PURE__ */ Struct({
|
|
78985
79140
|
id: WebhookEndpointId2,
|
|
78986
79141
|
name: String4,
|
|
@@ -79309,6 +79464,14 @@ var WebhooksRegenerateSecret404 = ResourceNotFoundError2;
|
|
|
79309
79464
|
var WebhooksRegenerateSecret422 = ValidationError2;
|
|
79310
79465
|
var WebhooksRegenerateSecret500 = InternalError2;
|
|
79311
79466
|
var WebhooksRegenerateSecret504 = GatewayTimeoutError2;
|
|
79467
|
+
var WebhooksGetSecretPathParams = /* @__PURE__ */ Struct({ id: WebhookEndpointId2 });
|
|
79468
|
+
var WebhooksGetSecret200 = WebhookSigningSecret;
|
|
79469
|
+
var WebhooksGetSecret401 = UnauthorizedError2;
|
|
79470
|
+
var WebhooksGetSecret403 = ForbiddenError2;
|
|
79471
|
+
var WebhooksGetSecret404 = ResourceNotFoundError2;
|
|
79472
|
+
var WebhooksGetSecret422 = ValidationError2;
|
|
79473
|
+
var WebhooksGetSecret500 = InternalError2;
|
|
79474
|
+
var WebhooksGetSecret504 = GatewayTimeoutError2;
|
|
79312
79475
|
var WebhooksGetStatsPathParams = /* @__PURE__ */ Struct({ id: WebhookEndpointId2 });
|
|
79313
79476
|
var WebhooksGetStatsQuery = /* @__PURE__ */ Struct({
|
|
79314
79477
|
after: optionalKey2(Union2([String4, Null2])),
|
|
@@ -79358,7 +79521,7 @@ var WebhooksGroup = class extends make37("Webhooks").add(get5("webhooksList", "/
|
|
|
79358
79521
|
WebhooksCreate502.pipe(status(502)),
|
|
79359
79522
|
WebhooksCreate504.pipe(status(504))
|
|
79360
79523
|
]
|
|
79361
|
-
}).middleware(ApiKeySecurityMiddleware).annotate(Identifier, "webhooks.create").annotate(Summary, "Create a webhook").annotate(Description, "Creates a signed webhook endpoint for Samva delivery and inbound events, stores subscriptions, and returns the endpoint and signing secret with a 201 response. `
|
|
79524
|
+
}).middleware(ApiKeySecurityMiddleware).annotate(Identifier, "webhooks.create").annotate(Summary, "Create a webhook").annotate(Description, "Creates a signed webhook endpoint for Samva delivery and inbound events, stores subscriptions, and returns the endpoint and signing secret with a 201 response. `namespaceId` confines the endpoint to one namespace's events and `mailboxIds` to those mailboxes' events; when both are set, every mailbox must belong to the namespace."), get5("webhooksGet", "/v1/webhooks/:id", {
|
|
79362
79525
|
params: WebhooksGetPathParams,
|
|
79363
79526
|
success: WebhooksGet200,
|
|
79364
79527
|
error: [
|
|
@@ -79429,7 +79592,18 @@ var WebhooksGroup = class extends make37("Webhooks").add(get5("webhooksList", "/
|
|
|
79429
79592
|
WebhooksRegenerateSecret500,
|
|
79430
79593
|
WebhooksRegenerateSecret504.pipe(status(504))
|
|
79431
79594
|
]
|
|
79432
|
-
}).middleware(ApiKeySecurityMiddleware).annotate(Identifier, "webhooks.regenerateSecret").annotate(Summary, "Rotate a webhook signing secret").annotate(Description, "Generates and returns a new signing secret. The previous secret remains valid for a 24-hour rotation overlap."), get5("
|
|
79595
|
+
}).middleware(ApiKeySecurityMiddleware).annotate(Identifier, "webhooks.regenerateSecret").annotate(Summary, "Rotate a webhook signing secret").annotate(Description, "Generates and returns a new signing secret. The previous secret remains valid for a 24-hour rotation overlap."), get5("webhooksGetSecret", "/v1/webhooks/:id/secret", {
|
|
79596
|
+
params: WebhooksGetSecretPathParams,
|
|
79597
|
+
success: WebhooksGetSecret200,
|
|
79598
|
+
error: [
|
|
79599
|
+
WebhooksGetSecret401.pipe(status(401)),
|
|
79600
|
+
WebhooksGetSecret403.pipe(status(403)),
|
|
79601
|
+
WebhooksGetSecret404.pipe(status(404)),
|
|
79602
|
+
WebhooksGetSecret422.pipe(status(422)),
|
|
79603
|
+
WebhooksGetSecret500,
|
|
79604
|
+
WebhooksGetSecret504.pipe(status(504))
|
|
79605
|
+
]
|
|
79606
|
+
}).middleware(ApiKeySecurityMiddleware).annotate(Identifier, "webhooks.getSecret").annotate(Summary, "Get a webhook signing secret").annotate(Description, "Returns the endpoint's current signing secret and when a rotated-out secret stops verifying. It needs the same permission as rotating the secret."), get5("webhooksGetStats", "/v1/webhooks/:id/stats", {
|
|
79433
79607
|
params: WebhooksGetStatsPathParams,
|
|
79434
79608
|
query: WebhooksGetStatsQuery,
|
|
79435
79609
|
success: WebhooksGetStats200,
|
|
@@ -79460,6 +79634,7 @@ var WebhooksGroup = class extends make37("Webhooks").add(get5("webhooksList", "/
|
|
|
79460
79634
|
var make55 = /* @__PURE__ */ forGroup(WebhooksGroup);
|
|
79461
79635
|
var list27 = /* @__PURE__ */ make55("webhooksList");
|
|
79462
79636
|
var create16 = /* @__PURE__ */ make55("webhooksCreate");
|
|
79637
|
+
var getSecret = /* @__PURE__ */ make55("webhooksGetSecret");
|
|
79463
79638
|
var get28 = /* @__PURE__ */ make55("webhooksGet");
|
|
79464
79639
|
var remove14 = /* @__PURE__ */ make55("webhooksRemove");
|
|
79465
79640
|
var update13 = /* @__PURE__ */ make55("webhooksUpdate");
|
|
@@ -79549,6 +79724,18 @@ var get29 = make29("get", { id: idArgument4, json: jsonFlag }).pipe(withDescript
|
|
|
79549
79724
|
["URL", data.url]
|
|
79550
79725
|
]);
|
|
79551
79726
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
79727
|
+
var secret = make29("secret", { id: idArgument4, json: jsonFlag }).pipe(withDescription3("Read the current webhook signing secret (requires webhooks:update)"), withExamples([{ command: "samva webhooks secret wep_abc123 --json" }]), withHandler(({ id, json }) => gen2(function* () {
|
|
79728
|
+
const client = yield* getClientProvider;
|
|
79729
|
+
const data = yield* getSecret({ id }).pipe(client.provide, mapError2((error) => toCliApiError("Could not read webhook signing secret", error)));
|
|
79730
|
+
if (json)
|
|
79731
|
+
return yield* printJson({ ...data, secret: value2(data.secret) });
|
|
79732
|
+
yield* printFields([
|
|
79733
|
+
["Signing secret", value2(data.secret)],
|
|
79734
|
+
["Created at", data.createdAt]
|
|
79735
|
+
]);
|
|
79736
|
+
if (data.previousExpiresAt !== null)
|
|
79737
|
+
yield* log(`The previous secret keeps verifying until ${data.previousExpiresAt}.`);
|
|
79738
|
+
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
79552
79739
|
var logs = make29("logs", {
|
|
79553
79740
|
id: idArgument4,
|
|
79554
79741
|
limit: Int5("limit").pipe(optional4),
|
|
@@ -79706,15 +79893,15 @@ var rotate3 = make29("rotate-secret", {
|
|
|
79706
79893
|
yield* confirmDestructive({
|
|
79707
79894
|
yes,
|
|
79708
79895
|
json,
|
|
79709
|
-
message: `Rotate the signing secret for webhook ${id}? The
|
|
79896
|
+
message: `Rotate the signing secret for webhook ${id}? The previous secret keeps verifying for 24 hours.`,
|
|
79710
79897
|
nonInteractiveMessage: "Secret rotation requires --yes in non-interactive mode. Preview with --dry-run."
|
|
79711
79898
|
});
|
|
79712
79899
|
const client = yield* getClientProvider;
|
|
79713
79900
|
const data = yield* regenerateSecret({ id }).pipe(client.provide, mapError2((error) => toCliApiError("Could not rotate webhook secret", error)));
|
|
79714
|
-
const warning =
|
|
79901
|
+
const warning = `Read this signing secret again with samva webhooks secret ${id}. The previous secret remains valid for 24 hours.`;
|
|
79715
79902
|
const secret = value2(data.secret);
|
|
79716
79903
|
if (json)
|
|
79717
|
-
return yield* printJson({ secret,
|
|
79904
|
+
return yield* printJson({ secret, warning });
|
|
79718
79905
|
yield* error(`WARNING: ${warning}`);
|
|
79719
79906
|
yield* log(secret);
|
|
79720
79907
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
@@ -79735,10 +79922,10 @@ var create17 = make29("create", {
|
|
|
79735
79922
|
]);
|
|
79736
79923
|
const client = yield* getClientProvider;
|
|
79737
79924
|
const result = yield* create16(payload).pipe(client.provide, mapError2((error) => toCliApiError("Could not create webhook", error)));
|
|
79738
|
-
const warning =
|
|
79925
|
+
const warning = `Read this signing secret again with samva webhooks secret ${result.endpoint.id}.`;
|
|
79739
79926
|
const secret = value2(result.secret);
|
|
79740
79927
|
if (json)
|
|
79741
|
-
return yield* printJson({ endpoint: result.endpoint, secret,
|
|
79928
|
+
return yield* printJson({ endpoint: result.endpoint, secret, warning });
|
|
79742
79929
|
yield* error(`WARNING: ${warning}`);
|
|
79743
79930
|
yield* printFields([
|
|
79744
79931
|
["ID", result.endpoint.id],
|
|
@@ -79794,7 +79981,19 @@ var remove15 = make29("remove", {
|
|
|
79794
79981
|
return yield* printJson(result);
|
|
79795
79982
|
yield* log(`Removed webhook ${id}.`);
|
|
79796
79983
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
79797
|
-
var webhooksCommand = make29("webhooks").pipe(withDescription3("Inspect, test, and recover customer webhooks"), withExamples([{ command: "samva webhooks list --json" }]), withSubcommands([
|
|
79984
|
+
var webhooksCommand = make29("webhooks").pipe(withDescription3("Inspect, test, and recover customer webhooks"), withExamples([{ command: "samva webhooks list --json" }]), withSubcommands([
|
|
79985
|
+
list28,
|
|
79986
|
+
get29,
|
|
79987
|
+
secret,
|
|
79988
|
+
create17,
|
|
79989
|
+
update14,
|
|
79990
|
+
test2,
|
|
79991
|
+
logs,
|
|
79992
|
+
stats3,
|
|
79993
|
+
retry4,
|
|
79994
|
+
rotate3,
|
|
79995
|
+
remove15
|
|
79996
|
+
]));
|
|
79798
79997
|
|
|
79799
79998
|
// src/lib/root-commands.ts
|
|
79800
79999
|
var rootCommands = [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@samva/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Samva CLI — email and platform operations from your terminal",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -50,22 +50,22 @@
|
|
|
50
50
|
"@effect/vitest": "4.0.0",
|
|
51
51
|
"@samva/contracts": "0.0.0",
|
|
52
52
|
"@samva/core": "0.0.0",
|
|
53
|
-
"@samva/mailbox": "0.5.
|
|
53
|
+
"@samva/mailbox": "0.5.1",
|
|
54
54
|
"@samva/markup": "^0.13.1",
|
|
55
55
|
"@samva/vite": "^0.13.1",
|
|
56
56
|
"@types/node": "^26.6.2",
|
|
57
57
|
"better-auth": "1.7.5",
|
|
58
58
|
"effect": "4.0.0",
|
|
59
|
-
"samva": "0.
|
|
59
|
+
"samva": "0.21.0",
|
|
60
60
|
"typescript": "^7.0.2",
|
|
61
61
|
"vite": "~8.3.0",
|
|
62
62
|
"vitest": "^5.0.3"
|
|
63
63
|
},
|
|
64
64
|
"optionalDependencies": {
|
|
65
|
-
"@samva/cli-darwin-arm64": "0.
|
|
66
|
-
"@samva/cli-darwin-x64": "0.
|
|
67
|
-
"@samva/cli-linux-arm64": "0.
|
|
68
|
-
"@samva/cli-linux-x64": "0.
|
|
65
|
+
"@samva/cli-darwin-arm64": "0.18.0",
|
|
66
|
+
"@samva/cli-darwin-x64": "0.18.0",
|
|
67
|
+
"@samva/cli-linux-arm64": "0.18.0",
|
|
68
|
+
"@samva/cli-linux-x64": "0.18.0"
|
|
69
69
|
},
|
|
70
70
|
"engines": {
|
|
71
71
|
"node": ">=18"
|