@primitivedotdev/sdk 0.26.1 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +2 -2
  2. package/dist/api/index.js +3 -406
  3. package/dist/openapi/index.js +7631 -7
  4. package/package.json +6 -63
  5. package/bin/run.js +0 -20
  6. package/dist/api/generated/client/client.gen.js +0 -235
  7. package/dist/api/generated/client/index.js +0 -6
  8. package/dist/api/generated/client/types.gen.js +0 -2
  9. package/dist/api/generated/client/utils.gen.js +0 -228
  10. package/dist/api/generated/client.gen.js +0 -3
  11. package/dist/api/generated/core/auth.gen.js +0 -14
  12. package/dist/api/generated/core/bodySerializer.gen.js +0 -57
  13. package/dist/api/generated/core/params.gen.js +0 -100
  14. package/dist/api/generated/core/pathSerializer.gen.js +0 -106
  15. package/dist/api/generated/core/queryKeySerializer.gen.js +0 -92
  16. package/dist/api/generated/core/serverSentEvents.gen.js +0 -132
  17. package/dist/api/generated/core/types.gen.js +0 -2
  18. package/dist/api/generated/core/utils.gen.js +0 -87
  19. package/dist/api/generated/index.js +0 -2
  20. package/dist/api/generated/sdk.gen.js +0 -878
  21. package/dist/api/generated/types.gen.js +0 -2
  22. package/dist/api/verify-signature.js +0 -198
  23. package/dist/oclif/api-command.js +0 -755
  24. package/dist/oclif/auth.js +0 -223
  25. package/dist/oclif/commands/emails-latest.js +0 -185
  26. package/dist/oclif/commands/emails-poll.js +0 -121
  27. package/dist/oclif/commands/emails-wait.js +0 -171
  28. package/dist/oclif/commands/emails-watch.js +0 -165
  29. package/dist/oclif/commands/functions-deploy.js +0 -124
  30. package/dist/oclif/commands/functions-init.js +0 -256
  31. package/dist/oclif/commands/functions-redeploy.js +0 -113
  32. package/dist/oclif/commands/functions-set-secret.js +0 -213
  33. package/dist/oclif/commands/login.js +0 -237
  34. package/dist/oclif/commands/logout.js +0 -88
  35. package/dist/oclif/commands/send.js +0 -222
  36. package/dist/oclif/commands/whoami.js +0 -95
  37. package/dist/oclif/fish-completion.js +0 -87
  38. package/dist/oclif/index.js +0 -167
  39. package/dist/oclif/lint/raw-send-mail-fetch.js +0 -98
  40. package/dist/openapi/openapi.generated.js +0 -5754
  41. package/dist/openapi/operations.generated.js +0 -4626
  42. package/dist/parser/address-parser.js +0 -129
  43. package/dist/types.generated.js +0 -7
  44. package/dist/types.js +0 -53
  45. package/dist/webhook/errors.js +0 -224
  46. package/dist/webhook/received-email.js +0 -82
  47. package/oclif.manifest.json +0 -4380
@@ -1,171 +0,0 @@
1
- import { Command, Errors, Flags } from "@oclif/core";
2
- import { PrimitiveApiClient } from "../../api/index.js";
3
- import { extractErrorPayload, removeStaleSavedCredentialOnUnauthorized, writeErrorWithHints, } from "../api-command.js";
4
- import { resolveCliAuth } from "../auth.js";
5
- import { formatHeader, formatRow, pickIdWidth } from "./emails-latest.js";
6
- import { collectNewAcceptedEmails, DEFAULT_EMAIL_POLL_INTERVAL_SECONDS, DEFAULT_EMAIL_POLL_PAGE_SIZE, fetchEmailSearchPage, filtersFromFlags, MAX_EMAIL_POLL_PAGE_SIZE, sinceFromFlags, sleep, } from "./emails-poll.js";
7
- const DEFAULT_WAIT_TIMEOUT_SECONDS = 300;
8
- function cliError(message) {
9
- return new Errors.CLIError(message, { exit: 1 });
10
- }
11
- class EmailsWaitCommand extends Command {
12
- static description = "Poll until matching inbound emails arrive, printing each match as it is found.";
13
- static summary = "Wait for matching inbound emails";
14
- static examples = [
15
- "<%= config.bin %> emails wait --to test@example.com",
16
- "<%= config.bin %> emails wait --subject verify --number 5 --timeout 120",
17
- "<%= config.bin %> emails wait --q 'domain:example.com' --table",
18
- ];
19
- static flags = {
20
- "api-key": Flags.string({
21
- description: "Primitive API key (defaults to PRIMITIVE_API_KEY or saved `primitive login` credentials)",
22
- env: "PRIMITIVE_API_KEY",
23
- }),
24
- "api-base-url-1": Flags.string({
25
- description: "Override the primary API base URL. Internal testing only; not documented to customers.",
26
- env: "PRIMITIVE_API_BASE_URL_1",
27
- hidden: true,
28
- }),
29
- "api-base-url-2": Flags.string({
30
- description: "Override the attachments-supporting send host base URL. Internal testing only; not documented to customers.",
31
- env: "PRIMITIVE_API_BASE_URL_2",
32
- hidden: true,
33
- }),
34
- body: Flags.string({
35
- description: "Full-text body filter",
36
- }),
37
- domain: Flags.string({
38
- description: "Filter by inbound email domain",
39
- }),
40
- "domain-id": Flags.string({
41
- description: "Filter by domain UUID",
42
- }),
43
- from: Flags.string({
44
- description: "Filter by sender address or domain",
45
- }),
46
- "has-attachment": Flags.boolean({
47
- description: "Only match emails with one or more attachments",
48
- }),
49
- "include-existing": Flags.boolean({
50
- description: "Start from existing matching emails instead of only new arrivals",
51
- }),
52
- interval: Flags.integer({
53
- default: DEFAULT_EMAIL_POLL_INTERVAL_SECONDS,
54
- description: "Seconds to wait between empty polls",
55
- min: 1,
56
- }),
57
- number: Flags.integer({
58
- char: "n",
59
- default: 1,
60
- description: "Exit successfully after this many matching emails",
61
- min: 1,
62
- }),
63
- "page-size": Flags.integer({
64
- default: DEFAULT_EMAIL_POLL_PAGE_SIZE,
65
- description: `Emails to fetch per poll (1-${MAX_EMAIL_POLL_PAGE_SIZE})`,
66
- max: MAX_EMAIL_POLL_PAGE_SIZE,
67
- min: 1,
68
- }),
69
- q: Flags.string({
70
- description: "Full-text search DSL query",
71
- }),
72
- since: Flags.string({
73
- description: "Only match emails received on or after this date/time",
74
- }),
75
- "spam-score-gte": Flags.integer({
76
- description: "Only match emails with spam score greater than or equal to this value",
77
- }),
78
- "spam-score-lt": Flags.integer({
79
- description: "Only match emails with spam score below this value",
80
- }),
81
- subject: Flags.string({
82
- description: "Full-text subject filter",
83
- }),
84
- table: Flags.boolean({
85
- description: "Print a human-readable table instead of JSONL",
86
- }),
87
- timeout: Flags.integer({
88
- default: DEFAULT_WAIT_TIMEOUT_SECONDS,
89
- description: "Seconds to wait before exiting nonzero; 0 waits forever",
90
- min: 0,
91
- }),
92
- to: Flags.string({
93
- description: "Filter by recipient address or domain",
94
- }),
95
- };
96
- async run() {
97
- const { flags } = await this.parse(EmailsWaitCommand);
98
- const baseUrlOverridden = flags["api-base-url-1"] !== undefined ||
99
- flags["api-base-url-2"] !== undefined;
100
- const auth = resolveCliAuth({
101
- apiKey: flags["api-key"],
102
- apiBaseUrl1: flags["api-base-url-1"],
103
- apiBaseUrl2: flags["api-base-url-2"],
104
- configDir: this.config.configDir,
105
- });
106
- const apiClient = new PrimitiveApiClient({
107
- apiKey: auth.apiKey,
108
- apiBaseUrl1: auth.apiBaseUrl1,
109
- apiBaseUrl2: auth.apiBaseUrl2,
110
- });
111
- let since;
112
- try {
113
- since = sinceFromFlags(flags);
114
- }
115
- catch (error) {
116
- throw cliError(error instanceof Error ? error.message : String(error));
117
- }
118
- const filters = filtersFromFlags(flags);
119
- const deadline = flags.timeout === 0 ? null : Date.now() + flags.timeout * 1000;
120
- const idWidth = pickIdWidth(Boolean(process.stdout.isTTY));
121
- const seenIds = new Set();
122
- let cursor = null;
123
- let matched = 0;
124
- let headerPrinted = false;
125
- while (deadline === null || Date.now() < deadline) {
126
- const page = await fetchEmailSearchPage({
127
- apiClient,
128
- cursor,
129
- filters,
130
- pageSize: flags["page-size"],
131
- since,
132
- });
133
- if (!page.ok) {
134
- const payload = extractErrorPayload(page.error);
135
- writeErrorWithHints(payload);
136
- removeStaleSavedCredentialOnUnauthorized({
137
- auth,
138
- baseUrlOverridden,
139
- configDir: this.config.configDir,
140
- payload,
141
- });
142
- process.exitCode = 1;
143
- return;
144
- }
145
- cursor = page.cursor ?? cursor;
146
- for (const email of collectNewAcceptedEmails(page.rows, seenIds)) {
147
- if (flags.table) {
148
- if (!headerPrinted) {
149
- process.stderr.write(`${formatHeader(idWidth)}\n`);
150
- headerPrinted = true;
151
- }
152
- this.log(formatRow(email, idWidth));
153
- }
154
- else {
155
- this.log(JSON.stringify(email));
156
- }
157
- matched += 1;
158
- if (matched >= flags.number)
159
- return;
160
- }
161
- if (page.rows.length > 0)
162
- continue;
163
- if (deadline !== null && Date.now() >= deadline)
164
- break;
165
- await sleep(flags.interval * 1000);
166
- }
167
- process.stderr.write(`Timed out waiting for ${flags.number} matching email${flags.number === 1 ? "" : "s"}; received ${matched}.\n`);
168
- process.exitCode = 1;
169
- }
170
- }
171
- export default EmailsWaitCommand;
@@ -1,165 +0,0 @@
1
- import { Command, Errors, Flags } from "@oclif/core";
2
- import { PrimitiveApiClient } from "../../api/index.js";
3
- import { extractErrorPayload, removeStaleSavedCredentialOnUnauthorized, writeErrorWithHints, } from "../api-command.js";
4
- import { resolveCliAuth } from "../auth.js";
5
- import { formatHeader, formatRow, pickIdWidth } from "./emails-latest.js";
6
- import { collectNewAcceptedEmails, DEFAULT_EMAIL_POLL_INTERVAL_SECONDS, DEFAULT_EMAIL_POLL_PAGE_SIZE, fetchEmailSearchPage, filtersFromFlags, MAX_EMAIL_POLL_PAGE_SIZE, sinceFromFlags, sleep, } from "./emails-poll.js";
7
- function cliError(message) {
8
- return new Errors.CLIError(message, { exit: 1 });
9
- }
10
- class EmailsWatchCommand extends Command {
11
- static description = "Poll for new inbound emails and print matching messages as they arrive.";
12
- static summary = "Watch inbound emails with filters";
13
- static examples = [
14
- "<%= config.bin %> emails watch --to support@example.com",
15
- "<%= config.bin %> emails watch --subject verify --seconds 300",
16
- "<%= config.bin %> emails watch --number 20 --jsonl",
17
- ];
18
- static flags = {
19
- "api-key": Flags.string({
20
- description: "Primitive API key (defaults to PRIMITIVE_API_KEY or saved `primitive login` credentials)",
21
- env: "PRIMITIVE_API_KEY",
22
- }),
23
- "api-base-url-1": Flags.string({
24
- description: "Override the primary API base URL. Internal testing only; not documented to customers.",
25
- env: "PRIMITIVE_API_BASE_URL_1",
26
- hidden: true,
27
- }),
28
- "api-base-url-2": Flags.string({
29
- description: "Override the attachments-supporting send host base URL. Internal testing only; not documented to customers.",
30
- env: "PRIMITIVE_API_BASE_URL_2",
31
- hidden: true,
32
- }),
33
- body: Flags.string({
34
- description: "Full-text body filter",
35
- }),
36
- domain: Flags.string({
37
- description: "Filter by inbound email domain",
38
- }),
39
- "domain-id": Flags.string({
40
- description: "Filter by domain UUID",
41
- }),
42
- from: Flags.string({
43
- description: "Filter by sender address or domain",
44
- }),
45
- "has-attachment": Flags.boolean({
46
- description: "Only show emails with one or more attachments",
47
- }),
48
- "include-existing": Flags.boolean({
49
- description: "Start from existing matching emails instead of only new arrivals",
50
- }),
51
- interval: Flags.integer({
52
- default: DEFAULT_EMAIL_POLL_INTERVAL_SECONDS,
53
- description: "Seconds to wait between empty polls",
54
- min: 1,
55
- }),
56
- jsonl: Flags.boolean({
57
- description: "Print each email as one JSON object per line",
58
- }),
59
- number: Flags.integer({
60
- description: "Exit after printing this many matching emails",
61
- min: 1,
62
- }),
63
- "page-size": Flags.integer({
64
- default: DEFAULT_EMAIL_POLL_PAGE_SIZE,
65
- description: `Emails to fetch per poll (1-${MAX_EMAIL_POLL_PAGE_SIZE})`,
66
- max: MAX_EMAIL_POLL_PAGE_SIZE,
67
- min: 1,
68
- }),
69
- q: Flags.string({
70
- description: "Full-text search DSL query",
71
- }),
72
- seconds: Flags.integer({
73
- description: "Exit after this many seconds",
74
- min: 1,
75
- }),
76
- since: Flags.string({
77
- description: "Only show emails received on or after this date/time",
78
- }),
79
- "spam-score-gte": Flags.integer({
80
- description: "Only show emails with spam score greater than or equal to this value",
81
- }),
82
- "spam-score-lt": Flags.integer({
83
- description: "Only show emails with spam score below this value",
84
- }),
85
- subject: Flags.string({
86
- description: "Full-text subject filter",
87
- }),
88
- to: Flags.string({
89
- description: "Filter by recipient address or domain",
90
- }),
91
- };
92
- async run() {
93
- const { flags } = await this.parse(EmailsWatchCommand);
94
- const baseUrlOverridden = flags["api-base-url-1"] !== undefined ||
95
- flags["api-base-url-2"] !== undefined;
96
- const auth = resolveCliAuth({
97
- apiKey: flags["api-key"],
98
- apiBaseUrl1: flags["api-base-url-1"],
99
- apiBaseUrl2: flags["api-base-url-2"],
100
- configDir: this.config.configDir,
101
- });
102
- const apiClient = new PrimitiveApiClient({
103
- apiKey: auth.apiKey,
104
- apiBaseUrl1: auth.apiBaseUrl1,
105
- apiBaseUrl2: auth.apiBaseUrl2,
106
- });
107
- let since;
108
- try {
109
- since = sinceFromFlags(flags);
110
- }
111
- catch (error) {
112
- throw cliError(error instanceof Error ? error.message : String(error));
113
- }
114
- const filters = filtersFromFlags(flags);
115
- const deadline = flags.seconds ? Date.now() + flags.seconds * 1000 : null;
116
- const idWidth = pickIdWidth(Boolean(process.stdout.isTTY));
117
- const seenIds = new Set();
118
- let cursor = null;
119
- let printed = 0;
120
- let headerPrinted = false;
121
- while (deadline === null || Date.now() < deadline) {
122
- const page = await fetchEmailSearchPage({
123
- apiClient,
124
- cursor,
125
- filters,
126
- pageSize: flags["page-size"],
127
- since,
128
- });
129
- if (!page.ok) {
130
- const payload = extractErrorPayload(page.error);
131
- writeErrorWithHints(payload);
132
- removeStaleSavedCredentialOnUnauthorized({
133
- auth,
134
- baseUrlOverridden,
135
- configDir: this.config.configDir,
136
- payload,
137
- });
138
- process.exitCode = 1;
139
- return;
140
- }
141
- cursor = page.cursor ?? cursor;
142
- for (const email of collectNewAcceptedEmails(page.rows, seenIds)) {
143
- if (flags.jsonl) {
144
- this.log(JSON.stringify(email));
145
- }
146
- else {
147
- if (!headerPrinted) {
148
- process.stderr.write(`${formatHeader(idWidth)}\n`);
149
- headerPrinted = true;
150
- }
151
- this.log(formatRow(email, idWidth));
152
- }
153
- printed += 1;
154
- if (flags.number && printed >= flags.number)
155
- return;
156
- }
157
- if (page.rows.length > 0)
158
- continue;
159
- if (deadline !== null && Date.now() >= deadline)
160
- break;
161
- await sleep(flags.interval * 1000);
162
- }
163
- }
164
- }
165
- export default EmailsWatchCommand;
@@ -1,124 +0,0 @@
1
- import { Command, Flags } from "@oclif/core";
2
- import { createFunction } from "../../api/generated/sdk.gen.js";
3
- import { PrimitiveApiClient } from "../../api/index.js";
4
- import { extractErrorPayload, readTextFileFlag, removeStaleSavedCredentialOnUnauthorized, runWithTiming, TIME_FLAG_DESCRIPTION, writeErrorWithHints, } from "../api-command.js";
5
- import { resolveCliAuth } from "../auth.js";
6
- import { emitRawSendMailFetchWarning } from "../lint/raw-send-mail-fetch.js";
7
- // `primitive functions:deploy` is the agent-grade shortcut for
8
- // `functions:create-function`. The underlying operation takes `code`
9
- // as a string in the JSON body, which is awkward at the CLI for
10
- // multi-line bundles: agents would otherwise have to shell-escape an
11
- // entire ESM file or write a temp body.json. This command reads the
12
- // bundle straight off disk via --file, so the natural workflow is:
13
- //
14
- // esbuild handler.ts --bundle --format=esm --outfile=bundle.js
15
- // primitive functions:deploy --name myfn --file bundle.js
16
- //
17
- // Source maps follow the same shape via --source-map-file. They are
18
- // stored only on the runtime side (not in our database) so dropping
19
- // them later in the pipeline is fine; the CLI just hands them through.
20
- //
21
- // For full control (raw body, --raw-body JSON, etc.) the underlying
22
- // `functions:create-function` operation stays available.
23
- class FunctionsDeployCommand extends Command {
24
- static description = `Deploy a new function from a bundled handler file. Agent-grade shortcut for functions:create-function.
25
-
26
- Reads the bundle off disk (--file) instead of forcing the caller to
27
- serialize the source into a JSON body. Use the underlying operation
28
- \`functions:create-function\` if you need the full flag surface
29
- (raw-body JSON, etc.).`;
30
- static summary = "Deploy a new function from a bundled handler file";
31
- static examples = [
32
- "<%= config.bin %> functions:deploy --name forwarder --file ./bundle.js",
33
- "<%= config.bin %> functions:deploy --name forwarder --file ./bundle.js --source-map-file ./bundle.js.map",
34
- ];
35
- static flags = {
36
- "api-key": Flags.string({
37
- description: "Primitive API key (defaults to PRIMITIVE_API_KEY or saved `primitive login` credentials)",
38
- env: "PRIMITIVE_API_KEY",
39
- }),
40
- "api-base-url-1": Flags.string({
41
- description: "Override the primary API base URL. Internal testing only; not documented to customers.",
42
- env: "PRIMITIVE_API_BASE_URL_1",
43
- hidden: true,
44
- }),
45
- "api-base-url-2": Flags.string({
46
- description: "Override the attachments-supporting send host base URL. Internal testing only; not documented to customers.",
47
- env: "PRIMITIVE_API_BASE_URL_2",
48
- hidden: true,
49
- }),
50
- name: Flags.string({
51
- description: "Slug-style name. Lowercase letters, digits, hyphens, underscores. 1-64 chars. Must be unique within the org.",
52
- required: true,
53
- }),
54
- file: Flags.string({
55
- description: "Path to the bundled ESM handler file (single self-contained module). Loaded as the `code` body field.",
56
- required: true,
57
- }),
58
- "source-map-file": Flags.string({
59
- description: "Optional path to a source map for the bundle. Stored only on the runtime side and used to symbolicate stack traces.",
60
- }),
61
- time: Flags.boolean({
62
- description: TIME_FLAG_DESCRIPTION,
63
- }),
64
- };
65
- async run() {
66
- const { flags } = await this.parse(FunctionsDeployCommand);
67
- await runWithTiming(flags.time, async () => {
68
- // Reads are inside the timed block so --time captures disk I/O
69
- // alongside the API call. A pathological filesystem (NFS, slow
70
- // FUSE mount) showing up here is exactly the kind of latency
71
- // surprise --time is meant to surface.
72
- const code = readTextFileFlag(flags.file, "--file");
73
- const sourceMap = flags["source-map-file"]
74
- ? readTextFileFlag(flags["source-map-file"], "--source-map-file")
75
- : undefined;
76
- // Non-blocking deploy-time lint: if the bundle has a raw
77
- // fetch(...) call against /send-mail, nudge the author toward
78
- // `createPrimitiveClient` from `@primitivedotdev/sdk/api`.
79
- // The warning lands on stderr so it never contaminates the
80
- // JSON stdout the caller may pipe into jq.
81
- emitRawSendMailFetchWarning(code, (chunk) => process.stderr.write(chunk));
82
- const baseUrlOverridden = flags["api-base-url-1"] !== undefined ||
83
- flags["api-base-url-2"] !== undefined;
84
- const auth = resolveCliAuth({
85
- apiKey: flags["api-key"],
86
- apiBaseUrl1: flags["api-base-url-1"],
87
- apiBaseUrl2: flags["api-base-url-2"],
88
- configDir: this.config.configDir,
89
- });
90
- const apiClient = new PrimitiveApiClient({
91
- apiKey: auth.apiKey,
92
- apiBaseUrl1: auth.apiBaseUrl1,
93
- apiBaseUrl2: auth.apiBaseUrl2,
94
- });
95
- const authFailureContext = {
96
- auth,
97
- baseUrlOverridden,
98
- configDir: this.config.configDir,
99
- };
100
- const result = await createFunction({
101
- body: {
102
- name: flags.name,
103
- code,
104
- ...(sourceMap !== undefined ? { sourceMap } : {}),
105
- },
106
- client: apiClient.client,
107
- responseStyle: "fields",
108
- });
109
- if (result.error) {
110
- const errorPayload = extractErrorPayload(result.error);
111
- writeErrorWithHints(errorPayload);
112
- removeStaleSavedCredentialOnUnauthorized({
113
- ...authFailureContext,
114
- payload: errorPayload,
115
- });
116
- process.exitCode = 1;
117
- return;
118
- }
119
- const envelope = result.data;
120
- this.log(JSON.stringify(envelope?.data ?? null, null, 2));
121
- });
122
- }
123
- }
124
- export default FunctionsDeployCommand;