@primitivedotdev/cli 0.30.0 → 0.30.1
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/bin/run.js +6 -6
- package/dist/oclif/index.js +473 -153
- package/dist/oclif/proxy-auto-detect.js +35 -9
- package/package.json +1 -1
package/bin/run.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { applyProxyAutoDetect } from "../dist/oclif/proxy-auto-detect.js";
|
|
3
|
+
import { restartWithProxyEnvIfNeeded } from "../dist/oclif/proxy-auto-detect.js";
|
|
5
4
|
|
|
6
|
-
// Auto-
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
|
|
5
|
+
// Auto-restart with NODE_USE_ENV_PROXY=1 when HTTP(S)_PROXY is in the env.
|
|
6
|
+
// Node reads NODE_USE_ENV_PROXY during process startup, so mutating
|
|
7
|
+
// process.env inside this process is too late for built-in fetch.
|
|
8
|
+
restartWithProxyEnvIfNeeded();
|
|
10
9
|
|
|
10
|
+
const { execute } = await import("@oclif/core");
|
|
11
11
|
await execute({ dir: import.meta.url });
|
package/dist/oclif/index.js
CHANGED
|
@@ -371,7 +371,7 @@ const mergeConfigs = (a, b) => {
|
|
|
371
371
|
...b
|
|
372
372
|
};
|
|
373
373
|
if (config.baseUrl?.endsWith("/")) config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
|
|
374
|
-
config.headers = mergeHeaders(a.headers, b.headers);
|
|
374
|
+
config.headers = mergeHeaders$1(a.headers, b.headers);
|
|
375
375
|
return config;
|
|
376
376
|
};
|
|
377
377
|
const headersEntries = (headers) => {
|
|
@@ -381,7 +381,7 @@ const headersEntries = (headers) => {
|
|
|
381
381
|
});
|
|
382
382
|
return entries;
|
|
383
383
|
};
|
|
384
|
-
const mergeHeaders = (...headers) => {
|
|
384
|
+
const mergeHeaders$1 = (...headers) => {
|
|
385
385
|
const mergedHeaders = new Headers();
|
|
386
386
|
for (const header of headers) {
|
|
387
387
|
if (!header) continue;
|
|
@@ -461,7 +461,7 @@ const createClient = (config = {}) => {
|
|
|
461
461
|
..._config,
|
|
462
462
|
...options,
|
|
463
463
|
fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
|
|
464
|
-
headers: mergeHeaders(_config.headers, options.headers),
|
|
464
|
+
headers: mergeHeaders$1(_config.headers, options.headers),
|
|
465
465
|
serializedBody: void 0
|
|
466
466
|
};
|
|
467
467
|
if (opts.security) await setAuthParams({
|
|
@@ -1604,17 +1604,18 @@ const updateFunction = (options) => (options.client ?? client).put({
|
|
|
1604
1604
|
* Sends a real test email from a Primitive-controlled sender to a
|
|
1605
1605
|
* local-part on one of the org's verified inbound domains. By
|
|
1606
1606
|
* default the recipient is a synthetic
|
|
1607
|
-
* `__primitive_function_test+<random>@<domain>` address
|
|
1608
|
-
*
|
|
1609
|
-
*
|
|
1610
|
-
*
|
|
1611
|
-
*
|
|
1612
|
-
*
|
|
1613
|
-
*
|
|
1614
|
-
*
|
|
1615
|
-
*
|
|
1616
|
-
*
|
|
1617
|
-
*
|
|
1607
|
+
* `__primitive_function_test+<random>@<domain>` address on a
|
|
1608
|
+
* domain selected to route to the function. Scoped functions use
|
|
1609
|
+
* their scoped domain; fallback functions use a domain that has
|
|
1610
|
+
* no enabled domain-scoped endpoint. Pass `local_part` to
|
|
1611
|
+
* override and exercise routing logic that branches on a specific
|
|
1612
|
+
* recipient (the common pattern when one function handles multiple
|
|
1613
|
+
* inboxes like `summarize@` and `action@`). The function fires
|
|
1614
|
+
* through the normal MX delivery path, so reply / send-mail calls
|
|
1615
|
+
* from inside the handler against the inbound's `email.id` work
|
|
1616
|
+
* the same as in production. Returns immediately after the send is
|
|
1617
|
+
* queued; the invocation appears on the function's invocations
|
|
1618
|
+
* list within a few seconds.
|
|
1618
1619
|
*
|
|
1619
1620
|
* Requires that the function is currently `deployed`. Returns 422
|
|
1620
1621
|
* if the function is in `pending` or `failed` state, or if the
|
|
@@ -3274,7 +3275,7 @@ const openapiDocument = {
|
|
|
3274
3275
|
"post": {
|
|
3275
3276
|
"operationId": "testFunction",
|
|
3276
3277
|
"summary": "Send a test invocation",
|
|
3277
|
-
"description": "Sends a real test email from a Primitive-controlled sender to a\nlocal-part on one of the org's verified inbound domains. By\ndefault the recipient is a synthetic\n`__primitive_function_test+<random>@<domain>` address
|
|
3278
|
+
"description": "Sends a real test email from a Primitive-controlled sender to a\nlocal-part on one of the org's verified inbound domains. By\ndefault the recipient is a synthetic\n`__primitive_function_test+<random>@<domain>` address on a\ndomain selected to route to the function. Scoped functions use\ntheir scoped domain; fallback functions use a domain that has\nno enabled domain-scoped endpoint. Pass `local_part` to\noverride and exercise routing logic that branches on a specific\nrecipient (the common pattern when one function handles multiple\ninboxes like `summarize@` and `action@`). The function fires\nthrough the normal MX delivery path, so reply / send-mail calls\nfrom inside the handler against the inbound's `email.id` work\nthe same as in production. Returns immediately after the send is\nqueued; the invocation appears on the function's invocations\nlist within a few seconds.\n\nRequires that the function is currently `deployed`. Returns 422\nif the function is in `pending` or `failed` state, or if the\norg has no verified inbound domain to receive the test mail.\nReturns 400 if `local_part` is set to a value that does not\nmatch the local-part character set.\n",
|
|
3278
3279
|
"tags": ["Functions"],
|
|
3279
3280
|
"requestBody": {
|
|
3280
3281
|
"required": false,
|
|
@@ -9398,7 +9399,7 @@ const operationManifest = [
|
|
|
9398
9399
|
"binaryResponse": false,
|
|
9399
9400
|
"bodyRequired": false,
|
|
9400
9401
|
"command": "test-function",
|
|
9401
|
-
"description": "Sends a real test email from a Primitive-controlled sender to a\nlocal-part on one of the org's verified inbound domains. By\ndefault the recipient is a synthetic\n`__primitive_function_test+<random>@<domain>` address
|
|
9402
|
+
"description": "Sends a real test email from a Primitive-controlled sender to a\nlocal-part on one of the org's verified inbound domains. By\ndefault the recipient is a synthetic\n`__primitive_function_test+<random>@<domain>` address on a\ndomain selected to route to the function. Scoped functions use\ntheir scoped domain; fallback functions use a domain that has\nno enabled domain-scoped endpoint. Pass `local_part` to\noverride and exercise routing logic that branches on a specific\nrecipient (the common pattern when one function handles multiple\ninboxes like `summarize@` and `action@`). The function fires\nthrough the normal MX delivery path, so reply / send-mail calls\nfrom inside the handler against the inbound's `email.id` work\nthe same as in production. Returns immediately after the send is\nqueued; the invocation appears on the function's invocations\nlist within a few seconds.\n\nRequires that the function is currently `deployed`. Returns 422\nif the function is in `pending` or `failed` state, or if the\norg has no verified inbound domain to receive the test mail.\nReturns 400 if `local_part` is set to a value that does not\nmatch the local-part character set.\n",
|
|
9402
9403
|
"hasJsonBody": true,
|
|
9403
9404
|
"method": "POST",
|
|
9404
9405
|
"operationId": "testFunction",
|
|
@@ -10752,7 +10753,7 @@ const CREDENTIALS_FILE = "credentials.json";
|
|
|
10752
10753
|
const CREDENTIALS_LOCK_DIR = "credentials.lock";
|
|
10753
10754
|
const CREDENTIALS_LOCK_STALE_MS = 1800 * 1e3;
|
|
10754
10755
|
const MALFORMED_CREDENTIALS_HINT = "Run `primitive logout` and then `primitive login`.";
|
|
10755
|
-
function isRecord$
|
|
10756
|
+
function isRecord$2(value) {
|
|
10756
10757
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
10757
10758
|
}
|
|
10758
10759
|
function requireString(value, key) {
|
|
@@ -10775,7 +10776,7 @@ var StaleCredentialFormatError = class extends Error {
|
|
|
10775
10776
|
}
|
|
10776
10777
|
};
|
|
10777
10778
|
function parseCredentials(raw) {
|
|
10778
|
-
if (!isRecord$
|
|
10779
|
+
if (!isRecord$2(raw)) throw new Error(`Stored Primitive CLI credentials are malformed: expected a JSON object. ${MALFORMED_CREDENTIALS_HINT}`);
|
|
10779
10780
|
if (typeof raw.api_base_url_1 !== "string" && typeof raw.base_url === "string") throw new StaleCredentialFormatError();
|
|
10780
10781
|
const orgName = raw.org_name;
|
|
10781
10782
|
if (orgName !== null && typeof orgName !== "string") throw new Error(`Stored Primitive CLI credentials are malformed: org_name must be a string or null. ${MALFORMED_CREDENTIALS_HINT}`);
|
|
@@ -10920,6 +10921,269 @@ function resolveCliAuth(params) {
|
|
|
10920
10921
|
};
|
|
10921
10922
|
}
|
|
10922
10923
|
//#endregion
|
|
10924
|
+
//#region src/oclif/cli-config.ts
|
|
10925
|
+
const CONFIG_FILE = "config.json";
|
|
10926
|
+
const CONFIG_VERSION = 1;
|
|
10927
|
+
const DEFAULT_ENVIRONMENT = "default";
|
|
10928
|
+
function cliConfigPath(configDir) {
|
|
10929
|
+
return join(configDir, CONFIG_FILE);
|
|
10930
|
+
}
|
|
10931
|
+
function cliConfigError(message) {
|
|
10932
|
+
return new Errors.CLIError(`${message} Run \`primitive config reset\` to clear the local CLI config.`, { exit: 1 });
|
|
10933
|
+
}
|
|
10934
|
+
function isRecord$1(value) {
|
|
10935
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
10936
|
+
}
|
|
10937
|
+
function normalizeCliEnvironmentName(name) {
|
|
10938
|
+
const trimmed = name?.trim();
|
|
10939
|
+
if (!trimmed) throw new Errors.CLIError("Environment name must be a non-empty string.", { exit: 1 });
|
|
10940
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,62}$/.test(trimmed)) throw new Errors.CLIError("Environment name must start with a letter or number and may only contain letters, numbers, '.', '_', or '-'.", { exit: 1 });
|
|
10941
|
+
return trimmed;
|
|
10942
|
+
}
|
|
10943
|
+
function validateCliHeaderName(name) {
|
|
10944
|
+
const trimmed = name.trim();
|
|
10945
|
+
if (!trimmed) throw new Errors.CLIError("Header name must be a non-empty string.", { exit: 1 });
|
|
10946
|
+
if (!/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/.test(trimmed)) throw new Errors.CLIError(`Invalid header name: ${name}`, { exit: 1 });
|
|
10947
|
+
if (trimmed.toLowerCase() === "authorization") throw new Errors.CLIError("The Authorization header is managed by PRIMITIVE_API_KEY or saved CLI credentials.", { exit: 1 });
|
|
10948
|
+
return trimmed;
|
|
10949
|
+
}
|
|
10950
|
+
function validateCliHeaderValue(value, name) {
|
|
10951
|
+
if (value.length === 0) throw new Errors.CLIError(`Header ${name} value must not be empty.`, { exit: 1 });
|
|
10952
|
+
if (/[\r\n\0]/.test(value)) throw new Errors.CLIError(`Header ${name} value must not contain CR, LF, or NUL characters.`, { exit: 1 });
|
|
10953
|
+
return value;
|
|
10954
|
+
}
|
|
10955
|
+
function parseHeaderAssignment(assignment) {
|
|
10956
|
+
const separator = assignment.indexOf("=");
|
|
10957
|
+
if (separator <= 0) throw new Errors.CLIError("Header values must use name=value syntax, for example `x-custom=secret`.", { exit: 1 });
|
|
10958
|
+
const name = validateCliHeaderName(assignment.slice(0, separator));
|
|
10959
|
+
return [name, validateCliHeaderValue(assignment.slice(separator + 1), name)];
|
|
10960
|
+
}
|
|
10961
|
+
function parseHeaders(raw, context) {
|
|
10962
|
+
if (raw === void 0) return {};
|
|
10963
|
+
if (!isRecord$1(raw)) throw cliConfigError(`${context} headers must be a JSON object.`);
|
|
10964
|
+
const headers = {};
|
|
10965
|
+
for (const [rawName, rawValue] of Object.entries(raw)) {
|
|
10966
|
+
const name = validateCliHeaderName(rawName);
|
|
10967
|
+
if (typeof rawValue !== "string") throw cliConfigError(`${context} header ${name} must be a string.`);
|
|
10968
|
+
headers[name] = validateCliHeaderValue(rawValue, name);
|
|
10969
|
+
}
|
|
10970
|
+
return headers;
|
|
10971
|
+
}
|
|
10972
|
+
function parseEnvironmentConfig(raw, context) {
|
|
10973
|
+
if (!isRecord$1(raw)) throw cliConfigError(`${context} must be a JSON object.`);
|
|
10974
|
+
const env = {};
|
|
10975
|
+
if (raw.api_base_url_1 !== void 0) {
|
|
10976
|
+
if (typeof raw.api_base_url_1 !== "string") throw cliConfigError(`${context}.api_base_url_1 must be a string.`);
|
|
10977
|
+
env.api_base_url_1 = normalizeApiBaseUrl1(raw.api_base_url_1);
|
|
10978
|
+
}
|
|
10979
|
+
if (raw.api_base_url_2 !== void 0) {
|
|
10980
|
+
if (typeof raw.api_base_url_2 !== "string") throw cliConfigError(`${context}.api_base_url_2 must be a string.`);
|
|
10981
|
+
env.api_base_url_2 = normalizeApiBaseUrl2(raw.api_base_url_2);
|
|
10982
|
+
}
|
|
10983
|
+
const headers = parseHeaders(raw.headers, context);
|
|
10984
|
+
if (Object.keys(headers).length > 0) env.headers = headers;
|
|
10985
|
+
return env;
|
|
10986
|
+
}
|
|
10987
|
+
function parseStoredCliConfig(raw) {
|
|
10988
|
+
if (!isRecord$1(raw)) throw cliConfigError("Primitive CLI config must be a JSON object.");
|
|
10989
|
+
if (raw.version !== CONFIG_VERSION) throw cliConfigError(`Primitive CLI config version must be ${CONFIG_VERSION}.`);
|
|
10990
|
+
const currentRaw = raw.current_environment;
|
|
10991
|
+
const current_environment = currentRaw === null || currentRaw === void 0 ? null : typeof currentRaw === "string" ? normalizeCliEnvironmentName(currentRaw) : (() => {
|
|
10992
|
+
throw cliConfigError("Primitive CLI config current_environment must be a string or null.");
|
|
10993
|
+
})();
|
|
10994
|
+
if (!isRecord$1(raw.environments)) throw cliConfigError("Primitive CLI config environments must be an object.");
|
|
10995
|
+
const environments = {};
|
|
10996
|
+
for (const [rawName, rawEnv] of Object.entries(raw.environments)) {
|
|
10997
|
+
const name = normalizeCliEnvironmentName(rawName);
|
|
10998
|
+
environments[name] = parseEnvironmentConfig(rawEnv, `Primitive CLI config environment ${name}`);
|
|
10999
|
+
}
|
|
11000
|
+
if (current_environment && !environments[current_environment]) throw cliConfigError(`Primitive CLI config current environment ${current_environment} does not exist.`);
|
|
11001
|
+
return {
|
|
11002
|
+
version: CONFIG_VERSION,
|
|
11003
|
+
current_environment,
|
|
11004
|
+
environments
|
|
11005
|
+
};
|
|
11006
|
+
}
|
|
11007
|
+
function emptyCliConfig() {
|
|
11008
|
+
return {
|
|
11009
|
+
version: CONFIG_VERSION,
|
|
11010
|
+
current_environment: null,
|
|
11011
|
+
environments: {}
|
|
11012
|
+
};
|
|
11013
|
+
}
|
|
11014
|
+
function loadCliConfig(configDir) {
|
|
11015
|
+
const path = cliConfigPath(configDir);
|
|
11016
|
+
let contents;
|
|
11017
|
+
try {
|
|
11018
|
+
contents = readFileSync(path, "utf8");
|
|
11019
|
+
} catch (error) {
|
|
11020
|
+
if (error && typeof error === "object" && error.code === "ENOENT") return null;
|
|
11021
|
+
throw cliConfigError(`Could not read Primitive CLI config: ${error instanceof Error ? error.message : String(error)}.`);
|
|
11022
|
+
}
|
|
11023
|
+
try {
|
|
11024
|
+
return parseStoredCliConfig(JSON.parse(contents));
|
|
11025
|
+
} catch (error) {
|
|
11026
|
+
if (error instanceof SyntaxError) throw cliConfigError("Primitive CLI config is not valid JSON.");
|
|
11027
|
+
throw error;
|
|
11028
|
+
}
|
|
11029
|
+
}
|
|
11030
|
+
function saveCliConfig(configDir, config) {
|
|
11031
|
+
mkdirSync(configDir, {
|
|
11032
|
+
mode: 448,
|
|
11033
|
+
recursive: true
|
|
11034
|
+
});
|
|
11035
|
+
const path = cliConfigPath(configDir);
|
|
11036
|
+
const tempPath = join(configDir, `${CONFIG_FILE}.${process.pid}.${randomUUID()}.tmp`);
|
|
11037
|
+
try {
|
|
11038
|
+
writeFileSync(tempPath, `${JSON.stringify(config, null, 2)}\n`, { mode: 384 });
|
|
11039
|
+
renameSync(tempPath, path);
|
|
11040
|
+
} catch (error) {
|
|
11041
|
+
rmSync(tempPath, { force: true });
|
|
11042
|
+
throw error;
|
|
11043
|
+
}
|
|
11044
|
+
}
|
|
11045
|
+
function deleteCliConfig(configDir) {
|
|
11046
|
+
rmSync(cliConfigPath(configDir), { force: true });
|
|
11047
|
+
}
|
|
11048
|
+
function resolveConfigEnvironment(config) {
|
|
11049
|
+
if (!config) return null;
|
|
11050
|
+
const current = config.current_environment;
|
|
11051
|
+
if (current) {
|
|
11052
|
+
const environment = config.environments[current];
|
|
11053
|
+
return environment ? {
|
|
11054
|
+
name: current,
|
|
11055
|
+
config: environment
|
|
11056
|
+
} : null;
|
|
11057
|
+
}
|
|
11058
|
+
const defaultEnvironment = config.environments[DEFAULT_ENVIRONMENT];
|
|
11059
|
+
return defaultEnvironment ? {
|
|
11060
|
+
name: DEFAULT_ENVIRONMENT,
|
|
11061
|
+
config: defaultEnvironment
|
|
11062
|
+
} : null;
|
|
11063
|
+
}
|
|
11064
|
+
function upsertCliEnvironment(params) {
|
|
11065
|
+
const name = normalizeCliEnvironmentName(params.environmentName ?? DEFAULT_ENVIRONMENT);
|
|
11066
|
+
const existing = params.config.environments[name] ?? {};
|
|
11067
|
+
const nextHeaders = { ...existing.headers ?? {} };
|
|
11068
|
+
for (const assignment of params.headers ?? []) {
|
|
11069
|
+
const [headerName, value] = parseHeaderAssignment(assignment);
|
|
11070
|
+
nextHeaders[headerName] = value;
|
|
11071
|
+
}
|
|
11072
|
+
for (const rawName of params.unsetHeaders ?? []) delete nextHeaders[validateCliHeaderName(rawName)];
|
|
11073
|
+
const nextEnvironment = {
|
|
11074
|
+
...existing,
|
|
11075
|
+
...params.apiBaseUrl1 !== void 0 ? { api_base_url_1: normalizeApiBaseUrl1(params.apiBaseUrl1) } : {},
|
|
11076
|
+
...params.apiBaseUrl2 !== void 0 ? { api_base_url_2: normalizeApiBaseUrl2(params.apiBaseUrl2) } : {},
|
|
11077
|
+
...Object.keys(nextHeaders).length > 0 ? { headers: nextHeaders } : {}
|
|
11078
|
+
};
|
|
11079
|
+
if (Object.keys(nextHeaders).length === 0) delete nextEnvironment.headers;
|
|
11080
|
+
return {
|
|
11081
|
+
...params.config,
|
|
11082
|
+
current_environment: params.use === false ? params.config.current_environment : name,
|
|
11083
|
+
environments: {
|
|
11084
|
+
...params.config.environments,
|
|
11085
|
+
[name]: nextEnvironment
|
|
11086
|
+
}
|
|
11087
|
+
};
|
|
11088
|
+
}
|
|
11089
|
+
function removeCliEnvironment(config, environmentName) {
|
|
11090
|
+
const name = normalizeCliEnvironmentName(environmentName);
|
|
11091
|
+
const environments = { ...config.environments };
|
|
11092
|
+
delete environments[name];
|
|
11093
|
+
return {
|
|
11094
|
+
...config,
|
|
11095
|
+
current_environment: config.current_environment === name ? null : config.current_environment,
|
|
11096
|
+
environments
|
|
11097
|
+
};
|
|
11098
|
+
}
|
|
11099
|
+
function redactCliEnvironment(environment) {
|
|
11100
|
+
const headers = environment.headers && Object.keys(environment.headers).length > 0 ? Object.fromEntries(Object.keys(environment.headers).map((name) => [name, "***"])) : void 0;
|
|
11101
|
+
return {
|
|
11102
|
+
...environment,
|
|
11103
|
+
...headers ? { headers } : {}
|
|
11104
|
+
};
|
|
11105
|
+
}
|
|
11106
|
+
//#endregion
|
|
11107
|
+
//#region src/oclif/api-client.ts
|
|
11108
|
+
const API_HEADERS_ENV = "PRIMITIVE_API_HEADERS";
|
|
11109
|
+
function mergeHeaders(...headers) {
|
|
11110
|
+
const merged = {};
|
|
11111
|
+
for (const headerSet of headers) {
|
|
11112
|
+
if (!headerSet) continue;
|
|
11113
|
+
for (const [name, value] of Object.entries(headerSet)) merged[name] = value;
|
|
11114
|
+
}
|
|
11115
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
11116
|
+
}
|
|
11117
|
+
function parseHeadersJson(raw) {
|
|
11118
|
+
let parsed;
|
|
11119
|
+
try {
|
|
11120
|
+
parsed = JSON.parse(raw);
|
|
11121
|
+
} catch (error) {
|
|
11122
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
11123
|
+
throw new Errors.CLIError(`${API_HEADERS_ENV} must be valid JSON object syntax: ${detail}`, { exit: 1 });
|
|
11124
|
+
}
|
|
11125
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new Errors.CLIError(`${API_HEADERS_ENV} must be a JSON object.`, { exit: 1 });
|
|
11126
|
+
const headers = {};
|
|
11127
|
+
for (const [rawName, rawValue] of Object.entries(parsed)) {
|
|
11128
|
+
const name = validateCliHeaderName(rawName);
|
|
11129
|
+
if (typeof rawValue !== "string") throw new Errors.CLIError(`${API_HEADERS_ENV}.${name} must be a string.`, { exit: 1 });
|
|
11130
|
+
headers[name] = validateCliHeaderValue(rawValue, name);
|
|
11131
|
+
}
|
|
11132
|
+
return headers;
|
|
11133
|
+
}
|
|
11134
|
+
function cliApiHeadersFromEnv(env = process.env) {
|
|
11135
|
+
const rawGenericHeaders = env[API_HEADERS_ENV]?.trim();
|
|
11136
|
+
return rawGenericHeaders ? parseHeadersJson(rawGenericHeaders) : void 0;
|
|
11137
|
+
}
|
|
11138
|
+
function resolveCliApiRequestConfig(params) {
|
|
11139
|
+
const currentEnvironment = resolveConfigEnvironment(loadCliConfig(params.configDir));
|
|
11140
|
+
const configuredApiBaseUrl1 = currentEnvironment?.config.api_base_url_1;
|
|
11141
|
+
const configuredApiBaseUrl2 = currentEnvironment?.config.api_base_url_2;
|
|
11142
|
+
const apiBaseUrl1 = params.apiBaseUrl1 !== void 0 ? normalizeApiBaseUrl1(params.apiBaseUrl1) : configuredApiBaseUrl1;
|
|
11143
|
+
const apiBaseUrl2 = params.apiBaseUrl2 !== void 0 ? normalizeApiBaseUrl2(params.apiBaseUrl2) : configuredApiBaseUrl2;
|
|
11144
|
+
return {
|
|
11145
|
+
apiBaseUrl1,
|
|
11146
|
+
apiBaseUrl2,
|
|
11147
|
+
baseUrlOverridden: apiBaseUrl1 !== void 0 || apiBaseUrl2 !== void 0,
|
|
11148
|
+
environmentName: currentEnvironment?.name ?? null,
|
|
11149
|
+
headers: mergeHeaders(currentEnvironment?.config.headers, cliApiHeadersFromEnv(params.env)),
|
|
11150
|
+
resolvedApiBaseUrl1: normalizeApiBaseUrl1(apiBaseUrl1),
|
|
11151
|
+
resolvedApiBaseUrl2: normalizeApiBaseUrl2(apiBaseUrl2)
|
|
11152
|
+
};
|
|
11153
|
+
}
|
|
11154
|
+
function createCliApiClient(params) {
|
|
11155
|
+
const requestConfig = resolveCliApiRequestConfig(params);
|
|
11156
|
+
return {
|
|
11157
|
+
apiClient: new PrimitiveApiClient({
|
|
11158
|
+
apiKey: params.apiKey,
|
|
11159
|
+
apiBaseUrl1: requestConfig.resolvedApiBaseUrl1,
|
|
11160
|
+
apiBaseUrl2: requestConfig.resolvedApiBaseUrl2,
|
|
11161
|
+
headers: requestConfig.headers
|
|
11162
|
+
}),
|
|
11163
|
+
requestConfig
|
|
11164
|
+
};
|
|
11165
|
+
}
|
|
11166
|
+
function createAuthenticatedCliApiClient(params) {
|
|
11167
|
+
const requestConfig = resolveCliApiRequestConfig(params);
|
|
11168
|
+
const auth = resolveCliAuth({
|
|
11169
|
+
apiKey: params.apiKey,
|
|
11170
|
+
apiBaseUrl1: requestConfig.apiBaseUrl1,
|
|
11171
|
+
apiBaseUrl2: requestConfig.apiBaseUrl2,
|
|
11172
|
+
configDir: params.configDir
|
|
11173
|
+
});
|
|
11174
|
+
return {
|
|
11175
|
+
apiClient: new PrimitiveApiClient({
|
|
11176
|
+
apiKey: auth.apiKey,
|
|
11177
|
+
apiBaseUrl1: auth.apiBaseUrl1,
|
|
11178
|
+
apiBaseUrl2: auth.apiBaseUrl2,
|
|
11179
|
+
headers: requestConfig.headers
|
|
11180
|
+
}),
|
|
11181
|
+
auth,
|
|
11182
|
+
baseUrlOverridden: requestConfig.baseUrlOverridden,
|
|
11183
|
+
requestConfig
|
|
11184
|
+
};
|
|
11185
|
+
}
|
|
11186
|
+
//#endregion
|
|
10923
11187
|
//#region src/oclif/endpoints-test-redirect.ts
|
|
10924
11188
|
async function detectFunctionEndpoint(endpointId, listEndpoints) {
|
|
10925
11189
|
let response;
|
|
@@ -11243,7 +11507,7 @@ function writeErrorWithHints(payload) {
|
|
|
11243
11507
|
function removeStaleSavedCredentialOnUnauthorized(params) {
|
|
11244
11508
|
if (extractErrorCode(params.payload) !== API_ERROR_CODES.unauthorized || params.auth.source !== "stored") return false;
|
|
11245
11509
|
if (params.baseUrlOverridden && params.auth.credentials !== null && params.auth.apiBaseUrl1 !== params.auth.credentials.api_base_url_1) {
|
|
11246
|
-
process.stderr.write("Saved Primitive CLI credentials were rejected by the overridden API base URL. The local credential was not removed; unset PRIMITIVE_API_BASE_URL_1, or run `primitive logout` to remove the stored credential.\n");
|
|
11510
|
+
process.stderr.write("Saved Primitive CLI credentials were rejected by the overridden API base URL. The local credential was not removed; unset PRIMITIVE_API_BASE_URL_1, run `primitive config reset` to clear configured URL overrides, or run `primitive logout` to remove the stored credential.\n");
|
|
11247
11511
|
return false;
|
|
11248
11512
|
}
|
|
11249
11513
|
deleteCliCredentials(params.configDir);
|
|
@@ -11268,9 +11532,6 @@ async function runWithTiming(enabled, fn) {
|
|
|
11268
11532
|
const TIME_FLAG_DESCRIPTION = "Print the wall-clock duration of this command to stderr after it completes (e.g. `[time: 1.34s]`). Useful for measuring `--wait` send latency, comparing CLI overhead, or capturing timing in scripts.";
|
|
11269
11533
|
const API_BASE_URL_1_FLAG_DESCRIPTION = "Override the primary API base URL. Internal testing only; not documented to customers.";
|
|
11270
11534
|
const API_BASE_URL_2_FLAG_DESCRIPTION = "Override the attachments-supporting send host base URL. Internal testing only; not documented to customers.";
|
|
11271
|
-
function baseUrlOverriddenFromFlags(flags) {
|
|
11272
|
-
return typeof flags["api-base-url-1"] === "string" || typeof flags["api-base-url-2"] === "string";
|
|
11273
|
-
}
|
|
11274
11535
|
const HOST_2_OPERATIONS = new Set(["sendEmail"]);
|
|
11275
11536
|
const RESERVED_FLAG_NAMES = new Set([
|
|
11276
11537
|
"api-key",
|
|
@@ -11379,18 +11640,12 @@ function createOperationCommand(operation) {
|
|
|
11379
11640
|
const { flags } = await this.parse(OperationCommand);
|
|
11380
11641
|
const parsedFlags = flags;
|
|
11381
11642
|
await runWithTiming(parsedFlags.time === true, async () => {
|
|
11382
|
-
const
|
|
11383
|
-
const auth = resolveCliAuth({
|
|
11643
|
+
const { apiClient, auth, baseUrlOverridden } = createAuthenticatedCliApiClient({
|
|
11384
11644
|
apiKey: typeof parsedFlags["api-key"] === "string" ? parsedFlags["api-key"] : void 0,
|
|
11385
11645
|
apiBaseUrl1: typeof parsedFlags["api-base-url-1"] === "string" ? parsedFlags["api-base-url-1"] : void 0,
|
|
11386
11646
|
apiBaseUrl2: typeof parsedFlags["api-base-url-2"] === "string" ? parsedFlags["api-base-url-2"] : void 0,
|
|
11387
11647
|
configDir: this.config.configDir
|
|
11388
11648
|
});
|
|
11389
|
-
const apiClient = new PrimitiveApiClient({
|
|
11390
|
-
apiKey: auth.apiKey,
|
|
11391
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
11392
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
11393
|
-
});
|
|
11394
11649
|
let body;
|
|
11395
11650
|
if (operation.hasJsonBody) {
|
|
11396
11651
|
const explicit = readJsonBody(parsedFlags);
|
|
@@ -11482,6 +11737,128 @@ function canonicalizeCliReferences(description) {
|
|
|
11482
11737
|
return description.replaceAll("`primitive emails:latest`", "`primitive emails latest`").replaceAll("`primitive describe emails:get-email | jq '.responseSchema.properties'`", "`primitive describe emails:get | jq '.responseSchema.properties'`");
|
|
11483
11738
|
}
|
|
11484
11739
|
//#endregion
|
|
11740
|
+
//#region src/oclif/commands/config.ts
|
|
11741
|
+
function loadOrCreateConfig(configDir) {
|
|
11742
|
+
return loadCliConfig(configDir) ?? emptyCliConfig();
|
|
11743
|
+
}
|
|
11744
|
+
function redactConfig(config) {
|
|
11745
|
+
return {
|
|
11746
|
+
...config,
|
|
11747
|
+
environments: Object.fromEntries(Object.entries(config.environments).map(([name, environment]) => [name, redactCliEnvironment(environment)]))
|
|
11748
|
+
};
|
|
11749
|
+
}
|
|
11750
|
+
var ConfigSetCommand = class ConfigSetCommand extends Command {
|
|
11751
|
+
static hidden = true;
|
|
11752
|
+
static summary = "Set hidden Primitive CLI request config";
|
|
11753
|
+
static flags = {
|
|
11754
|
+
environment: Flags.string({
|
|
11755
|
+
char: "e",
|
|
11756
|
+
description: "Environment name to create or update"
|
|
11757
|
+
}),
|
|
11758
|
+
"api-base-url-1": Flags.string({ description: "Primary API base URL" }),
|
|
11759
|
+
"api-base-url-2": Flags.string({ description: "Attachments-supporting API base URL" }),
|
|
11760
|
+
header: Flags.string({
|
|
11761
|
+
description: "Request header in name=value form. Repeatable.",
|
|
11762
|
+
multiple: true
|
|
11763
|
+
}),
|
|
11764
|
+
"unset-header": Flags.string({
|
|
11765
|
+
description: "Request header name to remove. Repeatable.",
|
|
11766
|
+
multiple: true
|
|
11767
|
+
})
|
|
11768
|
+
};
|
|
11769
|
+
async run() {
|
|
11770
|
+
const { flags } = await this.parse(ConfigSetCommand);
|
|
11771
|
+
const headers = flags.header ?? [];
|
|
11772
|
+
if (flags["api-base-url-1"] === void 0 && flags["api-base-url-2"] === void 0 && headers.length === 0 && (flags["unset-header"] ?? []).length === 0) throw new Errors.CLIError("Nothing to set. Pass an API base URL, --header, or --unset-header.", { exit: 1 });
|
|
11773
|
+
const config = upsertCliEnvironment({
|
|
11774
|
+
apiBaseUrl1: flags["api-base-url-1"],
|
|
11775
|
+
apiBaseUrl2: flags["api-base-url-2"],
|
|
11776
|
+
config: loadOrCreateConfig(this.config.configDir),
|
|
11777
|
+
environmentName: flags.environment,
|
|
11778
|
+
headers,
|
|
11779
|
+
unsetHeaders: flags["unset-header"]
|
|
11780
|
+
});
|
|
11781
|
+
saveCliConfig(this.config.configDir, config);
|
|
11782
|
+
process.stderr.write(`Primitive CLI environment ${config.current_environment} is active.\n`);
|
|
11783
|
+
}
|
|
11784
|
+
};
|
|
11785
|
+
var ConfigUseCommand = class ConfigUseCommand extends Command {
|
|
11786
|
+
static hidden = true;
|
|
11787
|
+
static summary = "Switch active Primitive CLI request config";
|
|
11788
|
+
static args = { environment: Args.string({
|
|
11789
|
+
description: "Environment name to use",
|
|
11790
|
+
required: true
|
|
11791
|
+
}) };
|
|
11792
|
+
async run() {
|
|
11793
|
+
const { args } = await this.parse(ConfigUseCommand);
|
|
11794
|
+
const environment = normalizeCliEnvironmentName(args.environment);
|
|
11795
|
+
const config = loadOrCreateConfig(this.config.configDir);
|
|
11796
|
+
if (!config.environments[environment]) throw new Errors.CLIError(`Primitive CLI environment ${environment} is not configured.`, { exit: 1 });
|
|
11797
|
+
saveCliConfig(this.config.configDir, {
|
|
11798
|
+
...config,
|
|
11799
|
+
current_environment: environment
|
|
11800
|
+
});
|
|
11801
|
+
process.stderr.write(`Primitive CLI environment ${environment} is active.\n`);
|
|
11802
|
+
}
|
|
11803
|
+
};
|
|
11804
|
+
var ConfigListCommand = class ConfigListCommand extends Command {
|
|
11805
|
+
static hidden = true;
|
|
11806
|
+
static summary = "List hidden Primitive CLI request configs";
|
|
11807
|
+
static flags = {
|
|
11808
|
+
json: Flags.boolean({ description: "Print JSON" }),
|
|
11809
|
+
"show-secrets": Flags.boolean({ description: "Show header values instead of redacting them" })
|
|
11810
|
+
};
|
|
11811
|
+
async run() {
|
|
11812
|
+
const { flags } = await this.parse(ConfigListCommand);
|
|
11813
|
+
const config = loadOrCreateConfig(this.config.configDir);
|
|
11814
|
+
const output = flags["show-secrets"] ? config : redactConfig(config);
|
|
11815
|
+
if (flags.json) {
|
|
11816
|
+
this.log(JSON.stringify(output, null, 2));
|
|
11817
|
+
return;
|
|
11818
|
+
}
|
|
11819
|
+
const entries = Object.entries(config.environments);
|
|
11820
|
+
if (entries.length === 0) {
|
|
11821
|
+
this.log("No Primitive CLI environments configured.");
|
|
11822
|
+
return;
|
|
11823
|
+
}
|
|
11824
|
+
const activeEnvironment = resolveConfigEnvironment(config)?.name ?? null;
|
|
11825
|
+
for (const [name, environment] of entries) {
|
|
11826
|
+
const active = activeEnvironment === name ? "*" : " ";
|
|
11827
|
+
const headerNames = Object.keys(environment.headers ?? {});
|
|
11828
|
+
this.log(`${active} ${name}`);
|
|
11829
|
+
if (environment.api_base_url_1) this.log(` api_base_url_1: ${environment.api_base_url_1}`);
|
|
11830
|
+
if (environment.api_base_url_2) this.log(` api_base_url_2: ${environment.api_base_url_2}`);
|
|
11831
|
+
this.log(` headers: ${headerNames.length > 0 ? headerNames.join(", ") : "(none)"}`);
|
|
11832
|
+
}
|
|
11833
|
+
}
|
|
11834
|
+
};
|
|
11835
|
+
var ConfigResetCommand = class ConfigResetCommand extends Command {
|
|
11836
|
+
static hidden = true;
|
|
11837
|
+
static summary = "Reset hidden Primitive CLI request config";
|
|
11838
|
+
static flags = { environment: Flags.string({
|
|
11839
|
+
char: "e",
|
|
11840
|
+
description: "Only remove one environment"
|
|
11841
|
+
}) };
|
|
11842
|
+
async run() {
|
|
11843
|
+
const { flags } = await this.parse(ConfigResetCommand);
|
|
11844
|
+
if (flags.environment === void 0) {
|
|
11845
|
+
deleteCliConfig(this.config.configDir);
|
|
11846
|
+
process.stderr.write("Primitive CLI request config reset.\n");
|
|
11847
|
+
return;
|
|
11848
|
+
}
|
|
11849
|
+
const environment = normalizeCliEnvironmentName(flags.environment);
|
|
11850
|
+
const config = loadCliConfig(this.config.configDir);
|
|
11851
|
+
if (!config?.environments[environment]) {
|
|
11852
|
+
process.stderr.write(`Primitive CLI environment ${environment} was not configured.\n`);
|
|
11853
|
+
return;
|
|
11854
|
+
}
|
|
11855
|
+
const nextConfig = removeCliEnvironment(config, environment);
|
|
11856
|
+
if (Object.keys(nextConfig.environments).length === 0) deleteCliConfig(this.config.configDir);
|
|
11857
|
+
else saveCliConfig(this.config.configDir, nextConfig);
|
|
11858
|
+
process.stderr.write(`Primitive CLI environment ${environment} removed.\n`);
|
|
11859
|
+
}
|
|
11860
|
+
};
|
|
11861
|
+
//#endregion
|
|
11485
11862
|
//#region src/oclif/commands/doctor.ts
|
|
11486
11863
|
const MIN_NODE_MAJOR = 22;
|
|
11487
11864
|
function renderRow({ label, outcome }) {
|
|
@@ -11580,14 +11957,10 @@ function checkApiKey(opts) {
|
|
|
11580
11957
|
hint: "Run `primitive login`, pass --api-key explicitly, or export PRIMITIVE_API_KEY=prim_..."
|
|
11581
11958
|
};
|
|
11582
11959
|
}
|
|
11583
|
-
async function checkAccount(
|
|
11960
|
+
async function checkAccount(client) {
|
|
11584
11961
|
try {
|
|
11585
11962
|
const result = await getAccount({
|
|
11586
|
-
client:
|
|
11587
|
-
apiKey: opts.apiKey,
|
|
11588
|
-
apiBaseUrl1: opts.apiBaseUrl1,
|
|
11589
|
-
apiBaseUrl2: opts.apiBaseUrl2
|
|
11590
|
-
}).client,
|
|
11963
|
+
client: client.client,
|
|
11591
11964
|
responseStyle: "fields"
|
|
11592
11965
|
});
|
|
11593
11966
|
const apiError = result.error;
|
|
@@ -11628,14 +12001,10 @@ async function checkAccount(opts) {
|
|
|
11628
12001
|
};
|
|
11629
12002
|
}
|
|
11630
12003
|
}
|
|
11631
|
-
async function checkDomains(
|
|
12004
|
+
async function checkDomains(client) {
|
|
11632
12005
|
try {
|
|
11633
12006
|
const result = await listDomains({
|
|
11634
|
-
client:
|
|
11635
|
-
apiKey: opts.apiKey,
|
|
11636
|
-
apiBaseUrl1: opts.apiBaseUrl1,
|
|
11637
|
-
apiBaseUrl2: opts.apiBaseUrl2
|
|
11638
|
-
}).client,
|
|
12007
|
+
client: client.client,
|
|
11639
12008
|
responseStyle: "fields"
|
|
11640
12009
|
});
|
|
11641
12010
|
if (result.error) return {
|
|
@@ -11706,28 +12075,20 @@ var DoctorCommand = class DoctorCommand extends Command {
|
|
|
11706
12075
|
outcome: apiKeyCheck
|
|
11707
12076
|
});
|
|
11708
12077
|
if (apiKeyCheck.status !== "fail") {
|
|
11709
|
-
const auth =
|
|
12078
|
+
const { apiClient, auth } = createAuthenticatedCliApiClient({
|
|
11710
12079
|
apiKey: flags["api-key"],
|
|
11711
12080
|
apiBaseUrl1: flags["api-base-url-1"],
|
|
11712
12081
|
apiBaseUrl2: flags["api-base-url-2"],
|
|
11713
12082
|
configDir: this.config.configDir
|
|
11714
12083
|
});
|
|
11715
12084
|
if (auth.apiKey !== void 0) {
|
|
11716
|
-
const accountCheck = await checkAccount(
|
|
11717
|
-
apiKey: auth.apiKey,
|
|
11718
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
11719
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
11720
|
-
});
|
|
12085
|
+
const accountCheck = await checkAccount(apiClient);
|
|
11721
12086
|
rows.push({
|
|
11722
12087
|
label: "API auth",
|
|
11723
12088
|
outcome: accountCheck.outcome
|
|
11724
12089
|
});
|
|
11725
12090
|
if (accountCheck.outcome.status === "ok") {
|
|
11726
|
-
const domainsOutcome = await checkDomains(
|
|
11727
|
-
apiKey: auth.apiKey,
|
|
11728
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
11729
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
11730
|
-
});
|
|
12091
|
+
const domainsOutcome = await checkDomains(apiClient);
|
|
11731
12092
|
rows.push({
|
|
11732
12093
|
label: "Domains",
|
|
11733
12094
|
outcome: domainsOutcome
|
|
@@ -11821,19 +12182,14 @@ var EmailsLatestCommand = class EmailsLatestCommand extends Command {
|
|
|
11821
12182
|
async run() {
|
|
11822
12183
|
const { flags } = await this.parse(EmailsLatestCommand);
|
|
11823
12184
|
await runWithTiming(flags.time, async () => {
|
|
11824
|
-
const
|
|
11825
|
-
const auth = resolveCliAuth({
|
|
12185
|
+
const { apiClient, auth, baseUrlOverridden } = createAuthenticatedCliApiClient({
|
|
11826
12186
|
apiKey: flags["api-key"],
|
|
11827
12187
|
apiBaseUrl1: flags["api-base-url-1"],
|
|
11828
12188
|
apiBaseUrl2: flags["api-base-url-2"],
|
|
11829
12189
|
configDir: this.config.configDir
|
|
11830
12190
|
});
|
|
11831
12191
|
const result = await listEmails({
|
|
11832
|
-
client:
|
|
11833
|
-
apiKey: auth.apiKey,
|
|
11834
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
11835
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
11836
|
-
}).client,
|
|
12192
|
+
client: apiClient.client,
|
|
11837
12193
|
query: { limit: flags.limit },
|
|
11838
12194
|
responseStyle: "fields"
|
|
11839
12195
|
});
|
|
@@ -12030,18 +12386,12 @@ var EmailsWaitCommand = class EmailsWaitCommand extends Command {
|
|
|
12030
12386
|
};
|
|
12031
12387
|
async run() {
|
|
12032
12388
|
const { flags } = await this.parse(EmailsWaitCommand);
|
|
12033
|
-
const
|
|
12034
|
-
const auth = resolveCliAuth({
|
|
12389
|
+
const { apiClient, auth, baseUrlOverridden } = createAuthenticatedCliApiClient({
|
|
12035
12390
|
apiKey: flags["api-key"],
|
|
12036
12391
|
apiBaseUrl1: flags["api-base-url-1"],
|
|
12037
12392
|
apiBaseUrl2: flags["api-base-url-2"],
|
|
12038
12393
|
configDir: this.config.configDir
|
|
12039
12394
|
});
|
|
12040
|
-
const apiClient = new PrimitiveApiClient({
|
|
12041
|
-
apiKey: auth.apiKey,
|
|
12042
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
12043
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
12044
|
-
});
|
|
12045
12395
|
let since;
|
|
12046
12396
|
try {
|
|
12047
12397
|
since = sinceFromFlags(flags);
|
|
@@ -12158,18 +12508,12 @@ var EmailsWatchCommand = class EmailsWatchCommand extends Command {
|
|
|
12158
12508
|
};
|
|
12159
12509
|
async run() {
|
|
12160
12510
|
const { flags } = await this.parse(EmailsWatchCommand);
|
|
12161
|
-
const
|
|
12162
|
-
const auth = resolveCliAuth({
|
|
12511
|
+
const { apiClient, auth, baseUrlOverridden } = createAuthenticatedCliApiClient({
|
|
12163
12512
|
apiKey: flags["api-key"],
|
|
12164
12513
|
apiBaseUrl1: flags["api-base-url-1"],
|
|
12165
12514
|
apiBaseUrl2: flags["api-base-url-2"],
|
|
12166
12515
|
configDir: this.config.configDir
|
|
12167
12516
|
});
|
|
12168
|
-
const apiClient = new PrimitiveApiClient({
|
|
12169
|
-
apiKey: auth.apiKey,
|
|
12170
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
12171
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
12172
|
-
});
|
|
12173
12517
|
let since;
|
|
12174
12518
|
try {
|
|
12175
12519
|
since = sinceFromFlags(flags);
|
|
@@ -12860,18 +13204,12 @@ var FunctionsDeployCommand = class FunctionsDeployCommand extends Command {
|
|
|
12860
13204
|
const code = readTextFileFlag(flags.file, "--file");
|
|
12861
13205
|
const sourceMap = flags["source-map-file"] ? readTextFileFlag(flags["source-map-file"], "--source-map-file") : void 0;
|
|
12862
13206
|
emitRawSendMailFetchWarning(code, (chunk) => process.stderr.write(chunk));
|
|
12863
|
-
const
|
|
12864
|
-
const auth = resolveCliAuth({
|
|
13207
|
+
const { apiClient, auth, baseUrlOverridden } = createAuthenticatedCliApiClient({
|
|
12865
13208
|
apiKey: flags["api-key"],
|
|
12866
13209
|
apiBaseUrl1: flags["api-base-url-1"],
|
|
12867
13210
|
apiBaseUrl2: flags["api-base-url-2"],
|
|
12868
13211
|
configDir: this.config.configDir
|
|
12869
13212
|
});
|
|
12870
|
-
const apiClient = new PrimitiveApiClient({
|
|
12871
|
-
apiKey: auth.apiKey,
|
|
12872
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
12873
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
12874
|
-
});
|
|
12875
13213
|
const authFailureContext = {
|
|
12876
13214
|
auth,
|
|
12877
13215
|
baseUrlOverridden,
|
|
@@ -12978,8 +13316,8 @@ const PRIMITIVE_TEAM_AUTHOR = {
|
|
|
12978
13316
|
name: "Primitive Team",
|
|
12979
13317
|
url: "https://primitive.dev"
|
|
12980
13318
|
};
|
|
12981
|
-
const SDK_VERSION_RANGE = "^0.30.
|
|
12982
|
-
const CLI_VERSION_RANGE = "^0.30.
|
|
13319
|
+
const SDK_VERSION_RANGE = "^0.30.1";
|
|
13320
|
+
const CLI_VERSION_RANGE = "^0.30.1";
|
|
12983
13321
|
const ESBUILD_VERSION_RANGE = "^0.27.0";
|
|
12984
13322
|
function renderHandler() {
|
|
12985
13323
|
return `// env.PRIMITIVE_API_KEY is auto-injected by the Primitive Functions runtime.
|
|
@@ -13001,14 +13339,14 @@ import {
|
|
|
13001
13339
|
// the loop guard recognizes mail returning to it as self-traffic.
|
|
13002
13340
|
const REPLY_FROM = "you@your-domain.primitive.email";
|
|
13003
13341
|
|
|
13004
|
-
// Loop protection. A deployed Function
|
|
13005
|
-
//
|
|
13006
|
-
//
|
|
13007
|
-
//
|
|
13008
|
-
// fan-out loop.
|
|
13342
|
+
// Loop protection. A newly deployed Function starts as a fallback
|
|
13343
|
+
// endpoint for managed *.primitive.email domains that do not have a
|
|
13344
|
+
// domain-scoped endpoint. That can include bounces and auto-replies
|
|
13345
|
+
// generated by the handler's own outbound traffic. Without this guard
|
|
13346
|
+
// the handler can respond to its own bounces and create a fan-out loop.
|
|
13009
13347
|
//
|
|
13010
13348
|
// The default check returns true when From is on any *.primitive.email
|
|
13011
|
-
// address (covers
|
|
13349
|
+
// address (covers managed-domain fallback mail, the simple
|
|
13012
13350
|
// self-reply case, and bounces from mailer-daemon@*.primitive.email)
|
|
13013
13351
|
// or when From contains REPLY_FROM as a case-insensitive substring.
|
|
13014
13352
|
// Substring matching is deliberate so display-name forms like
|
|
@@ -13462,18 +13800,12 @@ var FunctionsLogsCommand = class FunctionsLogsCommand extends Command {
|
|
|
13462
13800
|
if (flags["poll-interval"] <= 0) this.error("--poll-interval must be greater than 0.", { exit: 2 });
|
|
13463
13801
|
if (flags.follow && flags.cursor) this.error("--cursor cannot be combined with --follow.", { exit: 2 });
|
|
13464
13802
|
await runWithTiming(flags.time, async () => {
|
|
13465
|
-
const
|
|
13466
|
-
const auth = resolveCliAuth({
|
|
13803
|
+
const { apiClient, auth, baseUrlOverridden } = createAuthenticatedCliApiClient({
|
|
13467
13804
|
apiKey: flags["api-key"],
|
|
13468
13805
|
apiBaseUrl1: flags["api-base-url-1"],
|
|
13469
13806
|
apiBaseUrl2: flags["api-base-url-2"],
|
|
13470
13807
|
configDir: this.config.configDir
|
|
13471
13808
|
});
|
|
13472
|
-
const apiClient = new PrimitiveApiClient({
|
|
13473
|
-
apiKey: auth.apiKey,
|
|
13474
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
13475
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
13476
|
-
});
|
|
13477
13809
|
const seenIds = /* @__PURE__ */ new Set();
|
|
13478
13810
|
let completedInitialFollowPoll = false;
|
|
13479
13811
|
let hasObservedLogs = false;
|
|
@@ -13704,18 +14036,12 @@ var FunctionsRedeployCommand = class FunctionsRedeployCommand extends Command {
|
|
|
13704
14036
|
const code = readTextFileFlag(flags.file, "--file");
|
|
13705
14037
|
const sourceMap = flags["source-map-file"] ? readTextFileFlag(flags["source-map-file"], "--source-map-file") : void 0;
|
|
13706
14038
|
emitRawSendMailFetchWarning(code, (chunk) => process.stderr.write(chunk));
|
|
13707
|
-
const
|
|
13708
|
-
const auth = resolveCliAuth({
|
|
14039
|
+
const { apiClient, auth, baseUrlOverridden } = createAuthenticatedCliApiClient({
|
|
13709
14040
|
apiKey: flags["api-key"],
|
|
13710
14041
|
apiBaseUrl1: flags["api-base-url-1"],
|
|
13711
14042
|
apiBaseUrl2: flags["api-base-url-2"],
|
|
13712
14043
|
configDir: this.config.configDir
|
|
13713
14044
|
});
|
|
13714
|
-
const apiClient = new PrimitiveApiClient({
|
|
13715
|
-
apiKey: auth.apiKey,
|
|
13716
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
13717
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
13718
|
-
});
|
|
13719
14045
|
const authFailureContext = {
|
|
13720
14046
|
auth,
|
|
13721
14047
|
baseUrlOverridden,
|
|
@@ -13925,18 +14251,12 @@ var FunctionsSetSecretCommand = class FunctionsSetSecretCommand extends Command
|
|
|
13925
14251
|
async run() {
|
|
13926
14252
|
const { flags } = await this.parse(FunctionsSetSecretCommand);
|
|
13927
14253
|
await runWithTiming(flags.time, async () => {
|
|
13928
|
-
const
|
|
13929
|
-
const auth = resolveCliAuth({
|
|
14254
|
+
const { apiClient, auth, baseUrlOverridden } = createAuthenticatedCliApiClient({
|
|
13930
14255
|
apiKey: flags["api-key"],
|
|
13931
14256
|
apiBaseUrl1: flags["api-base-url-1"],
|
|
13932
14257
|
apiBaseUrl2: flags["api-base-url-2"],
|
|
13933
14258
|
configDir: this.config.configDir
|
|
13934
14259
|
});
|
|
13935
|
-
const apiClient = new PrimitiveApiClient({
|
|
13936
|
-
apiKey: auth.apiKey,
|
|
13937
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
13938
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
13939
|
-
});
|
|
13940
14260
|
const authFailureContext = {
|
|
13941
14261
|
auth,
|
|
13942
14262
|
baseUrlOverridden,
|
|
@@ -14053,7 +14373,8 @@ function stringOrNull(value) {
|
|
|
14053
14373
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
14054
14374
|
}
|
|
14055
14375
|
function findMatchingFunctionEndpoints(params) {
|
|
14056
|
-
const
|
|
14376
|
+
const domainMatches = [];
|
|
14377
|
+
const fallbackMatches = [];
|
|
14057
14378
|
for (const endpoint of params.endpoints) {
|
|
14058
14379
|
if (endpoint.kind !== "function") continue;
|
|
14059
14380
|
if (endpoint.enabled === false) continue;
|
|
@@ -14063,20 +14384,22 @@ function findMatchingFunctionEndpoints(params) {
|
|
|
14063
14384
|
const domainId = stringOrNull(endpoint.domain_id);
|
|
14064
14385
|
if (domainId !== null && (params.inboundDomainId === null || domainId !== params.inboundDomainId)) continue;
|
|
14065
14386
|
const functionId = stringOrNull(endpoint.function_id);
|
|
14066
|
-
|
|
14387
|
+
const match = {
|
|
14067
14388
|
function_id: functionId,
|
|
14068
14389
|
id,
|
|
14069
14390
|
is_current_function: functionId === params.currentFunctionId,
|
|
14070
|
-
scope: domainId === null ? "
|
|
14071
|
-
}
|
|
14391
|
+
scope: domainId === null ? "fallback" : "domain"
|
|
14392
|
+
};
|
|
14393
|
+
if (domainId === null) fallbackMatches.push(match);
|
|
14394
|
+
else domainMatches.push(match);
|
|
14072
14395
|
}
|
|
14073
|
-
return
|
|
14396
|
+
return domainMatches.length > 0 ? domainMatches : fallbackMatches;
|
|
14074
14397
|
}
|
|
14075
14398
|
function formatFunctionEndpointNoiseWarning(params) {
|
|
14076
14399
|
if (params.endpoints.filter((endpoint) => !endpoint.is_current_function).length === 0) return null;
|
|
14077
14400
|
const lines = [`Warning: ${params.endpoints.length} function endpoints may receive mail for ${params.toAddress}:`];
|
|
14078
14401
|
for (const endpoint of params.endpoints) {
|
|
14079
|
-
const scope = endpoint.scope === "
|
|
14402
|
+
const scope = endpoint.scope === "fallback" ? "fallback" : `scoped to ${params.inboundDomain}`;
|
|
14080
14403
|
const current = endpoint.is_current_function ? " (this function)" : "";
|
|
14081
14404
|
const target = endpoint.function_id ? ` -> function ${endpoint.function_id}` : "";
|
|
14082
14405
|
lines.push(`- endpoint ${endpoint.id}${target}, ${scope}${current}`);
|
|
@@ -14155,18 +14478,12 @@ var FunctionsTestFunctionCommand = class FunctionsTestFunctionCommand extends Co
|
|
|
14155
14478
|
const { flags } = await this.parse(FunctionsTestFunctionCommand);
|
|
14156
14479
|
const shouldWait = flags.wait || flags["show-sends"];
|
|
14157
14480
|
const shouldShowSends = flags["show-sends"];
|
|
14158
|
-
const baseUrlOverridden =
|
|
14159
|
-
const auth = resolveCliAuth({
|
|
14481
|
+
const { apiClient, auth, baseUrlOverridden } = createAuthenticatedCliApiClient({
|
|
14160
14482
|
apiKey: flags["api-key"],
|
|
14161
14483
|
apiBaseUrl1: flags["api-base-url-1"],
|
|
14162
14484
|
apiBaseUrl2: flags["api-base-url-2"],
|
|
14163
14485
|
configDir: this.config.configDir
|
|
14164
14486
|
});
|
|
14165
|
-
const apiClient = new PrimitiveApiClient({
|
|
14166
|
-
apiKey: auth.apiKey,
|
|
14167
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
14168
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
14169
|
-
});
|
|
14170
14487
|
await runWithTiming(flags.time, async () => {
|
|
14171
14488
|
const triggerResult = await testFunction({
|
|
14172
14489
|
client: apiClient.client,
|
|
@@ -14306,11 +14623,16 @@ function retryAfterSeconds$1(result) {
|
|
|
14306
14623
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
14307
14624
|
}
|
|
14308
14625
|
async function checkExistingLogin(params) {
|
|
14309
|
-
const
|
|
14310
|
-
|
|
14626
|
+
const requestConfig = resolveCliApiRequestConfig({
|
|
14627
|
+
apiBaseUrl1: params.apiBaseUrl1,
|
|
14628
|
+
configDir: params.configDir
|
|
14629
|
+
});
|
|
14630
|
+
const probeApiBaseUrl1 = requestConfig.apiBaseUrl1 ?? params.credentials.api_base_url_1;
|
|
14311
14631
|
const apiClient = new PrimitiveApiClient({
|
|
14312
14632
|
apiKey: params.credentials.api_key,
|
|
14313
|
-
apiBaseUrl1: probeApiBaseUrl1
|
|
14633
|
+
apiBaseUrl1: probeApiBaseUrl1,
|
|
14634
|
+
apiBaseUrl2: requestConfig.resolvedApiBaseUrl2,
|
|
14635
|
+
headers: requestConfig.headers
|
|
14314
14636
|
});
|
|
14315
14637
|
const result = await (params.checkAccount ?? ((client) => getAccount({
|
|
14316
14638
|
client: client.client,
|
|
@@ -14326,7 +14648,7 @@ async function checkExistingLogin(params) {
|
|
|
14326
14648
|
credentials: params.credentials,
|
|
14327
14649
|
source: "stored"
|
|
14328
14650
|
},
|
|
14329
|
-
baseUrlOverridden,
|
|
14651
|
+
baseUrlOverridden: requestConfig.baseUrlOverridden,
|
|
14330
14652
|
configDir: params.configDir,
|
|
14331
14653
|
payload
|
|
14332
14654
|
})) return { status: "removed_stale" };
|
|
@@ -14372,7 +14694,11 @@ var LoginCommand = class LoginCommand extends Command {
|
|
|
14372
14694
|
}
|
|
14373
14695
|
}
|
|
14374
14696
|
async runWithCredentialLock(flags) {
|
|
14375
|
-
const
|
|
14697
|
+
const { apiClient, requestConfig } = createCliApiClient({
|
|
14698
|
+
apiBaseUrl1: flags["api-base-url-1"],
|
|
14699
|
+
configDir: this.config.configDir
|
|
14700
|
+
});
|
|
14701
|
+
const apiBaseUrl1 = requestConfig.resolvedApiBaseUrl1;
|
|
14376
14702
|
let existing;
|
|
14377
14703
|
try {
|
|
14378
14704
|
existing = loadCliCredentials(this.config.configDir);
|
|
@@ -14395,7 +14721,6 @@ var LoginCommand = class LoginCommand extends Command {
|
|
|
14395
14721
|
throw cliError$2(existingStatus.message);
|
|
14396
14722
|
} else throw cliError$2(`Already logged in${existing.org_name ? ` for ${existing.org_name}` : ""}. Run \`primitive logout\` before logging in again.`);
|
|
14397
14723
|
}
|
|
14398
|
-
const apiClient = new PrimitiveApiClient({ apiBaseUrl1 });
|
|
14399
14724
|
const started = await startCliLogin({
|
|
14400
14725
|
body: { device_name: flags["device-name"] ?? hostname() },
|
|
14401
14726
|
client: apiClient.client,
|
|
@@ -14505,10 +14830,15 @@ var LogoutCommand = class LogoutCommand extends Command {
|
|
|
14505
14830
|
return;
|
|
14506
14831
|
}
|
|
14507
14832
|
if (!credentials) throw cliError$1("Not logged in. Run `primitive login` to create saved CLI credentials.");
|
|
14508
|
-
const
|
|
14833
|
+
const requestConfig = resolveCliApiRequestConfig({
|
|
14834
|
+
apiBaseUrl1: flags["api-base-url-1"],
|
|
14835
|
+
configDir: this.config.configDir
|
|
14836
|
+
});
|
|
14837
|
+
const apiBaseUrl1 = requestConfig.apiBaseUrl1 ? normalizeApiBaseUrl1(requestConfig.apiBaseUrl1) : credentials.api_base_url_1;
|
|
14509
14838
|
const apiClient = new PrimitiveApiClient({
|
|
14510
14839
|
apiKey: credentials.api_key,
|
|
14511
|
-
apiBaseUrl1
|
|
14840
|
+
apiBaseUrl1,
|
|
14841
|
+
headers: requestConfig.headers
|
|
14512
14842
|
});
|
|
14513
14843
|
const result = await cliLogout({
|
|
14514
14844
|
body: { key_id: credentials.key_id },
|
|
@@ -14689,18 +15019,12 @@ var ReplyCommand = class ReplyCommand extends Command {
|
|
|
14689
15019
|
});
|
|
14690
15020
|
if (bodies.kind === "error") throw new Errors.CLIError(bodies.message);
|
|
14691
15021
|
await runWithTiming(flags.time, async () => {
|
|
14692
|
-
const
|
|
14693
|
-
const auth = resolveCliAuth({
|
|
15022
|
+
const { apiClient, auth, baseUrlOverridden } = createAuthenticatedCliApiClient({
|
|
14694
15023
|
apiKey: flags["api-key"],
|
|
14695
15024
|
apiBaseUrl1: flags["api-base-url-1"],
|
|
14696
15025
|
apiBaseUrl2: flags["api-base-url-2"],
|
|
14697
15026
|
configDir: this.config.configDir
|
|
14698
15027
|
});
|
|
14699
|
-
const apiClient = new PrimitiveApiClient({
|
|
14700
|
-
apiKey: auth.apiKey,
|
|
14701
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
14702
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
14703
|
-
});
|
|
14704
15028
|
const result = await replyToEmail({
|
|
14705
15029
|
body: {
|
|
14706
15030
|
...bodies.body !== void 0 ? { body_text: bodies.body } : {},
|
|
@@ -14829,18 +15153,12 @@ var SendCommand = class SendCommand extends Command {
|
|
|
14829
15153
|
});
|
|
14830
15154
|
if (bodies.kind === "error") throw new Errors.CLIError(bodies.message);
|
|
14831
15155
|
await runWithTiming(flags.time, async () => {
|
|
14832
|
-
const
|
|
14833
|
-
const auth = resolveCliAuth({
|
|
15156
|
+
const { apiClient, auth, baseUrlOverridden } = createAuthenticatedCliApiClient({
|
|
14834
15157
|
apiKey: flags["api-key"],
|
|
14835
15158
|
apiBaseUrl1: flags["api-base-url-1"],
|
|
14836
15159
|
apiBaseUrl2: flags["api-base-url-2"],
|
|
14837
15160
|
configDir: this.config.configDir
|
|
14838
15161
|
});
|
|
14839
|
-
const apiClient = new PrimitiveApiClient({
|
|
14840
|
-
apiKey: auth.apiKey,
|
|
14841
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
14842
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
14843
|
-
});
|
|
14844
15162
|
const authFailureContext = {
|
|
14845
15163
|
auth,
|
|
14846
15164
|
baseUrlOverridden,
|
|
@@ -15113,7 +15431,11 @@ async function runSignupWithCredentialLock(params) {
|
|
|
15113
15431
|
const startFn = deps.startCliSignup ?? startCliSignup;
|
|
15114
15432
|
const verifyFn = deps.verifyCliSignup ?? verifyCliSignup;
|
|
15115
15433
|
const checkExistingLoginFn = deps.checkExistingLogin ?? checkExistingLogin;
|
|
15116
|
-
const
|
|
15434
|
+
const { apiClient, requestConfig } = createCliApiClient({
|
|
15435
|
+
apiBaseUrl1: flags["api-base-url-1"],
|
|
15436
|
+
configDir
|
|
15437
|
+
});
|
|
15438
|
+
const apiBaseUrl1 = requestConfig.resolvedApiBaseUrl1;
|
|
15117
15439
|
let existing;
|
|
15118
15440
|
try {
|
|
15119
15441
|
existing = loadCliCredentials(configDir);
|
|
@@ -15137,7 +15459,6 @@ async function runSignupWithCredentialLock(params) {
|
|
|
15137
15459
|
} else throw cliError(`Already logged in${existing.org_name ? ` for ${existing.org_name}` : ""}. Run \`primitive logout\` before creating a new account.`);
|
|
15138
15460
|
}
|
|
15139
15461
|
if (flags.force) deletePendingCliSignup(configDir);
|
|
15140
|
-
const apiClient = new PrimitiveApiClient({ apiBaseUrl1 });
|
|
15141
15462
|
let start = flags.force ? null : loadPendingCliSignup(configDir, apiBaseUrl1);
|
|
15142
15463
|
const resumed = Boolean(start);
|
|
15143
15464
|
if (start) process$1.stderr.write(`Continuing pending Primitive CLI signup for ${start.email}.\n`);
|
|
@@ -15294,19 +15615,14 @@ var WhoamiCommand = class WhoamiCommand extends Command {
|
|
|
15294
15615
|
async run() {
|
|
15295
15616
|
const { flags } = await this.parse(WhoamiCommand);
|
|
15296
15617
|
await runWithTiming(flags.time, async () => {
|
|
15297
|
-
const
|
|
15298
|
-
const auth = resolveCliAuth({
|
|
15618
|
+
const { apiClient, auth, baseUrlOverridden } = createAuthenticatedCliApiClient({
|
|
15299
15619
|
apiKey: flags["api-key"],
|
|
15300
15620
|
apiBaseUrl1: flags["api-base-url-1"],
|
|
15301
15621
|
apiBaseUrl2: flags["api-base-url-2"],
|
|
15302
15622
|
configDir: this.config.configDir
|
|
15303
15623
|
});
|
|
15304
15624
|
const result = await getAccount({
|
|
15305
|
-
client:
|
|
15306
|
-
apiKey: auth.apiKey,
|
|
15307
|
-
apiBaseUrl1: auth.apiBaseUrl1,
|
|
15308
|
-
apiBaseUrl2: auth.apiBaseUrl2
|
|
15309
|
-
}).client,
|
|
15625
|
+
client: apiClient.client,
|
|
15310
15626
|
responseStyle: "fields"
|
|
15311
15627
|
});
|
|
15312
15628
|
if (result.error) {
|
|
@@ -15535,6 +15851,10 @@ const generatedCommands = Object.fromEntries(operationManifest.filter((operation
|
|
|
15535
15851
|
const COMMANDS = {
|
|
15536
15852
|
completion: CompletionCommand,
|
|
15537
15853
|
"list-operations": ListOperationsCommand,
|
|
15854
|
+
"config:list": ConfigListCommand,
|
|
15855
|
+
"config:reset": ConfigResetCommand,
|
|
15856
|
+
"config:set": ConfigSetCommand,
|
|
15857
|
+
"config:use": ConfigUseCommand,
|
|
15538
15858
|
describe: DescribeCommand,
|
|
15539
15859
|
send: SendCommand,
|
|
15540
15860
|
reply: ReplyCommand,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
1
2
|
//#region src/oclif/proxy-auto-detect.ts
|
|
2
3
|
const PROXY_ENV_VARS = [
|
|
3
4
|
"HTTP_PROXY",
|
|
@@ -15,7 +16,7 @@ function detectProxyVars(env) {
|
|
|
15
16
|
return typeof value === "string" && value.length > 0;
|
|
16
17
|
});
|
|
17
18
|
}
|
|
18
|
-
function
|
|
19
|
+
function restartWithProxyEnvIfNeeded(options = {}) {
|
|
19
20
|
const env = options.env ?? process.env;
|
|
20
21
|
const stderr = options.stderr ?? process.stderr;
|
|
21
22
|
const detectedVars = detectProxyVars(env);
|
|
@@ -29,17 +30,42 @@ function applyProxyAutoDetect(options = {}) {
|
|
|
29
30
|
detectedVars,
|
|
30
31
|
reason: "node_use_env_proxy_already_set"
|
|
31
32
|
};
|
|
32
|
-
|
|
33
|
+
const argv = options.argv ?? process.argv;
|
|
34
|
+
const entrypoint = argv[1];
|
|
35
|
+
if (!entrypoint) return {
|
|
36
|
+
applied: false,
|
|
37
|
+
detectedVars,
|
|
38
|
+
reason: "missing_entrypoint"
|
|
39
|
+
};
|
|
40
|
+
const execPath = options.execPath ?? process.execPath;
|
|
41
|
+
const execArgv = options.execArgv ?? process.execArgv;
|
|
42
|
+
const spawn = options.spawn ?? spawnSync;
|
|
43
|
+
const exit = options.exit ?? ((code) => {
|
|
44
|
+
process.exit(code);
|
|
45
|
+
throw new Error("process.exit returned unexpectedly");
|
|
46
|
+
});
|
|
33
47
|
if (!hintPrinted) {
|
|
34
48
|
hintPrinted = true;
|
|
35
49
|
const names = detectedVars.join("/");
|
|
36
|
-
stderr.write(`primitive: proxy detected via ${names}, NODE_USE_ENV_PROXY=1
|
|
50
|
+
stderr.write(`primitive: proxy detected via ${names}, restarting with NODE_USE_ENV_PROXY=1\n`);
|
|
37
51
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
const child = spawn(execPath, [
|
|
53
|
+
...execArgv,
|
|
54
|
+
entrypoint,
|
|
55
|
+
...argv.slice(2)
|
|
56
|
+
], {
|
|
57
|
+
env: {
|
|
58
|
+
...env,
|
|
59
|
+
NODE_USE_ENV_PROXY: "1"
|
|
60
|
+
},
|
|
61
|
+
stdio: "inherit"
|
|
62
|
+
});
|
|
63
|
+
if (child.error) throw child.error;
|
|
64
|
+
if (child.signal) {
|
|
65
|
+
(options.kill ?? process.kill)(options.pid ?? process.pid, child.signal);
|
|
66
|
+
return exit(1);
|
|
67
|
+
}
|
|
68
|
+
return exit(child.status ?? 1);
|
|
43
69
|
}
|
|
44
70
|
//#endregion
|
|
45
|
-
export { _resetHintLatchForTest,
|
|
71
|
+
export { _resetHintLatchForTest, restartWithProxyEnvIfNeeded };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primitivedotdev/cli",
|
|
3
|
-
"version": "0.30.
|
|
3
|
+
"version": "0.30.1",
|
|
4
4
|
"description": "Official Primitive CLI: deploy Primitive Functions, send and inspect mail, manage endpoints, all from the terminal. Wraps the @primitivedotdev/sdk runtime client with one-shot commands.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|