@primitivedotdev/sdk 0.20.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.
- package/dist/api/generated/index.js +1 -1
- package/dist/api/generated/sdk.gen.js +30 -0
- package/dist/api/index.d.ts +2 -2
- package/dist/api/index.js +40 -5
- package/dist/{api-DNF21MDo.js → api-BjzvA2Fy.js} +63 -6
- package/dist/{index-C6ObsYjq.d.ts → index-QTYQpSFt.d.ts} +215 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/oclif/api-command.js +74 -13
- package/dist/oclif/auth.js +65 -10
- package/dist/oclif/commands/emails-latest.js +23 -12
- package/dist/oclif/commands/emails-poll.js +121 -0
- package/dist/oclif/commands/emails-wait.js +171 -0
- package/dist/oclif/commands/emails-watch.js +165 -0
- package/dist/oclif/commands/functions-deploy.js +15 -6
- package/dist/oclif/commands/functions-redeploy.js +15 -6
- package/dist/oclif/commands/login.js +18 -14
- package/dist/oclif/commands/logout.js +9 -8
- package/dist/oclif/commands/send.js +21 -7
- package/dist/oclif/commands/whoami.js +15 -6
- package/dist/oclif/fish-completion.js +1 -1
- package/dist/oclif/index.js +6 -0
- package/dist/openapi/openapi.generated.js +397 -2
- package/dist/openapi/operations.generated.js +305 -1
- package/oclif.manifest.json +1327 -281
- package/package.json +1 -1
|
@@ -321,7 +321,7 @@ type Options$1<TData extends TDataShape = TDataShape, ThrowOnError extends boole
|
|
|
321
321
|
//#endregion
|
|
322
322
|
//#region src/api/generated/types.gen.d.ts
|
|
323
323
|
type ClientOptions = {
|
|
324
|
-
baseUrl: 'https://www.primitive.dev/api/v1' | (string & {});
|
|
324
|
+
baseUrl: 'https://www.primitive.dev/api/v1' | 'https://api.primitive.dev/v1' | 'https://api.primitive.dev/v1' | 'https://www.primitive.dev/api/v1' | (string & {});
|
|
325
325
|
};
|
|
326
326
|
type SuccessEnvelope = {
|
|
327
327
|
success: boolean;
|
|
@@ -347,7 +347,7 @@ type PaginationMeta = {
|
|
|
347
347
|
type ErrorResponse = {
|
|
348
348
|
success: boolean;
|
|
349
349
|
error: {
|
|
350
|
-
code: 'unauthorized' | 'forbidden' | 'not_found' | 'validation_error' | 'rate_limit_exceeded' | 'internal_error' | 'conflict' | 'mx_conflict' | 'outbound_disabled' | 'cannot_send_from_domain' | 'recipient_not_allowed' | 'outbound_key_missing' | 'outbound_unreachable' | 'outbound_key_invalid' | 'outbound_capacity_exhausted' | 'outbound_response_malformed' | 'outbound_relay_failed' | 'discard_not_enabled' | 'inbound_not_repliable' | 'authorization_pending' | 'slow_down' | 'access_denied' | 'expired_token' | 'invalid_device_code';
|
|
350
|
+
code: 'unauthorized' | 'forbidden' | 'not_found' | 'validation_error' | 'rate_limit_exceeded' | 'internal_error' | 'conflict' | 'mx_conflict' | 'outbound_disabled' | 'cannot_send_from_domain' | 'recipient_not_allowed' | 'outbound_key_missing' | 'outbound_unreachable' | 'outbound_key_invalid' | 'outbound_capacity_exhausted' | 'outbound_response_malformed' | 'outbound_relay_failed' | 'discard_not_enabled' | 'inbound_not_repliable' | 'search_timeout' | 'authorization_pending' | 'slow_down' | 'access_denied' | 'expired_token' | 'invalid_device_code';
|
|
351
351
|
message: string;
|
|
352
352
|
/**
|
|
353
353
|
* Optional structured data that callers can inspect to recover
|
|
@@ -644,6 +644,66 @@ type EmailSummary = {
|
|
|
644
644
|
webhook_status?: EmailWebhookStatus;
|
|
645
645
|
webhook_attempt_count: number;
|
|
646
646
|
};
|
|
647
|
+
type EmailSearchHighlights = {
|
|
648
|
+
/**
|
|
649
|
+
* Subject snippets with matching terms highlighted.
|
|
650
|
+
*/
|
|
651
|
+
subject: Array<string>;
|
|
652
|
+
/**
|
|
653
|
+
* Body snippets with matching terms highlighted.
|
|
654
|
+
*/
|
|
655
|
+
body: Array<string>;
|
|
656
|
+
};
|
|
657
|
+
type EmailSearchResult = EmailSummary & {
|
|
658
|
+
/**
|
|
659
|
+
* Number of parsed attachments on the email.
|
|
660
|
+
*/
|
|
661
|
+
attachment_count: number;
|
|
662
|
+
/**
|
|
663
|
+
* Whether the parsed From address is known to this org from prior authenticated inbound mail.
|
|
664
|
+
*/
|
|
665
|
+
from_known_address: boolean;
|
|
666
|
+
/**
|
|
667
|
+
* Relevance score. Present only when sorting by relevance.
|
|
668
|
+
*/
|
|
669
|
+
score?: number;
|
|
670
|
+
highlights?: EmailSearchHighlights;
|
|
671
|
+
};
|
|
672
|
+
type EmailSearchMeta = {
|
|
673
|
+
/**
|
|
674
|
+
* Total number of matching records, capped when `total_capped` is true.
|
|
675
|
+
*/
|
|
676
|
+
total: number;
|
|
677
|
+
/**
|
|
678
|
+
* Whether `total` was capped instead of counted exactly.
|
|
679
|
+
*/
|
|
680
|
+
total_capped: boolean;
|
|
681
|
+
/**
|
|
682
|
+
* Page size used for this request.
|
|
683
|
+
*/
|
|
684
|
+
limit: number;
|
|
685
|
+
/**
|
|
686
|
+
* Cursor for the next search page, or null if no more results.
|
|
687
|
+
*/
|
|
688
|
+
cursor: string | null;
|
|
689
|
+
/**
|
|
690
|
+
* Sort mode used for the result page.
|
|
691
|
+
*/
|
|
692
|
+
sort: 'relevance' | 'received_at_desc' | 'received_at_asc';
|
|
693
|
+
};
|
|
694
|
+
type EmailSearchFacetBucket = {
|
|
695
|
+
value: string | null;
|
|
696
|
+
count: number;
|
|
697
|
+
};
|
|
698
|
+
type EmailSearchFacets = {
|
|
699
|
+
by_sender: Array<EmailSearchFacetBucket>;
|
|
700
|
+
by_domain: Array<EmailSearchFacetBucket>;
|
|
701
|
+
by_status: Array<EmailSearchFacetBucket>;
|
|
702
|
+
has_attachment: {
|
|
703
|
+
true: number;
|
|
704
|
+
false: number;
|
|
705
|
+
};
|
|
706
|
+
};
|
|
647
707
|
type EmailDetail = {
|
|
648
708
|
id: string;
|
|
649
709
|
message_id?: string | null;
|
|
@@ -2186,6 +2246,109 @@ type ListEmailsResponses = {
|
|
|
2186
2246
|
};
|
|
2187
2247
|
};
|
|
2188
2248
|
type ListEmailsResponse = ListEmailsResponses[keyof ListEmailsResponses];
|
|
2249
|
+
type SearchEmailsData = {
|
|
2250
|
+
body?: never;
|
|
2251
|
+
path?: never;
|
|
2252
|
+
query?: {
|
|
2253
|
+
/**
|
|
2254
|
+
* Full-text search DSL query.
|
|
2255
|
+
*/
|
|
2256
|
+
q?: string;
|
|
2257
|
+
/**
|
|
2258
|
+
* Filter by sender address or sender domain.
|
|
2259
|
+
*/
|
|
2260
|
+
from?: string;
|
|
2261
|
+
/**
|
|
2262
|
+
* Filter by recipient address or recipient domain.
|
|
2263
|
+
*/
|
|
2264
|
+
to?: string;
|
|
2265
|
+
/**
|
|
2266
|
+
* Full-text search restricted to the subject field.
|
|
2267
|
+
*/
|
|
2268
|
+
subject?: string;
|
|
2269
|
+
/**
|
|
2270
|
+
* Full-text search restricted to the parsed text body.
|
|
2271
|
+
*/
|
|
2272
|
+
body?: string;
|
|
2273
|
+
/**
|
|
2274
|
+
* Filter by domain ID.
|
|
2275
|
+
*/
|
|
2276
|
+
domain_id?: string;
|
|
2277
|
+
/**
|
|
2278
|
+
* Filter by inbound email lifecycle status.
|
|
2279
|
+
*/
|
|
2280
|
+
status?: EmailStatus;
|
|
2281
|
+
/**
|
|
2282
|
+
* Filter emails received on or after this timestamp.
|
|
2283
|
+
*/
|
|
2284
|
+
date_from?: string;
|
|
2285
|
+
/**
|
|
2286
|
+
* Filter emails received on or before this timestamp.
|
|
2287
|
+
*/
|
|
2288
|
+
date_to?: string;
|
|
2289
|
+
/**
|
|
2290
|
+
* Filter by whether the email has one or more attachments.
|
|
2291
|
+
*/
|
|
2292
|
+
has_attachment?: 'true' | 'false';
|
|
2293
|
+
/**
|
|
2294
|
+
* Filter to emails with spam score below this value.
|
|
2295
|
+
*/
|
|
2296
|
+
spam_score_lt?: number;
|
|
2297
|
+
/**
|
|
2298
|
+
* Filter to emails with spam score greater than or equal to this value.
|
|
2299
|
+
*/
|
|
2300
|
+
spam_score_gte?: number;
|
|
2301
|
+
/**
|
|
2302
|
+
* Sort mode. Defaults to relevance when a text query is present,
|
|
2303
|
+
* otherwise `received_at_desc`.
|
|
2304
|
+
*
|
|
2305
|
+
*/
|
|
2306
|
+
sort?: 'relevance' | 'received_at_desc' | 'received_at_asc';
|
|
2307
|
+
/**
|
|
2308
|
+
* Opaque pagination cursor from a previous search response.
|
|
2309
|
+
*/
|
|
2310
|
+
cursor?: string;
|
|
2311
|
+
/**
|
|
2312
|
+
* Number of results per page
|
|
2313
|
+
*/
|
|
2314
|
+
limit?: number;
|
|
2315
|
+
/**
|
|
2316
|
+
* Include subject/body highlight snippets when text search is active.
|
|
2317
|
+
*/
|
|
2318
|
+
snippet?: 'true' | 'false';
|
|
2319
|
+
/**
|
|
2320
|
+
* Include facet counts for sender, domain, status, and attachment presence.
|
|
2321
|
+
*/
|
|
2322
|
+
include_facets?: 'true' | 'false';
|
|
2323
|
+
};
|
|
2324
|
+
url: '/emails/search';
|
|
2325
|
+
};
|
|
2326
|
+
type SearchEmailsErrors = {
|
|
2327
|
+
/**
|
|
2328
|
+
* Invalid request parameters
|
|
2329
|
+
*/
|
|
2330
|
+
400: ErrorResponse;
|
|
2331
|
+
/**
|
|
2332
|
+
* Invalid or missing API key
|
|
2333
|
+
*/
|
|
2334
|
+
401: ErrorResponse;
|
|
2335
|
+
/**
|
|
2336
|
+
* Search query timed out
|
|
2337
|
+
*/
|
|
2338
|
+
504: ErrorResponse;
|
|
2339
|
+
};
|
|
2340
|
+
type SearchEmailsError = SearchEmailsErrors[keyof SearchEmailsErrors];
|
|
2341
|
+
type SearchEmailsResponses = {
|
|
2342
|
+
/**
|
|
2343
|
+
* Search results
|
|
2344
|
+
*/
|
|
2345
|
+
200: SuccessEnvelope & {
|
|
2346
|
+
data: Array<EmailSearchResult>;
|
|
2347
|
+
meta: EmailSearchMeta;
|
|
2348
|
+
facets?: EmailSearchFacets;
|
|
2349
|
+
};
|
|
2350
|
+
};
|
|
2351
|
+
type SearchEmailsResponse = SearchEmailsResponses[keyof SearchEmailsResponses];
|
|
2189
2352
|
type DeleteEmailData = {
|
|
2190
2353
|
body?: never;
|
|
2191
2354
|
path: {
|
|
@@ -3409,7 +3572,7 @@ type SetFunctionSecretResponses = {
|
|
|
3409
3572
|
};
|
|
3410
3573
|
type SetFunctionSecretResponse = SetFunctionSecretResponses[keyof SetFunctionSecretResponses];
|
|
3411
3574
|
declare namespace sdk_gen_d_exports {
|
|
3412
|
-
export { Options, addDomain, cliLogout, createEndpoint, createFilter, createFunction, createFunctionSecret, deleteDomain, deleteEmail, deleteEndpoint, deleteFilter, deleteFunction, deleteFunctionSecret, discardEmailContent, downloadAttachments, downloadRawEmail, getAccount, getEmail, getFunction, getSendPermissions, getSentEmail, getStorageStats, getWebhookSecret, listDeliveries, listDomains, listEmails, listEndpoints, listFilters, listFunctionSecrets, listFunctions, listSentEmails, pollCliLogin, replayDelivery, replayEmailWebhooks, replyToEmail, rotateWebhookSecret, sendEmail, setFunctionSecret, startCliLogin, testEndpoint, testFunction, updateAccount, updateDomain, updateEndpoint, updateFilter, updateFunction, verifyDomain };
|
|
3575
|
+
export { Options, addDomain, cliLogout, createEndpoint, createFilter, createFunction, createFunctionSecret, deleteDomain, deleteEmail, deleteEndpoint, deleteFilter, deleteFunction, deleteFunctionSecret, discardEmailContent, downloadAttachments, downloadRawEmail, getAccount, getEmail, getFunction, getSendPermissions, getSentEmail, getStorageStats, getWebhookSecret, listDeliveries, listDomains, listEmails, listEndpoints, listFilters, listFunctionSecrets, listFunctions, listSentEmails, pollCliLogin, replayDelivery, replayEmailWebhooks, replyToEmail, rotateWebhookSecret, searchEmails, sendEmail, setFunctionSecret, startCliLogin, testEndpoint, testFunction, updateAccount, updateDomain, updateEndpoint, updateFilter, updateFunction, verifyDomain };
|
|
3413
3576
|
}
|
|
3414
3577
|
type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean, TResponse = unknown> = Options$1<TData, ThrowOnError, TResponse> & {
|
|
3415
3578
|
/**
|
|
@@ -3557,6 +3720,23 @@ declare const verifyDomain: <ThrowOnError extends boolean = false>(options: Opti
|
|
|
3557
3720
|
*
|
|
3558
3721
|
*/
|
|
3559
3722
|
declare const listEmails: <ThrowOnError extends boolean = false>(options?: Options<ListEmailsData, ThrowOnError>) => RequestResult<ListEmailsResponses, ListEmailsErrors, ThrowOnError, "fields">;
|
|
3723
|
+
/**
|
|
3724
|
+
* Search inbound emails
|
|
3725
|
+
*
|
|
3726
|
+
* Searches inbound emails with structured filters and optional
|
|
3727
|
+
* full-text matching across parsed email fields. This endpoint is
|
|
3728
|
+
* optimized for filtered inbox views and CLI polling workflows:
|
|
3729
|
+
* callers that only need new accepted mail can pass
|
|
3730
|
+
* `sort=received_at_asc`, `snippet=false`, `include_facets=false`,
|
|
3731
|
+
* and a `date_from` timestamp.
|
|
3732
|
+
*
|
|
3733
|
+
* `q`, `subject`, and `body` use the same English full-text index
|
|
3734
|
+
* as the web inbox search. Structured filters such as `from`, `to`,
|
|
3735
|
+
* `domain_id`, status, attachment presence, and spam score bounds
|
|
3736
|
+
* are combined with the text query.
|
|
3737
|
+
*
|
|
3738
|
+
*/
|
|
3739
|
+
declare const searchEmails: <ThrowOnError extends boolean = false>(options?: Options<SearchEmailsData, ThrowOnError>) => RequestResult<SearchEmailsResponses, SearchEmailsErrors, ThrowOnError, "fields">;
|
|
3560
3740
|
/**
|
|
3561
3741
|
* Delete an email
|
|
3562
3742
|
*/
|
|
@@ -3796,6 +3976,15 @@ declare const getSendPermissions: <ThrowOnError extends boolean = false>(options
|
|
|
3796
3976
|
* the request returns once the relay accepts the message for delivery.
|
|
3797
3977
|
* Set `wait: true` to wait for the first downstream SMTP delivery outcome.
|
|
3798
3978
|
*
|
|
3979
|
+
* **Host routing.** /send-mail is served by the attachments-
|
|
3980
|
+
* supporting host (`https://api.primitive.dev/v1`) so the
|
|
3981
|
+
* request body can carry inline attachments up to ~30 MiB raw.
|
|
3982
|
+
* The primary host (`https://www.primitive.dev/api/v1`) also
|
|
3983
|
+
* accepts /send-mail for attachment-free sends; sends WITH
|
|
3984
|
+
* attachments to the primary host return 413
|
|
3985
|
+
* `attachments_unsupported_on_this_endpoint`. The typed SDKs
|
|
3986
|
+
* route /send-mail to the attachments host automatically.
|
|
3987
|
+
*
|
|
3799
3988
|
*/
|
|
3800
3989
|
declare const sendEmail: <ThrowOnError extends boolean = false>(options: Options<SendEmailData, ThrowOnError>) => RequestResult<SendEmailResponses, SendEmailErrors, ThrowOnError, "fields">;
|
|
3801
3990
|
/**
|
|
@@ -3984,11 +4173,15 @@ declare const deleteFunctionSecret: <ThrowOnError extends boolean = false>(optio
|
|
|
3984
4173
|
declare const setFunctionSecret: <ThrowOnError extends boolean = false>(options: Options<SetFunctionSecretData, ThrowOnError>) => RequestResult<SetFunctionSecretResponses, SetFunctionSecretErrors, ThrowOnError, "fields">;
|
|
3985
4174
|
//#endregion
|
|
3986
4175
|
//#region src/api/index.d.ts
|
|
3987
|
-
declare const
|
|
4176
|
+
declare const DEFAULT_API_BASE_URL_1 = "https://www.primitive.dev/api/v1";
|
|
4177
|
+
declare const DEFAULT_API_BASE_URL_2 = "https://api.primitive.dev/v1";
|
|
3988
4178
|
interface PrimitiveApiClientOptions extends Omit<Config, "auth" | "baseUrl"> {
|
|
3989
4179
|
apiKey?: string;
|
|
3990
4180
|
auth?: Config["auth"];
|
|
3991
|
-
|
|
4181
|
+
/** @internal Override for the primary API host. Production default is correct; this exists for staging/local testing only. */
|
|
4182
|
+
apiBaseUrl1?: string;
|
|
4183
|
+
/** @internal Override for the attachments-supporting send host. Production default is correct; this exists for staging/local testing only. */
|
|
4184
|
+
apiBaseUrl2?: string;
|
|
3992
4185
|
}
|
|
3993
4186
|
interface SendThreadInput {
|
|
3994
4187
|
inReplyTo?: string;
|
|
@@ -4088,7 +4281,23 @@ declare class PrimitiveApiError extends Error {
|
|
|
4088
4281
|
});
|
|
4089
4282
|
}
|
|
4090
4283
|
declare class PrimitiveApiClient {
|
|
4284
|
+
/**
|
|
4285
|
+
* Generated client targeting the primary API host (apiBaseUrl1). Use
|
|
4286
|
+
* this when passing `client: ...` to a generated operation function
|
|
4287
|
+
* for every endpoint EXCEPT /send-mail. The hand-written
|
|
4288
|
+
* PrimitiveClient.send / .reply / .forward methods on the subclass
|
|
4289
|
+
* route /send-mail to the host-2 client internally.
|
|
4290
|
+
*/
|
|
4091
4291
|
readonly client: Client;
|
|
4292
|
+
/**
|
|
4293
|
+
* @internal Generated client targeting the attachments-supporting
|
|
4294
|
+
* send host (apiBaseUrl2). Used by PrimitiveClient.send() under the
|
|
4295
|
+
* hood. Exposed for the CLI's hand-rolled send command, which calls
|
|
4296
|
+
* the generated sendEmail directly; not part of the publicly-
|
|
4297
|
+
* documented SDK surface. Customer code should call .send() on the
|
|
4298
|
+
* subclass instead.
|
|
4299
|
+
*/
|
|
4300
|
+
readonly _sendClient: Client;
|
|
4092
4301
|
constructor(options?: PrimitiveApiClientOptions);
|
|
4093
4302
|
getConfig(): Config<ClientOptions$1>;
|
|
4094
4303
|
setConfig(config: Config): Config<ClientOptions$1>;
|
|
@@ -4118,4 +4327,4 @@ declare function createPrimitiveClient(options?: PrimitiveClientOptions): Primit
|
|
|
4118
4327
|
declare function client(options?: PrimitiveClientOptions): PrimitiveClient;
|
|
4119
4328
|
declare const operations: typeof sdk_gen_d_exports;
|
|
4120
4329
|
//#endregion
|
|
4121
|
-
export {
|
|
4330
|
+
export { replyToEmail as $, TestEndpointError as $a, ReplayDeliveryResponses as $i, EmailDetail as $n, RequestOptions$1 as $o, GetWebhookSecretResponses as $r, CreateFunctionSecretInput as $t, deleteFunction as A, SendPermissionAnyRecipient as Aa, ListFunctionSecretsResponse as Ai, DeleteFunctionSecretErrors as An, UpdateFilterError as Ao, GetFunctionError as Ar, ClientOptions as At, getStorageStats as B, SetFunctionSecretErrors as Ba, ListSentEmailsResponse as Bi, DiscardEmailContentResponses as Bn, UpdateFunctionResponses as Bo, GetSentEmailError as Br, CreateFilterInput as Bt, createFilter as C, SendEmailError as Ca, ListFiltersError as Ci, DeleteFunctionData as Cn, UpdateEndpointData as Co, GetAccountResponses as Cr, CliLogoutData as Ct, deleteEmail as D, SendMailInput as Da, ListFunctionSecretsData as Di, DeleteFunctionResponses as Dn, UpdateEndpointResponse as Do, GetEmailResponse as Dr, CliLogoutResponse as Dt, deleteDomain as E, SendEmailResponses as Ea, ListFiltersResponses as Ei, DeleteFunctionResponse as En, UpdateEndpointInput as Eo, GetEmailErrors as Er, CliLogoutInput as Et, getAccount as F, SentEmailDetail as Fa, ListFunctionsResponse as Fi, DiscardContentResult as Fn, UpdateFunctionData as Fo, GetSendPermissionsError as Fr, CreateEndpointResponse as Ft, listEndpoints as G, StartCliLoginError as Ga, PollCliLoginErrors as Gi, DownloadAttachmentsErrors as Gn, VerifyDomainResponse as Go, GetStorageStatsError as Gr, CreateFunctionErrors as Gt, listDeliveries as H, SetFunctionSecretResponse as Ha, PaginationMeta as Hi, DomainVerifyResult as Hn, VerifyDomainData as Ho, GetSentEmailResponse as Hr, CreateFilterResponses as Ht, getEmail as I, SentEmailStatus as Ia, ListFunctionsResponses as Ii, DiscardEmailContentData as In, UpdateFunctionError as Io, GetSendPermissionsErrors as Ir, CreateEndpointResponses as It, listFunctions as J, StartCliLoginResponse as Ja, PollCliLoginResponses as Ji, DownloadRawEmailData as Jn, Client as Jo, GetStorageStatsResponses as Jr, CreateFunctionResponses as Jt, listFilters as K, StartCliLoginErrors as Ka, PollCliLoginInput as Ki, DownloadAttachmentsResponse as Kn, VerifyDomainResponses as Ko, GetStorageStatsErrors as Kr, CreateFunctionInput as Kt, getFunction as L, SentEmailSummary as La, ListSentEmailsData as Li, DiscardEmailContentError as Ln, UpdateFunctionErrors as Lo, GetSendPermissionsResponse as Lr, CreateFilterData as Lt, discardEmailContent as M, SendPermissionRule as Ma, ListFunctionsData as Mi, DeleteFunctionSecretResponses as Mn, UpdateFilterInput as Mo, GetFunctionResponse as Mr, CreateEndpointError as Mt, downloadAttachments as N, SendPermissionYourDomain as Na, ListFunctionsError as Ni, DeliveryStatus as Nn, UpdateFilterResponse as No, GetFunctionResponses as Nr, CreateEndpointErrors as Nt, deleteEndpoint as O, SendMailResult as Oa, ListFunctionSecretsError as Oi, DeleteFunctionSecretData as On, UpdateEndpointResponses as Oo, GetEmailResponses as Or, CliLogoutResponses as Ot, downloadRawEmail as P, SendPermissionsMeta as Pa, ListFunctionsErrors as Pi, DeliverySummary as Pn, UpdateFilterResponses as Po, GetSendPermissionsData as Pr, CreateEndpointInput as Pt, replayEmailWebhooks as Q, TestEndpointData as Qa, ReplayDeliveryResponse as Qi, DownloadRawEmailResponses as Qn, Options$1 as Qo, GetWebhookSecretResponse as Qr, CreateFunctionSecretErrors as Qt, getSendPermissions as R, SetFunctionSecretData as Ra, ListSentEmailsError as Ri, DiscardEmailContentErrors as Rn, UpdateFunctionInput as Ro, GetSendPermissionsResponses as Rr, CreateFilterError as Rt, createEndpoint as S, SendEmailData as Sa, ListFiltersData as Si, DeleteFilterResponses as Sn, UpdateDomainResponses as So, GetAccountResponse as Sr, CliLoginStartResult as St, createFunctionSecret as T, SendEmailResponse as Ta, ListFiltersResponse as Ti, DeleteFunctionErrors as Tn, UpdateEndpointErrors as To, GetEmailError as Tr, CliLogoutErrors as Tt, listDomains as U, SetFunctionSecretResponses as Ua, PollCliLoginData as Ui, DownloadAttachmentsData as Un, VerifyDomainError as Uo, GetSentEmailResponses as Ur, CreateFunctionData as Ut, getWebhookSecret as V, SetFunctionSecretInput as Va, ListSentEmailsResponses as Vi, Domain as Vn, VerifiedDomain as Vo, GetSentEmailErrors as Vr, CreateFilterResponse as Vt, listEmails as W, StartCliLoginData as Wa, PollCliLoginError as Wi, DownloadAttachmentsError as Wn, VerifyDomainErrors as Wo, GetStorageStatsData as Wr, CreateFunctionError as Wt, pollCliLogin as X, StorageStats as Xa, ReplayDeliveryError as Xi, DownloadRawEmailErrors as Xn, Config as Xo, GetWebhookSecretError as Xr, CreateFunctionSecretData as Xt, listSentEmails as Y, StartCliLoginResponses as Ya, ReplayDeliveryData as Yi, DownloadRawEmailError as Yn, ClientOptions$1 as Yo, GetWebhookSecretData as Yr, CreateFunctionResult as Yt, replayDelivery as Z, SuccessEnvelope as Za, ReplayDeliveryErrors as Zi, DownloadRawEmailResponse as Zn, CreateClientConfig as Zo, GetWebhookSecretErrors as Zr, CreateFunctionSecretError as Zt, createPrimitiveClient as _, SearchEmailsData as _a, ListEndpointsError as _i, DeleteEndpointResponses as _n, UpdateDomainData as _o, GateDenial as _r, AddDomainErrors as _t, PrimitiveApiClientOptions as a, ReplayResult as aa, ListDeliveriesResponses as ai, DeleteDomainErrors as an, TestFunctionErrors as ao, EmailSearchResult as ar, testEndpoint as at, addDomain as b, SearchEmailsResponse as ba, ListEndpointsResponses as bi, DeleteFilterErrors as bn, UpdateDomainInput as bo, GetAccountError as br, AddDomainResponses as bt, PrimitiveClient as c, ReplyToEmailErrors as ca, ListDomainsErrors as ci, DeleteEmailData as cn, TestInvocationResult as co, EmailWebhookStatus as cr, updateDomain as ct, RequestOptions as d, ResourceId as da, ListEmailsData as di, DeleteEmailResponse as dn, UpdateAccountData as do, Filter as dr, updateFunction as dt, ReplayEmailWebhooksData as ea, Limit as ei, CreateFunctionSecretResponse as en, TestEndpointErrors as eo, EmailDetailReply as er, RequestResult as es, rotateWebhookSecret as et, SendInput as f, RotateWebhookSecretData as fa, ListEmailsError as fi, DeleteEmailResponses as fn, UpdateAccountError as fo, FunctionDeployStatus as fr, verifyDomain as ft, createPrimitiveApiClient as g, RotateWebhookSecretResponses as ga, ListEndpointsData as gi, DeleteEndpointResponse as gn, UpdateAccountResponses as go, FunctionSecretWriteResult as gr, AddDomainError as gt, client as h, RotateWebhookSecretResponse as ha, ListEmailsResponses as hi, DeleteEndpointErrors as hn, UpdateAccountResponse as ho, FunctionSecretListItem as hr, AddDomainData as ht, PrimitiveApiClient as i, ReplayEmailWebhooksResponses as ia, ListDeliveriesResponse as ii, DeleteDomainError as in, TestFunctionError as io, EmailSearchMeta as ir, startCliLogin as it, deleteFunctionSecret as j, SendPermissionManagedZone as ja, ListFunctionSecretsResponses as ji, DeleteFunctionSecretResponse as jn, UpdateFilterErrors as jo, GetFunctionErrors as jr, CreateEndpointData as jt, deleteFilter as k, SendPermissionAddress as ka, ListFunctionSecretsErrors as ki, DeleteFunctionSecretError as kn, UpdateFilterData as ko, GetFunctionData as kr, CliLogoutResult as kt, PrimitiveClientOptions as l, ReplyToEmailResponse as la, ListDomainsResponse as li, DeleteEmailError as ln, TestResult as lo, Endpoint as lr, updateEndpoint as lt, SendThreadInput as m, RotateWebhookSecretErrors as ma, ListEmailsResponse as mi, DeleteEndpointError as mn, UpdateAccountInput as mo, FunctionListItem as mr, AccountUpdated as mt, DEFAULT_API_BASE_URL_2 as n, ReplayEmailWebhooksErrors as na, ListDeliveriesError as ni, Cursor as nn, TestEndpointResponses as no, EmailSearchFacets as nr, Auth as ns, sendEmail as nt, PrimitiveApiError as o, ReplyToEmailData as oa, ListDomainsData as oi, DeleteDomainResponse as on, TestFunctionResponse as oo, EmailStatus as or, testFunction as ot, SendResult as p, RotateWebhookSecretError as pa, ListEmailsErrors as pi, DeleteEndpointData as pn, UpdateAccountErrors as po, FunctionDetail as pr, Account as pt, listFunctionSecrets as q, StartCliLoginInput as qa, PollCliLoginResponse as qi, DownloadAttachmentsResponses as qn, WebhookSecret as qo, GetStorageStatsResponse as qr, CreateFunctionResponse as qt, ForwardInput as r, ReplayEmailWebhooksResponse as ra, ListDeliveriesErrors as ri, DeleteDomainData as rn, TestFunctionData as ro, EmailSearchHighlights as rr, setFunctionSecret as rt, PrimitiveApiErrorDetails as s, ReplyToEmailError as sa, ListDomainsError as si, DeleteDomainResponses as sn, TestFunctionResponses as so, EmailSummary as sr, updateAccount as st, DEFAULT_API_BASE_URL_1 as t, ReplayEmailWebhooksError as ta, ListDeliveriesData as ti, CreateFunctionSecretResponses as tn, TestEndpointResponse as to, EmailSearchFacetBucket as tr, ResponseStyle as ts, searchEmails as tt, ReplyInput as u, ReplyToEmailResponses as ua, ListDomainsResponses as ui, DeleteEmailErrors as un, UnverifiedDomain as uo, ErrorResponse as ur, updateFilter as ut, operations as v, SearchEmailsError as va, ListEndpointsErrors as vi, DeleteFilterData as vn, UpdateDomainError as vo, GateFix as vr, AddDomainInput as vt, createFunction as w, SendEmailErrors as wa, ListFiltersErrors as wi, DeleteFunctionError as wn, UpdateEndpointError as wo, GetEmailData as wr, CliLogoutError as wt, cliLogout as x, SearchEmailsResponses as xa, ListEnvelope as xi, DeleteFilterResponse as xn, UpdateDomainResponse as xo, GetAccountErrors as xr, CliLoginPollResult as xt, Options as y, SearchEmailsErrors as ya, ListEndpointsResponse as yi, DeleteFilterError as yn, UpdateDomainErrors as yo, GetAccountData as yr, AddDomainResponse as yt, getSentEmail as z, SetFunctionSecretError as za, ListSentEmailsErrors as zi, DiscardEmailContentResponse as zn, UpdateFunctionResponse as zo, GetSentEmailData as zr, CreateFilterErrors as zt };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { A as UnknownEvent, C as ParsedDataFailed, D as RawContentDownloadOnly, E as RawContent, M as WebhookAttachment, N as WebhookEvent, O as RawContentInline, S as ParsedDataComplete, T as ParsedStatus, _ as ForwardResultInline, a as DmarcPolicy, b as KnownWebhookEvent, c as EmailAnalysis, d as EventType, f as ForwardAnalysis, g as ForwardResultAttachmentSkipped, h as ForwardResultAttachmentAnalyzed, i as DkimSignature, j as ValidateEmailAuthResult, k as SpfResult, l as EmailAuth, m as ForwardResult, n as AuthVerdict, o as DmarcResult, p as ForwardOriginalSender, r as DkimResult, s as EmailAddress, t as AuthConfidence, u as EmailReceivedEvent, v as ForwardVerdict, w as ParsedError, x as ParsedData, y as ForwardVerification } from "./types-9vXGZjPd.js";
|
|
2
2
|
import { a as buildReplySubject, c as parseHeaderAddress, i as buildForwardSubject, n as ReceivedEmailAddress, o as formatAddress, r as ReceivedEmailThread, s as normalizeReceivedEmail, t as ReceivedEmail } from "./received-email-DNjpq_Wt.js";
|
|
3
|
-
import {
|
|
3
|
+
import { _ as createPrimitiveClient, c as PrimitiveClient, f as SendInput, h as client, l as PrimitiveClientOptions, m as SendThreadInput, o as PrimitiveApiError, p as SendResult, r as ForwardInput, u as ReplyInput } from "./index-QTYQpSFt.js";
|
|
4
4
|
import { A as VerifyOptions, B as PAYLOAD_ERRORS, C as signStandardWebhooksPayload, D as PRIMITIVE_CONFIRMED_HEADER, E as LEGACY_SIGNATURE_HEADER, F as VerifyDownloadTokenResult, G as VERIFICATION_ERRORS, H as RAW_EMAIL_ERRORS, I as generateDownloadToken, J as WebhookPayloadErrorCode, K as WebhookErrorCode, L as verifyDownloadToken, M as verifyWebhookSignature, N as GenerateDownloadTokenOptions, O as PRIMITIVE_SIGNATURE_HEADER, P as VerifyDownloadTokenOptions, Q as WebhookVerificationErrorCode, R as safeValidateEmailReceivedEvent, S as StandardWebhooksVerifyOptions, T as LEGACY_CONFIRMED_HEADER, U as RawEmailDecodeError, V as PrimitiveWebhookError, W as RawEmailDecodeErrorCode, X as WebhookValidationErrorCode, Y as WebhookValidationError, Z as WebhookVerificationError, _ as emailReceivedEventJsonSchema, a as confirmedHeaders, b as STANDARD_WEBHOOK_TIMESTAMP_HEADER, c as handleWebhook, d as isRawIncluded, f as parseWebhookEvent, g as validateEmailAuth, h as WEBHOOK_VERSION, i as WebhookHeaders, j as signWebhookPayload, k as SignResult, l as isDownloadExpired, m as verifyRawEmailDownload, n as HandleWebhookOptions, o as decodeRawEmail, p as receive, q as WebhookPayloadError, r as ReceiveRequestOptions, s as getDownloadTimeRemaining, t as DecodeRawEmailOptions, u as isEmailReceivedEvent, v as STANDARD_WEBHOOK_ID_HEADER, w as verifyStandardWebhooksSignature, x as StandardWebhooksSignResult, y as STANDARD_WEBHOOK_SIGNATURE_HEADER, z as validateEmailReceivedEvent } from "./index-CDlwyxdp.js";
|
|
5
5
|
|
|
6
6
|
//#region src/index.d.ts
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as parseHeaderAddress, i as normalizeReceivedEmail, n as buildReplySubject, r as formatAddress, t as buildForwardSubject } from "./received-email-D6tKtWwW.js";
|
|
2
|
-
import { a as
|
|
2
|
+
import { a as PrimitiveClient, c as createPrimitiveClient, i as PrimitiveApiError, o as client } from "./api-BjzvA2Fy.js";
|
|
3
3
|
import { A as PRIMITIVE_CONFIRMED_HEADER, B as RAW_EMAIL_ERRORS, C as STANDARD_WEBHOOK_ID_HEADER, D as verifyStandardWebhooksSignature, E as signStandardWebhooksPayload, F as verifyDownloadToken, G as WebhookVerificationError, H as VERIFICATION_ERRORS, I as safeValidateEmailReceivedEvent, L as validateEmailReceivedEvent, M as signWebhookPayload, N as verifyWebhookSignature, O as LEGACY_CONFIRMED_HEADER, P as generateDownloadToken, R as PAYLOAD_ERRORS, S as emailReceivedEventJsonSchema, T as STANDARD_WEBHOOK_TIMESTAMP_HEADER, U as WebhookPayloadError, V as RawEmailDecodeError, W as WebhookValidationError, _ as DmarcResult, a as isDownloadExpired, b as ParsedStatus, c as parseWebhookEvent, d as WEBHOOK_VERSION, f as validateEmailAuth, g as DmarcPolicy, h as DkimResult, i as handleWebhook, j as PRIMITIVE_SIGNATURE_HEADER, k as LEGACY_SIGNATURE_HEADER, l as receive, m as AuthVerdict, n as decodeRawEmail, o as isEmailReceivedEvent, p as AuthConfidence, r as getDownloadTimeRemaining, s as isRawIncluded, t as confirmedHeaders, u as verifyRawEmailDownload, v as EventType, w as STANDARD_WEBHOOK_SIGNATURE_HEADER, x as SpfResult, y as ForwardVerdict, z as PrimitiveWebhookError } from "./webhook-rUjGV6Zu.js";
|
|
4
4
|
//#region src/index.ts
|
|
5
5
|
const primitive = {
|
|
@@ -333,9 +333,12 @@ export function removeStaleSavedCredentialOnUnauthorized(params) {
|
|
|
333
333
|
}
|
|
334
334
|
const baseUrlDiffersFromSaved = params.baseUrlOverridden &&
|
|
335
335
|
params.auth.credentials !== null &&
|
|
336
|
-
params.auth.
|
|
336
|
+
params.auth.apiBaseUrl1 !== params.auth.credentials.api_base_url_1;
|
|
337
337
|
if (baseUrlDiffersFromSaved) {
|
|
338
|
-
|
|
338
|
+
// Override env vars (PRIMITIVE_API_BASE_URL_1 / _2) are intentionally
|
|
339
|
+
// not advertised in --help; this hint is the only customer-visible
|
|
340
|
+
// mention. They're for internal staging/local testing.
|
|
341
|
+
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");
|
|
339
342
|
return false;
|
|
340
343
|
}
|
|
341
344
|
deleteCliCredentials(params.configDir);
|
|
@@ -381,10 +384,45 @@ export async function runWithTiming(enabled, fn) {
|
|
|
381
384
|
// own static flags. Lives here so the flag's description and short
|
|
382
385
|
// name stay consistent across the hand-coded and generated commands.
|
|
383
386
|
export 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.";
|
|
387
|
+
// Shared description text for the api-base-url override flags. Keeps
|
|
388
|
+
// the wording identical across every command that includes them. The
|
|
389
|
+
// flags themselves are hidden from --help (internal staging/local-only).
|
|
390
|
+
export const API_BASE_URL_1_FLAG_DESCRIPTION = "Override the primary API base URL. Internal testing only; not documented to customers.";
|
|
391
|
+
export const API_BASE_URL_2_FLAG_DESCRIPTION = "Override the attachments-supporting send host base URL. Internal testing only; not documented to customers.";
|
|
392
|
+
// Helper: was either api-base-url override set by the caller? Used by
|
|
393
|
+
// removeStaleSavedCredentialOnUnauthorized to decide whether to
|
|
394
|
+
// preserve the saved credential when a 401 comes back.
|
|
395
|
+
export function baseUrlOverriddenFromFlags(flags) {
|
|
396
|
+
return (typeof flags["api-base-url-1"] === "string" ||
|
|
397
|
+
typeof flags["api-base-url-2"] === "string");
|
|
398
|
+
}
|
|
399
|
+
// Helper: resolve auth from a parsed-flags bag. Mirrors what every CLI
|
|
400
|
+
// command does inline so the api-base-url-1 / api-base-url-2 mapping
|
|
401
|
+
// stays in one place as we add more migration knobs.
|
|
402
|
+
export function resolveCliAuthFromFlags(flags, configDir) {
|
|
403
|
+
return resolveCliAuth({
|
|
404
|
+
apiKey: typeof flags["api-key"] === "string"
|
|
405
|
+
? flags["api-key"]
|
|
406
|
+
: undefined,
|
|
407
|
+
apiBaseUrl1: typeof flags["api-base-url-1"] === "string"
|
|
408
|
+
? flags["api-base-url-1"]
|
|
409
|
+
: undefined,
|
|
410
|
+
apiBaseUrl2: typeof flags["api-base-url-2"] === "string"
|
|
411
|
+
? flags["api-base-url-2"]
|
|
412
|
+
: undefined,
|
|
413
|
+
configDir,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
// Operations that route to the attachments-supporting host
|
|
417
|
+
// (apiBaseUrl2) instead of the primary API host. Internal to the CLI:
|
|
418
|
+
// as more operations migrate to host 2 over time, add their generated
|
|
419
|
+
// sdkName here. Today it is just /send-mail.
|
|
420
|
+
const HOST_2_OPERATIONS = new Set(["sendEmail"]);
|
|
384
421
|
// Reserved flag names the body-field expander must never overwrite.
|
|
385
422
|
// `--raw-body` and `--body-file` are the JSON escape hatches.
|
|
386
|
-
// `--api-key`, `--base-url`, `--output` are
|
|
387
|
-
// params get added before body fields and take
|
|
423
|
+
// `--api-key`, `--api-base-url-1`, `--api-base-url-2`, `--output` are
|
|
424
|
+
// infra. Path and query params get added before body fields and take
|
|
425
|
+
// precedence.
|
|
388
426
|
//
|
|
389
427
|
// Note: `--body` is intentionally NOT reserved here. The naive
|
|
390
428
|
// agent expectation (per AGX walkthrough) is that --body means
|
|
@@ -399,7 +437,8 @@ export const TIME_FLAG_DESCRIPTION = "Print the wall-clock duration of this comm
|
|
|
399
437
|
// send` defines its own --body for the message text.
|
|
400
438
|
const RESERVED_FLAG_NAMES = new Set([
|
|
401
439
|
"api-key",
|
|
402
|
-
"base-url",
|
|
440
|
+
"api-base-url-1",
|
|
441
|
+
"api-base-url-2",
|
|
403
442
|
"raw-body",
|
|
404
443
|
"body-file",
|
|
405
444
|
"output",
|
|
@@ -438,9 +477,20 @@ function buildFlags(operation) {
|
|
|
438
477
|
description: "Primitive API key (defaults to PRIMITIVE_API_KEY or saved `primitive login` credentials)",
|
|
439
478
|
env: "PRIMITIVE_API_KEY",
|
|
440
479
|
}),
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
480
|
+
// Two override knobs for the dual-host setup. Hidden because they
|
|
481
|
+
// are for internal staging/local testing only. Production users
|
|
482
|
+
// should not override; the defaults route correctly. Env vars
|
|
483
|
+
// PRIMITIVE_API_BASE_URL_1 and PRIMITIVE_API_BASE_URL_2 carry the
|
|
484
|
+
// same semantics. Both are intentionally absent from --help output.
|
|
485
|
+
"api-base-url-1": Flags.string({
|
|
486
|
+
description: "Override the primary API base URL. Internal testing only; not documented to customers.",
|
|
487
|
+
env: "PRIMITIVE_API_BASE_URL_1",
|
|
488
|
+
hidden: true,
|
|
489
|
+
}),
|
|
490
|
+
"api-base-url-2": Flags.string({
|
|
491
|
+
description: "Override the attachments-supporting send host base URL. Internal testing only; not documented to customers.",
|
|
492
|
+
env: "PRIMITIVE_API_BASE_URL_2",
|
|
493
|
+
hidden: true,
|
|
444
494
|
}),
|
|
445
495
|
time: Flags.boolean({
|
|
446
496
|
description: TIME_FLAG_DESCRIPTION,
|
|
@@ -543,19 +593,24 @@ export function createOperationCommand(operation) {
|
|
|
543
593
|
const { flags } = await this.parse(OperationCommand);
|
|
544
594
|
const parsedFlags = flags;
|
|
545
595
|
await runWithTiming(parsedFlags.time === true, async () => {
|
|
546
|
-
const baseUrlOverridden = typeof parsedFlags["base-url"] === "string"
|
|
596
|
+
const baseUrlOverridden = typeof parsedFlags["api-base-url-1"] === "string" ||
|
|
597
|
+
typeof parsedFlags["api-base-url-2"] === "string";
|
|
547
598
|
const auth = resolveCliAuth({
|
|
548
599
|
apiKey: typeof parsedFlags["api-key"] === "string"
|
|
549
600
|
? parsedFlags["api-key"]
|
|
550
601
|
: undefined,
|
|
551
|
-
|
|
552
|
-
? parsedFlags["base-url"]
|
|
602
|
+
apiBaseUrl1: typeof parsedFlags["api-base-url-1"] === "string"
|
|
603
|
+
? parsedFlags["api-base-url-1"]
|
|
604
|
+
: undefined,
|
|
605
|
+
apiBaseUrl2: typeof parsedFlags["api-base-url-2"] === "string"
|
|
606
|
+
? parsedFlags["api-base-url-2"]
|
|
553
607
|
: undefined,
|
|
554
608
|
configDir: this.config.configDir,
|
|
555
609
|
});
|
|
556
610
|
const apiClient = new PrimitiveApiClient({
|
|
557
611
|
apiKey: auth.apiKey,
|
|
558
|
-
|
|
612
|
+
apiBaseUrl1: auth.apiBaseUrl1,
|
|
613
|
+
apiBaseUrl2: auth.apiBaseUrl2,
|
|
559
614
|
});
|
|
560
615
|
// Two body sources, merged: explicit JSON via --body /
|
|
561
616
|
// --body-file (the base) plus per-field flags (the
|
|
@@ -601,9 +656,15 @@ export function createOperationCommand(operation) {
|
|
|
601
656
|
throw new Errors.CLIError(`Operation ${operation.operationId} requires a body. Pass each field as a --flag (see --help) or supply JSON via --raw-body / --body-file.`);
|
|
602
657
|
}
|
|
603
658
|
const operationFn = operations[operation.sdkName];
|
|
659
|
+
// Operations in HOST_2_OPERATIONS route to the attachments-
|
|
660
|
+
// supporting send host (apiBaseUrl2). Today that's only
|
|
661
|
+
// sendEmail; the list grows as we migrate more endpoints.
|
|
662
|
+
const targetClient = HOST_2_OPERATIONS.has(operation.sdkName)
|
|
663
|
+
? apiClient._sendClient
|
|
664
|
+
: apiClient.client;
|
|
604
665
|
const result = await operationFn({
|
|
605
666
|
body,
|
|
606
|
-
client:
|
|
667
|
+
client: targetClient,
|
|
607
668
|
parseAs: operation.binaryResponse ? "blob" : "auto",
|
|
608
669
|
path: collectValues(operation.pathParams, parsedFlags),
|
|
609
670
|
query: collectValues(operation.queryParams, parsedFlags),
|
package/dist/oclif/auth.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { chmodSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { DEFAULT_API_BASE_URL_1, DEFAULT_API_BASE_URL_2, } from "../api/index.js";
|
|
5
5
|
const CREDENTIALS_FILE = "credentials.json";
|
|
6
6
|
const CREDENTIALS_LOCK_DIR = "credentials.lock";
|
|
7
7
|
const CREDENTIALS_LOCK_STALE_MS = 30 * 60 * 1000;
|
|
@@ -16,10 +16,34 @@ function requireString(value, key) {
|
|
|
16
16
|
}
|
|
17
17
|
return raw;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Sentinel returned by parseCredentials when the on-disk credentials
|
|
21
|
+
* were written by a pre-dual-host CLI version (i.e. they have
|
|
22
|
+
* `base_url` instead of `api_base_url_1`). The caller treats this as
|
|
23
|
+
* "no saved credentials" after auto-cleaning the stale file. Defined
|
|
24
|
+
* as a class-tagged error so loadCliCredentials can distinguish it
|
|
25
|
+
* from a genuine malformed-credentials error.
|
|
26
|
+
*/
|
|
27
|
+
class StaleCredentialFormatError extends Error {
|
|
28
|
+
constructor() {
|
|
29
|
+
super("stale_credential_format");
|
|
30
|
+
this.name = "StaleCredentialFormatError";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
19
33
|
function parseCredentials(raw) {
|
|
20
34
|
if (!isRecord(raw)) {
|
|
21
35
|
throw new Error(`Stored Primitive CLI credentials are malformed: expected a JSON object. ${MALFORMED_CREDENTIALS_HINT}`);
|
|
22
36
|
}
|
|
37
|
+
// Stored credentials from an older CLI version used the field name
|
|
38
|
+
// `base_url`; the dual-host rename moved this to `api_base_url_1`.
|
|
39
|
+
// Detect the old shape specifically so loadCliCredentials can wipe
|
|
40
|
+
// the stale file and emit a clear "you've been logged out" notice
|
|
41
|
+
// instead of every command hard-failing with a generic "malformed"
|
|
42
|
+
// error that doesn't surface the actual fix (re-login).
|
|
43
|
+
if (typeof raw.api_base_url_1 !== "string" &&
|
|
44
|
+
typeof raw.base_url === "string") {
|
|
45
|
+
throw new StaleCredentialFormatError();
|
|
46
|
+
}
|
|
23
47
|
const orgName = raw.org_name;
|
|
24
48
|
if (orgName !== null && typeof orgName !== "string") {
|
|
25
49
|
throw new Error(`Stored Primitive CLI credentials are malformed: org_name must be a string or null. ${MALFORMED_CREDENTIALS_HINT}`);
|
|
@@ -30,19 +54,25 @@ function parseCredentials(raw) {
|
|
|
30
54
|
key_prefix: requireString(raw, "key_prefix"),
|
|
31
55
|
org_id: requireString(raw, "org_id"),
|
|
32
56
|
org_name: orgName,
|
|
33
|
-
|
|
57
|
+
api_base_url_1: requireString(raw, "api_base_url_1"),
|
|
34
58
|
created_at: requireString(raw, "created_at"),
|
|
35
59
|
};
|
|
36
60
|
}
|
|
37
61
|
export function credentialsPath(configDir) {
|
|
38
62
|
return join(configDir, CREDENTIALS_FILE);
|
|
39
63
|
}
|
|
40
|
-
|
|
41
|
-
const trimmed =
|
|
64
|
+
function normalize(url, fallback) {
|
|
65
|
+
const trimmed = url?.trim();
|
|
42
66
|
if (!trimmed)
|
|
43
|
-
return
|
|
67
|
+
return fallback;
|
|
44
68
|
return trimmed.replace(/\/+$/, "");
|
|
45
69
|
}
|
|
70
|
+
export function normalizeApiBaseUrl1(url) {
|
|
71
|
+
return normalize(url, DEFAULT_API_BASE_URL_1);
|
|
72
|
+
}
|
|
73
|
+
export function normalizeApiBaseUrl2(url) {
|
|
74
|
+
return normalize(url, DEFAULT_API_BASE_URL_2);
|
|
75
|
+
}
|
|
46
76
|
export function loadCliCredentials(configDir) {
|
|
47
77
|
const path = credentialsPath(configDir);
|
|
48
78
|
let contents;
|
|
@@ -62,6 +92,24 @@ export function loadCliCredentials(configDir) {
|
|
|
62
92
|
return parseCredentials(JSON.parse(contents));
|
|
63
93
|
}
|
|
64
94
|
catch (error) {
|
|
95
|
+
if (error instanceof StaleCredentialFormatError) {
|
|
96
|
+
// Saved credentials were written by a pre-dual-host CLI version.
|
|
97
|
+
// The format is incompatible (base_url vs api_base_url_1) and
|
|
98
|
+
// cannot be recovered. Clear the file so the caller sees "no
|
|
99
|
+
// saved credentials" and emit a one-shot notice telling the
|
|
100
|
+
// user they need to log back in. Idempotent: once the file is
|
|
101
|
+
// gone, this branch never fires again.
|
|
102
|
+
try {
|
|
103
|
+
rmSync(path, { force: true });
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// Best-effort cleanup; if the unlink fails (permissions,
|
|
107
|
+
// racing process), the next CLI invocation will hit this
|
|
108
|
+
// path again and try once more.
|
|
109
|
+
}
|
|
110
|
+
process.stderr.write("You've been logged out: your saved Primitive CLI credentials were created by an older CLI version and are no longer compatible. Run `primitive login` to re-authenticate.\n");
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
65
113
|
if (error instanceof SyntaxError) {
|
|
66
114
|
throw new Error("Stored Primitive CLI credentials are not valid JSON. Run `primitive logout` and then `primitive login`.");
|
|
67
115
|
}
|
|
@@ -140,10 +188,15 @@ export function acquireCliCredentialsLock(configDir, options = {}) {
|
|
|
140
188
|
}
|
|
141
189
|
export function resolveCliAuth(params) {
|
|
142
190
|
const apiKey = params.apiKey?.trim();
|
|
191
|
+
// Host 2 (api_base_url_2) is never stored; either set by env/flag or
|
|
192
|
+
// falls back to the production default. The login flow only deals
|
|
193
|
+
// with host 1.
|
|
194
|
+
const apiBaseUrl2 = normalizeApiBaseUrl2(params.apiBaseUrl2);
|
|
143
195
|
if (apiKey) {
|
|
144
196
|
return {
|
|
145
197
|
apiKey,
|
|
146
|
-
|
|
198
|
+
apiBaseUrl1: normalizeApiBaseUrl1(params.apiBaseUrl1),
|
|
199
|
+
apiBaseUrl2,
|
|
147
200
|
credentials: null,
|
|
148
201
|
source: "flag-or-env",
|
|
149
202
|
};
|
|
@@ -152,16 +205,18 @@ export function resolveCliAuth(params) {
|
|
|
152
205
|
if (credentials) {
|
|
153
206
|
return {
|
|
154
207
|
apiKey: credentials.api_key,
|
|
155
|
-
|
|
156
|
-
?
|
|
157
|
-
: credentials.
|
|
208
|
+
apiBaseUrl1: params.apiBaseUrl1
|
|
209
|
+
? normalizeApiBaseUrl1(params.apiBaseUrl1)
|
|
210
|
+
: credentials.api_base_url_1,
|
|
211
|
+
apiBaseUrl2,
|
|
158
212
|
credentials,
|
|
159
213
|
source: "stored",
|
|
160
214
|
};
|
|
161
215
|
}
|
|
162
216
|
return {
|
|
163
217
|
apiKey: undefined,
|
|
164
|
-
|
|
218
|
+
apiBaseUrl1: normalizeApiBaseUrl1(params.apiBaseUrl1),
|
|
219
|
+
apiBaseUrl2,
|
|
165
220
|
credentials: null,
|
|
166
221
|
source: "none",
|
|
167
222
|
};
|