@primitivedotdev/sdk 0.19.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import { Command, Errors, Flags } from "@oclif/core";
2
2
  import { cliLogout } from "../../api/generated/sdk.gen.js";
3
3
  import { PrimitiveApiClient } from "../../api/index.js";
4
4
  import { API_ERROR_CODES, extractErrorCode, extractErrorPayload, writeErrorWithHints, } from "../api-command.js";
5
- import { acquireCliCredentialsLock, deleteCliCredentials, loadCliCredentials, normalizeBaseUrl, } from "../auth.js";
5
+ import { acquireCliCredentialsLock, deleteCliCredentials, loadCliCredentials, normalizeApiBaseUrl1, } from "../auth.js";
6
6
  function cliError(message) {
7
7
  return new Errors.CLIError(message, { exit: 1 });
8
8
  }
@@ -15,9 +15,10 @@ class LogoutCommand extends Command {
15
15
  static summary = "Log out and revoke the saved CLI key";
16
16
  static examples = ["<%= config.bin %> logout"];
17
17
  static flags = {
18
- "base-url": Flags.string({
19
- description: "Override the API base URL used for key revocation",
20
- env: "PRIMITIVE_API_URL",
18
+ "api-base-url-1": Flags.string({
19
+ description: "Override the primary API base URL. Internal testing only; not documented to customers.",
20
+ env: "PRIMITIVE_API_BASE_URL_1",
21
+ hidden: true,
21
22
  }),
22
23
  };
23
24
  async run() {
@@ -52,12 +53,12 @@ class LogoutCommand extends Command {
52
53
  if (!credentials) {
53
54
  throw cliError("Not logged in. Run `primitive login` to create saved CLI credentials.");
54
55
  }
55
- const baseUrl = flags["base-url"]
56
- ? normalizeBaseUrl(flags["base-url"])
57
- : credentials.base_url;
56
+ const apiBaseUrl1 = flags["api-base-url-1"]
57
+ ? normalizeApiBaseUrl1(flags["api-base-url-1"])
58
+ : credentials.api_base_url_1;
58
59
  const apiClient = new PrimitiveApiClient({
59
60
  apiKey: credentials.api_key,
60
- baseUrl,
61
+ apiBaseUrl1,
61
62
  });
62
63
  const result = await cliLogout({
63
64
  body: { key_id: credentials.key_id },
@@ -115,9 +115,15 @@ class SendCommand extends Command {
115
115
  description: "Primitive API key (defaults to PRIMITIVE_API_KEY or saved `primitive login` credentials)",
116
116
  env: "PRIMITIVE_API_KEY",
117
117
  }),
118
- "base-url": Flags.string({
119
- description: "API base URL (defaults to PRIMITIVE_API_URL or production)",
120
- env: "PRIMITIVE_API_URL",
118
+ "api-base-url-1": Flags.string({
119
+ description: "Override the primary API base URL. Internal testing only; not documented to customers.",
120
+ env: "PRIMITIVE_API_BASE_URL_1",
121
+ hidden: true,
122
+ }),
123
+ "api-base-url-2": Flags.string({
124
+ description: "Override the attachments-supporting send host base URL. Internal testing only; not documented to customers.",
125
+ env: "PRIMITIVE_API_BASE_URL_2",
126
+ hidden: true,
121
127
  }),
122
128
  to: Flags.string({
123
129
  description: "Recipient address (e.g. alice@example.com).",
@@ -154,15 +160,18 @@ class SendCommand extends Command {
154
160
  throw new Errors.CLIError("Either --body or --html (or both) is required.");
155
161
  }
156
162
  await runWithTiming(flags.time, async () => {
157
- const baseUrlOverridden = flags["base-url"] !== undefined;
163
+ const baseUrlOverridden = flags["api-base-url-1"] !== undefined ||
164
+ flags["api-base-url-2"] !== undefined;
158
165
  const auth = resolveCliAuth({
159
166
  apiKey: flags["api-key"],
160
- baseUrl: flags["base-url"],
167
+ apiBaseUrl1: flags["api-base-url-1"],
168
+ apiBaseUrl2: flags["api-base-url-2"],
161
169
  configDir: this.config.configDir,
162
170
  });
163
171
  const apiClient = new PrimitiveApiClient({
164
172
  apiKey: auth.apiKey,
165
- baseUrl: auth.baseUrl,
173
+ apiBaseUrl1: auth.apiBaseUrl1,
174
+ apiBaseUrl2: auth.apiBaseUrl2,
166
175
  });
167
176
  const authFailureContext = {
168
177
  auth,
@@ -187,7 +196,12 @@ class SendCommand extends Command {
187
196
  ? { wait_timeout_ms: flags["wait-timeout-ms"] }
188
197
  : {}),
189
198
  },
190
- client: apiClient.client,
199
+ // /send-mail goes to the attachments-supporting host. The
200
+ // wrapper exposes the host-2 client as _sendClient for this
201
+ // and any other host-2 operation that lands here. Customer
202
+ // SDK callers should use PrimitiveClient.send() instead so
203
+ // the routing stays internal.
204
+ client: apiClient._sendClient,
191
205
  responseStyle: "fields",
192
206
  });
193
207
  if (result.error) {
@@ -25,9 +25,15 @@ class WhoamiCommand extends Command {
25
25
  description: "Primitive API key (defaults to PRIMITIVE_API_KEY or saved `primitive login` credentials)",
26
26
  env: "PRIMITIVE_API_KEY",
27
27
  }),
28
- "base-url": Flags.string({
29
- description: "API base URL (defaults to PRIMITIVE_API_URL or production)",
30
- env: "PRIMITIVE_API_URL",
28
+ "api-base-url-1": Flags.string({
29
+ description: "Override the primary API base URL. Internal testing only; not documented to customers.",
30
+ env: "PRIMITIVE_API_BASE_URL_1",
31
+ hidden: true,
32
+ }),
33
+ "api-base-url-2": Flags.string({
34
+ description: "Override the attachments-supporting send host base URL. Internal testing only; not documented to customers.",
35
+ env: "PRIMITIVE_API_BASE_URL_2",
36
+ hidden: true,
31
37
  }),
32
38
  time: Flags.boolean({
33
39
  description: TIME_FLAG_DESCRIPTION,
@@ -36,15 +42,18 @@ class WhoamiCommand extends Command {
36
42
  async run() {
37
43
  const { flags } = await this.parse(WhoamiCommand);
38
44
  await runWithTiming(flags.time, async () => {
39
- const baseUrlOverridden = flags["base-url"] !== undefined;
45
+ const baseUrlOverridden = flags["api-base-url-1"] !== undefined ||
46
+ flags["api-base-url-2"] !== undefined;
40
47
  const auth = resolveCliAuth({
41
48
  apiKey: flags["api-key"],
42
- baseUrl: flags["base-url"],
49
+ apiBaseUrl1: flags["api-base-url-1"],
50
+ apiBaseUrl2: flags["api-base-url-2"],
43
51
  configDir: this.config.configDir,
44
52
  });
45
53
  const apiClient = new PrimitiveApiClient({
46
54
  apiKey: auth.apiKey,
47
- baseUrl: auth.baseUrl,
55
+ apiBaseUrl1: auth.apiBaseUrl1,
56
+ apiBaseUrl2: auth.apiBaseUrl2,
48
57
  });
49
58
  const result = await getAccount({
50
59
  client: apiClient.client,
@@ -73,7 +73,7 @@ export function renderFishCompletion(binName) {
73
73
  ]) {
74
74
  lines.push(`complete -c ${binName} -n '${operationCondition(operation).replace(BIN_PLACEHOLDER, binName)}' -l '${fishEscape(parameter.name.replace(/_/g, "-"))}' -r -d '${fishEscape(parameter.description ?? parameter.name)}'`);
75
75
  }
76
- lines.push(`complete -c ${binName} -n '${operationCondition(operation).replace(BIN_PLACEHOLDER, binName)}' -l 'api-key' -r -d 'Primitive API key (defaults to PRIMITIVE_API_KEY or saved primitive login credentials)'`, `complete -c ${binName} -n '${operationCondition(operation).replace(BIN_PLACEHOLDER, binName)}' -l 'base-url' -r -d 'API base URL (defaults to PRIMITIVE_API_URL or production)'`);
76
+ lines.push(`complete -c ${binName} -n '${operationCondition(operation).replace(BIN_PLACEHOLDER, binName)}' -l 'api-key' -r -d 'Primitive API key (defaults to PRIMITIVE_API_KEY or saved primitive login credentials)'`);
77
77
  if (operation.hasJsonBody) {
78
78
  lines.push(`complete -c ${binName} -n '${operationCondition(operation).replace(BIN_PLACEHOLDER, binName)}' -l 'body' -r -d 'JSON request body'`, `complete -c ${binName} -n '${operationCondition(operation).replace(BIN_PLACEHOLDER, binName)}' -l 'body-file' -r -d 'Path to a JSON file used as the request body'`);
79
79
  }
@@ -2,6 +2,10 @@ import { Args, Command, Errors } from "@oclif/core";
2
2
  import { operationManifest, } from "../openapi/index.js";
3
3
  import { createOperationCommand } from "./api-command.js";
4
4
  import EmailsLatestCommand from "./commands/emails-latest.js";
5
+ import EmailsWaitCommand from "./commands/emails-wait.js";
6
+ import EmailsWatchCommand from "./commands/emails-watch.js";
7
+ import FunctionsDeployCommand from "./commands/functions-deploy.js";
8
+ import FunctionsRedeployCommand from "./commands/functions-redeploy.js";
5
9
  import LoginCommand from "./commands/login.js";
6
10
  import LogoutCommand from "./commands/logout.js";
7
11
  import SendCommand from "./commands/send.js";
@@ -131,5 +135,17 @@ export const COMMANDS = {
131
135
  // inbound emails as a compact text table. emails:list-emails stays
132
136
  // available for the full JSON envelope + cursor pagination.
133
137
  "emails:latest": EmailsLatestCommand,
138
+ // `emails:watch` and `emails:wait` poll the search API for new matching
139
+ // inbound mail. `watch` defaults to a human table; `wait` defaults to JSONL.
140
+ "emails:watch": EmailsWatchCommand,
141
+ "emails:wait": EmailsWaitCommand,
142
+ // `functions:deploy` and `functions:redeploy` are file-input
143
+ // shortcuts for create-function / update-function. The underlying
144
+ // ops take `code` as a body string, which is awkward at the CLI
145
+ // for multi-line bundles; these read the bundle off disk and pass
146
+ // it through. The auto-generated functions:* operations stay
147
+ // available for callers that want the full surface.
148
+ "functions:deploy": FunctionsDeployCommand,
149
+ "functions:redeploy": FunctionsRedeployCommand,
134
150
  ...generatedCommands,
135
151
  };