@tailor-platform/sdk 2.36.0 → 2.38.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/CHANGELOG.md +132 -0
- package/dist/{application-DaJbleMi.mjs → application-Bz80INH4.mjs} +1 -1
- package/dist/application-CeqD1OK-.mjs +207 -0
- package/dist/application-CeqD1OK-.mjs.map +1 -0
- package/dist/cli/commands/deploy/deploy.d.mts +7 -1
- package/dist/cli/commands/deploy/tailordb/migration-validation.d.mts +3 -0
- package/dist/cli/commands/executor/jobs.d.mts +3 -0
- package/dist/cli/commands/tailordb/migrate/bundler.d.mts +3 -0
- package/dist/cli/commands/tailordb/migrate/config.d.mts +4 -0
- package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +10 -0
- package/dist/cli/commands/tailordb/migrate/generate.d.mts +28 -2
- package/dist/cli/commands/tailordb/migrate/hints.d.mts +1 -0
- package/dist/cli/commands/tailordb/migrate/remote-state.d.mts +3 -0
- package/dist/cli/commands/tailordb/migrate/schema-checks.d.mts +3 -1
- package/dist/cli/commands/tailordb/migrate/snapshot-comparison.d.mts +4 -0
- package/dist/cli/commands/tailordb/migrate/snapshot-files.d.mts +44 -6
- package/dist/cli/commands/tailordb/migrate/snapshot-local.d.mts +2 -0
- package/dist/cli/commands/tailordb/migrate/snapshot-migrations.d.mts +2 -0
- package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +8 -0
- package/dist/cli/commands/tailordb/migrate/types.d.mts +2 -0
- package/dist/cli/commands/workspace/create.d.mts +1 -1
- package/dist/cli/lib.d.mts +3 -3
- package/dist/cli/lib.mjs +1 -1
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/main.mjs +65 -58
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/shared/args.d.mts +14 -5
- package/dist/cli/shared/client.d.mts +40 -3
- package/dist/cli/shared/error-json.d.mts +12 -26
- package/dist/cli/shared/function-execution.d.mts +2 -0
- package/dist/cli/shared/prompt.d.mts +9 -4
- package/dist/client-CHXix4LD.mjs +1 -0
- package/dist/client-DOQv-BP8.mjs +2 -0
- package/dist/client-DOQv-BP8.mjs.map +1 -0
- package/dist/completion/zsh-worker.zsh +151 -79
- package/dist/configure/config/index.d.mts +2 -0
- package/dist/configure/config/types.d.mts +2 -0
- package/dist/configure/index.mjs.map +1 -1
- package/dist/configure/services/executor/operation.d.mts +5 -4
- package/dist/configure/services/http-adapter/http-adapter.d.mts +1 -1
- package/dist/configure/services/index.d.mts +0 -1
- package/dist/configure/services/tailordb/schema.d.mts +1 -0
- package/dist/configure/services/tailordb/types.d.mts +12 -0
- package/dist/context-DSi5kfqr.mjs +23 -0
- package/dist/context-DSi5kfqr.mjs.map +1 -0
- package/dist/context-OOASEQLA.mjs +1 -0
- package/dist/{crashreport-DGU6lwiX.mjs → crashreport-CQTAlnbA.mjs} +4 -4
- package/dist/{crashreport-DGU6lwiX.mjs.map → crashreport-CQTAlnbA.mjs.map} +1 -1
- package/dist/crashreport-GRnWyDnF.mjs +1 -0
- package/dist/date-representation-Cr7W7Pn2.mjs.map +1 -1
- package/dist/{errors-BXmGBX-7.mjs → errors-9OOL3xOM.mjs} +6 -5
- package/dist/errors-9OOL3xOM.mjs.map +1 -0
- package/dist/field_behavior_pb-B196sUx6.mjs +2 -0
- package/dist/field_behavior_pb-B196sUx6.mjs.map +1 -0
- package/dist/{kysely-type-B0ri1-Xs.mjs → kysely-type-DhAZqdQg.mjs} +14 -10
- package/dist/kysely-type-DhAZqdQg.mjs.map +1 -0
- package/dist/notification_resource_pb-BZ0hCA01.mjs +1 -0
- package/dist/notification_resource_pb-Dwzah7gO.mjs +2 -0
- package/dist/notification_resource_pb-Dwzah7gO.mjs.map +1 -0
- package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
- package/dist/plugin/builtin/seed/seed-type-processor.d.mts +4 -3
- package/dist/plugin/get-generated-table.d.mts +4 -0
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/plugin/types.d.mts +55 -3
- package/dist/plugin/with-context.d.mts +16 -0
- package/dist/register-ts-hook-CXYYYgCl.mjs +1094 -0
- package/dist/register-ts-hook-CXYYYgCl.mjs.map +1 -0
- package/dist/repl-editor-Bposemei.mjs +2 -0
- package/dist/repl-editor-Bposemei.mjs.map +1 -0
- package/dist/resource_pb-elY668ZB.mjs +2 -0
- package/dist/resource_pb-elY668ZB.mjs.map +1 -0
- package/dist/schema-BU1aIQ63.mjs.map +1 -1
- package/dist/{secret-file-BxZ-J_Nz.mjs → secret-file-CSXzcg4c.mjs} +2 -2
- package/dist/{secret-file-BxZ-J_Nz.mjs.map → secret-file-CSXzcg4c.mjs.map} +1 -1
- package/dist/{service-CaGmqg0r.mjs → service-B2vx6CGM.mjs} +2 -2
- package/dist/{service-CaGmqg0r.mjs.map → service-B2vx6CGM.mjs.map} +1 -1
- package/dist/service-DB-RHn25.mjs +9 -0
- package/dist/service-DB-RHn25.mjs.map +1 -0
- package/dist/service-DsAWXbVX.mjs +1 -0
- package/dist/service_pb-Bethc2NW.mjs +1 -0
- package/dist/service_pb-CfpSriCy.mjs +2 -0
- package/dist/service_pb-CfpSriCy.mjs.map +1 -0
- package/dist/tailor-proto/src/tailor/v1/function_pb.d.mts +3 -3
- package/dist/tailor-proto/src/tailor/v1/function_resource_pb.d.mts +92 -0
- package/dist/tailor-proto/src/tailor/v1/notification_pb.d.mts +176 -0
- package/dist/tailor-proto/src/tailor/v1/notification_resource_pb.d.mts +172 -0
- package/dist/tailor-proto/src/tailor/v1/service_pb.d.mts +78 -0
- package/dist/types/app-config.generated.d.mts +1 -1
- package/dist/types/auth-connection.generated.d.mts +2 -2
- package/dist/types/auth.generated.d.mts +13 -13
- package/dist/types/executor.generated.d.mts +25 -25
- package/dist/types/field.generated.d.mts +2 -2
- package/dist/types/http-adapter.generated.d.mts +4 -4
- package/dist/types/idp.generated.d.mts +272 -272
- package/dist/types/resolver.generated.d.mts +10 -10
- package/dist/types/tailordb.generated.d.mts +84 -80
- package/dist/types/workflow.generated.d.mts +2 -2
- package/dist/validation-errors-DqCeUW4L.mjs +3 -0
- package/dist/validation-errors-DqCeUW4L.mjs.map +1 -0
- package/{LICENSE → dist/vendor/graphql/LICENSE} +6 -6
- package/dist/vendor/graphql/language/KindTypeMap.d.mts +3 -0
- package/dist/vendor/graphql/language/ast.d.mts +784 -0
- package/dist/vendor/graphql/language/kinds_.d.mts +203 -0
- package/dist/vendor/graphql/language/source.d.mts +46 -0
- package/dist/vendor/graphql/language/tokenKind.d.mts +35 -0
- package/dist/vitest/date-representation.d.mts +2 -0
- package/dist/vitest/environment.d.mts +1 -0
- package/dist/vitest/environment.mjs.map +1 -1
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/migration-steps.d.mts +13 -2
- package/dist/vitest/mock-kysely.d.mts +12 -2
- package/dist/vitest/mocks/aigateway.d.mts +7 -1
- package/dist/vitest/mocks/authconnection.d.mts +7 -1
- package/dist/vitest/mocks/file.d.mts +8 -2
- package/dist/vitest/mocks/iconv.d.mts +7 -1
- package/dist/vitest/mocks/idp.d.mts +7 -1
- package/dist/vitest/mocks/logger.d.mts +7 -1
- package/dist/vitest/mocks/secretmanager.d.mts +7 -1
- package/dist/vitest/mocks/tailordb-pglite.d.mts +12 -2
- package/dist/vitest/mocks/tailordb.d.mts +22 -4
- package/dist/vitest/mocks/workflow.d.mts +2 -1
- package/dist/vitest/pglite-kysely.d.mts +18 -2
- package/dist/vitest/pglite-temporal.d.mts +5 -1
- package/dist/vitest/workflow-local.d.mts +7 -0
- package/dist/workspace_resource_pb-Cow7mrJY.mjs +2 -0
- package/dist/workspace_resource_pb-Cow7mrJY.mjs.map +1 -0
- package/docs/cli/application.md +63 -29
- package/docs/cli/executor.md +2 -0
- package/docs/cli/function.md +3 -1
- package/docs/cli/notification.md +128 -0
- package/docs/cli/tailordb.md +45 -68
- package/docs/cli/workflow.md +2 -0
- package/docs/cli/workspace.md +20 -18
- package/docs/cli-reference.md +231 -50
- package/docs/configuration.md +2 -2
- package/docs/data-clone.md +1 -1
- package/docs/github-actions.md +266 -41
- package/docs/plugin/custom.md +4 -4
- package/docs/runtime.md +1 -1
- package/docs/services/auth.md +2 -0
- package/docs/services/idp.md +2 -0
- package/docs/services/tailordb/index.md +13 -4
- package/docs/services/tailordb/migration.md +109 -71
- package/docs/services/workflow.md +1 -1
- package/docs/testing.md +9 -10
- package/package.json +23 -19
- package/dist/application-BbORWCj-.mjs +0 -207
- package/dist/application-BbORWCj-.mjs.map +0 -1
- package/dist/configure/services/http-adapter/index.d.mts +0 -2
- package/dist/crashreport-WsYAWARW.mjs +0 -1
- package/dist/errors-BXmGBX-7.mjs.map +0 -1
- package/dist/kysely-type-B0ri1-Xs.mjs.map +0 -1
- package/dist/register-ts-hook-iAcG1dfz.mjs +0 -1057
- package/dist/register-ts-hook-iAcG1dfz.mjs.map +0 -1
- package/dist/repl-editor-DkrCZmmg.mjs +0 -2
- package/dist/repl-editor-DkrCZmmg.mjs.map +0 -1
- package/dist/service-DTrVVaDJ.mjs +0 -1
- package/dist/service-hIarp2Gl.mjs +0 -8
- package/dist/service-hIarp2Gl.mjs.map +0 -1
- package/dist/service_pb-6EkMfdOb.mjs +0 -2
- package/dist/service_pb-6EkMfdOb.mjs.map +0 -1
- package/dist/service_pb-CsJKokDl.mjs +0 -1
- package/dist/workspace_resource_pb-C4CkoYww.mjs +0 -2
- package/dist/workspace_resource_pb-C4CkoYww.mjs.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "../../tailor-proto/src/tailor/v1/resource_pb.mjs";
|
|
2
|
+
import "@politty/zod";
|
|
2
3
|
import { z } from "zod";
|
|
3
4
|
/**
|
|
4
5
|
* Schema for sort order (`asc` or `desc`).
|
|
@@ -20,7 +21,7 @@ type EnvFileArg = string | string[] | undefined;
|
|
|
20
21
|
* @param envFilesIfExists - Optional env file path(s) that are loaded if they exist
|
|
21
22
|
*/
|
|
22
23
|
export declare function loadEnvFiles(envFiles: EnvFileArg, envFilesIfExists: EnvFileArg): void;
|
|
23
|
-
interface CommonArgsOptions {
|
|
24
|
+
export interface CommonArgsOptions {
|
|
24
25
|
/** Extra short alias for `--verbose` (e.g. `"v"`), for plugins that need one */
|
|
25
26
|
verboseAlias?: string;
|
|
26
27
|
}
|
|
@@ -37,8 +38,8 @@ interface CommonArgsOptions {
|
|
|
37
38
|
* @returns Argument shape suitable for spreading into a command schema
|
|
38
39
|
*/
|
|
39
40
|
export declare function createCommonArgs(options?: CommonArgsOptions): {
|
|
40
|
-
"env-file": z.ZodOptional<z.ZodString
|
|
41
|
-
"env-file-if-exists": z.ZodOptional<z.ZodString
|
|
41
|
+
"env-file": z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
42
|
+
"env-file-if-exists": z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
42
43
|
verbose: z.ZodDefault<z.ZodBoolean>;
|
|
43
44
|
json: z.ZodDefault<z.ZodBoolean>;
|
|
44
45
|
};
|
|
@@ -46,11 +47,19 @@ export declare function createCommonArgs(options?: CommonArgsOptions): {
|
|
|
46
47
|
* Common arguments for all CLI commands
|
|
47
48
|
*/
|
|
48
49
|
export declare const commonArgs: {
|
|
49
|
-
"env-file": z.ZodOptional<z.ZodString
|
|
50
|
-
"env-file-if-exists": z.ZodOptional<z.ZodString
|
|
50
|
+
"env-file": z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
51
|
+
"env-file-if-exists": z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
51
52
|
verbose: z.ZodDefault<z.ZodBoolean>;
|
|
52
53
|
json: z.ZodDefault<z.ZodBoolean>;
|
|
53
54
|
};
|
|
55
|
+
/**
|
|
56
|
+
* Load the env files given on the command line, so that options backed by an
|
|
57
|
+
* environment variable read the values these files set. Call it before the
|
|
58
|
+
* CLI parses its arguments, such as from the `setup` hook of `runMain`.
|
|
59
|
+
* @param argv - Command-line arguments after the executable and script path
|
|
60
|
+
* @param options - Options passed to {@link createCommonArgs} for the global arguments
|
|
61
|
+
*/
|
|
62
|
+
export declare function loadEnvFilesFromArgv(argv: readonly string[], options?: CommonArgsOptions): void;
|
|
54
63
|
/**
|
|
55
64
|
* Arguments for commands that require workspace context
|
|
56
65
|
*/
|
|
@@ -17,6 +17,7 @@ import { AcceptCustomDomainTransferRequestSchema, AcceptCustomDomainTransferResp
|
|
|
17
17
|
import { CancelWorkflowExecutionRequestSchema, CancelWorkflowExecutionResponseSchema, CreateWorkflowJobFunctionExecutionPolicyRequestSchema, CreateWorkflowJobFunctionExecutionPolicyResponseSchema, CreateWorkflowJobFunctionRequestSchema, CreateWorkflowJobFunctionResponseSchema, CreateWorkflowRequestSchema, CreateWorkflowResponseSchema, DeleteWorkflowJobFunctionExecutionPolicyRequestSchema, DeleteWorkflowJobFunctionExecutionPolicyResponseSchema, DeleteWorkflowJobFunctionRequestSchema, DeleteWorkflowJobFunctionResponseSchema, DeleteWorkflowRequestSchema, DeleteWorkflowResponseSchema, GetWorkflowByNameRequestSchema, GetWorkflowByNameResponseSchema, GetWorkflowExecutionRequestSchema, GetWorkflowExecutionResponseSchema, GetWorkflowJobFunctionByNameRequestSchema, GetWorkflowJobFunctionByNameResponseSchema, GetWorkflowJobFunctionExecutionPolicyByKeyRequestSchema, GetWorkflowJobFunctionExecutionPolicyByKeyResponseSchema, GetWorkflowJobFunctionExecutionPolicyRequestSchema, GetWorkflowJobFunctionExecutionPolicyResponseSchema, GetWorkflowJobFunctionRequestSchema, GetWorkflowJobFunctionResponseSchema, GetWorkflowRequestSchema, GetWorkflowResponseSchema, ListWorkflowExecutionsRequestSchema, ListWorkflowExecutionsResponseSchema, ListWorkflowJobFunctionExecutionPoliciesRequestSchema, ListWorkflowJobFunctionExecutionPoliciesResponseSchema, ListWorkflowJobFunctionsRequestSchema, ListWorkflowJobFunctionsResponseSchema, ListWorkflowsRequestSchema, ListWorkflowsResponseSchema, ResumeWorkflowExecutionRequestSchema, ResumeWorkflowExecutionResponseSchema, StartWorkflowRequestSchema, StartWorkflowResponseSchema, TestResumeWorkflowRequestSchema, TestResumeWorkflowResponseSchema, TestStartWorkflowRequestSchema, TestStartWorkflowResponseSchema, UpdateWorkflowJobFunctionExecutionPolicyRequestSchema, UpdateWorkflowJobFunctionExecutionPolicyResponseSchema, UpdateWorkflowJobFunctionRequestSchema, UpdateWorkflowJobFunctionResponseSchema, UpdateWorkflowRequestSchema, UpdateWorkflowResponseSchema } from "../../tailor-proto/src/tailor/v1/workflow_pb.mjs";
|
|
18
18
|
import { BulkSetMetadataRequestSchema, BulkSetMetadataResponseSchema, GetMetadataRequestSchema, GetMetadataResponseSchema, ListMetadataRequestSchema, ListMetadataResponseSchema, SetMetadataRequestSchema, SetMetadataResponseSchema } from "../../tailor-proto/src/tailor/v1/metadata_pb.mjs";
|
|
19
19
|
import { CreateOTLPExporterRequestSchema, CreateOTLPExporterResponseSchema, CreateResourceAttributesConfigRequestSchema, CreateResourceAttributesConfigResponseSchema, DeleteOTLPExporterRequestSchema, DeleteOTLPExporterResponseSchema, DeleteResourceAttributesConfigRequestSchema, DeleteResourceAttributesConfigResponseSchema, GetOTLPExporterRequestSchema, GetOTLPExporterResponseSchema, GetResourceAttributesConfigRequestSchema, GetResourceAttributesConfigResponseSchema, ListOTLPExportersRequestSchema, ListOTLPExportersResponseSchema, TestOTLPExporterRequestSchema, TestOTLPExporterResponseSchema, UpdateOTLPExporterRequestSchema, UpdateOTLPExporterResponseSchema, UpdateResourceAttributesConfigRequestSchema, UpdateResourceAttributesConfigResponseSchema } from "../../tailor-proto/src/tailor/v1/telemetryrouter_pb.mjs";
|
|
20
|
+
import { CountMyUnreadNotificationsRequestSchema, CountMyUnreadNotificationsResponseSchema, DismissMyNotificationRequestSchema, DismissMyNotificationResponseSchema, GetMyNotificationRequestSchema, GetMyNotificationResponseSchema, ListMyNotificationsRequestSchema, ListMyNotificationsResponseSchema, MarkMyNotificationsReadRequestSchema, MarkMyNotificationsReadResponseSchema } from "../../tailor-proto/src/tailor/v1/notification_pb.mjs";
|
|
20
21
|
import { OperatorService, PingRequestSchema, PingResponseSchema } from "../../tailor-proto/src/tailor/v1/service_pb.mjs";
|
|
21
22
|
import "@badgateway/oauth2-client";
|
|
22
23
|
import { Client } from "@connectrpc/connect";
|
|
@@ -26,16 +27,26 @@ export type PlatformClientConfig = {
|
|
|
26
27
|
consoleUrl?: string;
|
|
27
28
|
};
|
|
28
29
|
export type OperatorClient = Client<typeof OperatorService>;
|
|
30
|
+
/** Options for {@link initOperatorClient}. */
|
|
31
|
+
interface OperatorClientOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Renew a browser-login token while the client runs (default true). Pass false for a
|
|
34
|
+
* best-effort call that may be abandoned mid-flight, which must never rotate the stored login.
|
|
35
|
+
*/
|
|
36
|
+
renewToken?: boolean;
|
|
37
|
+
}
|
|
29
38
|
/**
|
|
30
39
|
* Initialize an Operator client with the given access token.
|
|
31
40
|
* A client created with a token that `loadAccessToken` returned for a browser login
|
|
32
41
|
* (`tailor login`) renews the token while it runs, so it keeps working past the token's
|
|
33
|
-
* lifetime; this can refresh and save the stored login. Other tokens
|
|
42
|
+
* lifetime; this can refresh and save the stored login. Other tokens, and every token when
|
|
43
|
+
* `renewToken` is false, are sent as given.
|
|
34
44
|
* @param accessToken - Access token for authentication
|
|
35
45
|
* @param config - Optional platform connection settings
|
|
46
|
+
* @param options - Client options
|
|
36
47
|
* @returns Configured Operator client
|
|
37
48
|
*/
|
|
38
|
-
export declare function initOperatorClient(accessToken: string, config?: PlatformClientConfig): Promise<Client<import("@bufbuild/protobuf/codegenv2").GenService<{
|
|
49
|
+
export declare function initOperatorClient(accessToken: string, config?: PlatformClientConfig, options?: OperatorClientOptions): Promise<Client<import("@bufbuild/protobuf/codegenv2").GenService<{
|
|
39
50
|
ping: {
|
|
40
51
|
methodKind: "unary";
|
|
41
52
|
input: typeof PingRequestSchema;
|
|
@@ -1376,4 +1387,30 @@ export declare function initOperatorClient(accessToken: string, config?: Platfor
|
|
|
1376
1387
|
input: typeof DeleteResourceAttributesConfigRequestSchema;
|
|
1377
1388
|
output: typeof DeleteResourceAttributesConfigResponseSchema;
|
|
1378
1389
|
};
|
|
1379
|
-
|
|
1390
|
+
listMyNotifications: {
|
|
1391
|
+
methodKind: "unary";
|
|
1392
|
+
input: typeof ListMyNotificationsRequestSchema;
|
|
1393
|
+
output: typeof ListMyNotificationsResponseSchema;
|
|
1394
|
+
};
|
|
1395
|
+
getMyNotification: {
|
|
1396
|
+
methodKind: "unary";
|
|
1397
|
+
input: typeof GetMyNotificationRequestSchema;
|
|
1398
|
+
output: typeof GetMyNotificationResponseSchema;
|
|
1399
|
+
};
|
|
1400
|
+
countMyUnreadNotifications: {
|
|
1401
|
+
methodKind: "unary";
|
|
1402
|
+
input: typeof CountMyUnreadNotificationsRequestSchema;
|
|
1403
|
+
output: typeof CountMyUnreadNotificationsResponseSchema;
|
|
1404
|
+
};
|
|
1405
|
+
markMyNotificationsRead: {
|
|
1406
|
+
methodKind: "unary";
|
|
1407
|
+
input: typeof MarkMyNotificationsReadRequestSchema;
|
|
1408
|
+
output: typeof MarkMyNotificationsReadResponseSchema;
|
|
1409
|
+
};
|
|
1410
|
+
dismissMyNotification: {
|
|
1411
|
+
methodKind: "unary";
|
|
1412
|
+
input: typeof DismissMyNotificationRequestSchema;
|
|
1413
|
+
output: typeof DismissMyNotificationResponseSchema;
|
|
1414
|
+
};
|
|
1415
|
+
}>>>;
|
|
1416
|
+
export {};
|
|
@@ -3,40 +3,26 @@ export interface ErrorToJsonOptions {
|
|
|
3
3
|
/** Include the original stack trace in the error envelope. */
|
|
4
4
|
includeStack?: boolean;
|
|
5
5
|
}
|
|
6
|
+
type ErrorEnvelope = {
|
|
7
|
+
error: Readonly<Record<string, Jsonifiable | undefined>>;
|
|
8
|
+
};
|
|
6
9
|
/**
|
|
7
10
|
* Convert a CLI failure into the stable JSON error envelope.
|
|
11
|
+
*
|
|
12
|
+
* String values come without colors, and registered secrets are redacted from every value.
|
|
13
|
+
* The envelope holds only what JSON can represent: a `Date` becomes its ISO string, and when
|
|
14
|
+
* the context cannot be written as JSON, for example because it is circular, the envelope
|
|
15
|
+
* leaves out `context` and `stack`.
|
|
8
16
|
* @param error - Failure to serialize
|
|
9
17
|
* @param options - JSON serialization options
|
|
10
18
|
* @returns JSON-compatible error envelope
|
|
11
19
|
*/
|
|
12
|
-
export declare function errorToJson(error: unknown, options?: ErrorToJsonOptions):
|
|
13
|
-
error: Readonly<Record<string, Jsonifiable | undefined>>;
|
|
14
|
-
};
|
|
20
|
+
export declare function errorToJson(error: unknown, options?: ErrorToJsonOptions): ErrorEnvelope;
|
|
15
21
|
/**
|
|
16
|
-
* Serialize a CLI failure into the stable JSON error envelope.
|
|
17
|
-
*
|
|
18
|
-
* String values are written without colors.
|
|
19
|
-
*
|
|
20
|
-
* Redacts registered secrets from every string, number, boolean, and `null` *value* in the
|
|
21
|
-
* envelope, however deeply nested, before this function's own `JSON.stringify` call, rather
|
|
22
|
-
* than relying only on the redaction `logger.log()` does on the final string: an upstream
|
|
23
|
-
* error message (or `error.context`, an arbitrary record) can already embed a secret in
|
|
24
|
-
* JSON-escaped form (e.g. echoed back inside a JSON API error body), and stringifying the
|
|
25
|
-
* envelope would escape that a second time, no longer matching a registered secret's
|
|
26
|
-
* single-level-escaped form. Redacting non-string bare tokens here also matters because the
|
|
27
|
-
* later, structure-unaware `redactSecrets()` pass over the fully rendered JSON text cannot
|
|
28
|
-
* tell a bare token apart from a JSON string, so a secret whose value coincides with an
|
|
29
|
-
* unrelated number/boolean/`null` elsewhere in the envelope would otherwise become an
|
|
30
|
-
* unquoted `<redacted>` and break the output as JSON.
|
|
31
|
-
*
|
|
32
|
-
* Does not cover a secret used as an object *key* (e.g. `context: { [secret]: true }`) —
|
|
33
|
-
* `JSON.stringify`'s replacer can only transform values, never rename keys. No current
|
|
34
|
-
* caller does this (`context` keys are always fixed, SDK-chosen strings), and the CLI's own
|
|
35
|
-
* `logger.log(serializeError(...))` call site is still protected regardless, since that
|
|
36
|
-
* redaction pass re-scans the fully rendered JSON text and does not distinguish key
|
|
37
|
-
* position from value position.
|
|
22
|
+
* Serialize a CLI failure into the stable JSON error envelope that `errorToJson` returns.
|
|
38
23
|
* @param error - Failure to serialize
|
|
39
24
|
* @param options - JSON serialization options
|
|
40
25
|
* @returns Serialized JSON error envelope
|
|
41
26
|
*/
|
|
42
|
-
export declare function serializeError(error: unknown, options?: ErrorToJsonOptions): string;
|
|
27
|
+
export declare function serializeError(error: unknown, options?: ErrorToJsonOptions): string;
|
|
28
|
+
export {};
|
|
@@ -9,4 +9,6 @@ export interface FunctionLogEntryInfo {
|
|
|
9
9
|
severity: string;
|
|
10
10
|
/** When the line was logged, or null when unknown */
|
|
11
11
|
timestamp: Date | null;
|
|
12
|
+
/** Who wrote the line: `USER` for your code, `PLATFORM` for the Platform, or `UNSPECIFIED` when not recorded or not recognized by this CLI version */
|
|
13
|
+
source: string;
|
|
12
14
|
}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
+
/** Options every prompt accepts. */
|
|
2
|
+
export interface BasePromptConfig {
|
|
3
|
+
/** Remediation reported when the prompt cannot be shown, such as the option or environment variable that supplies the answer instead. */
|
|
4
|
+
suggestion?: string;
|
|
5
|
+
}
|
|
1
6
|
/** Options accepted by {@link prompt.confirm}. */
|
|
2
|
-
export interface ConfirmConfig {
|
|
7
|
+
export interface ConfirmConfig extends BasePromptConfig {
|
|
3
8
|
message: string;
|
|
4
9
|
default?: boolean;
|
|
5
10
|
}
|
|
6
11
|
/** Options accepted by {@link prompt.text}. */
|
|
7
|
-
export interface TextConfig {
|
|
12
|
+
export interface TextConfig extends BasePromptConfig {
|
|
8
13
|
message: string;
|
|
9
14
|
default?: string;
|
|
10
15
|
required?: boolean;
|
|
11
16
|
validate?: (value: string) => boolean | string | Promise<boolean | string>;
|
|
12
17
|
}
|
|
13
18
|
/** Options accepted by {@link prompt.password}. */
|
|
14
|
-
export interface PasswordConfig {
|
|
19
|
+
export interface PasswordConfig extends BasePromptConfig {
|
|
15
20
|
message: string;
|
|
16
21
|
mask?: boolean | string;
|
|
17
22
|
validate?: (value: string) => boolean | string | Promise<boolean | string>;
|
|
@@ -25,7 +30,7 @@ export interface SelectChoice<Value> {
|
|
|
25
30
|
disabled?: boolean | string;
|
|
26
31
|
}
|
|
27
32
|
/** Options accepted by {@link prompt.select}. */
|
|
28
|
-
export interface SelectConfig<Value> {
|
|
33
|
+
export interface SelectConfig<Value> extends BasePromptConfig {
|
|
29
34
|
message: string;
|
|
30
35
|
choices: readonly SelectChoice<Value>[];
|
|
31
36
|
default?: NoInfer<Value>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{A as e,C as t,D as n,E as r,F as i,I as a,M as o,N as s,O as c,P as l,S as u,T as d,_ as f,a as p,b as m,c as h,d as g,f as _,g as v,h as y,i as b,j as x,k as S,l as C,m as w,n as T,o as E,p as D,r as O,s as k,t as A,u as j,v as M,w as N,x as P,y as F}from"./client-DOQv-BP8.mjs";import{t as I}from"./user-agent-vdHYF3QL.mjs";export{A as MAX_PAGE_SIZE,T as POOLED_UPLOAD_METHODS,O as RETRY_SAFE_CREATE_METHODS,b as UPLOAD_POOL_MAX_CONNECTIONS,p as closeConnectionPool,E as concurrencyLimitInterceptor,k as createPooledStreamTransport,h as createTransport,C as defaultConsoleBaseUrl,j as defaultPlatformBaseUrl,g as errorHandlingInterceptor,_ as fetchAll,D as fetchAllTolerant,w as fetchMachineUserToken,y as fetchPaged,v as fetchPlatformMachineUserToken,f as fetchUserInfo,M as findAccessTokenSource,F as getConsoleBaseUrl,m as getEffectivePlatformConfig,P as getOAuth2ClientId,u as getOrNull,t as getPlatformBaseUrl,N as hasStaticWebsiteUrlPlaceholder,d as initOAuth2Client,r as initOperatorClient,n as isDefaultPlatform,c as isNotFoundError,S as normalizeBaseUrl,e as parseMethodName,x as registerAccessTokenSource,o as rememberPlatformConfigForToken,s as resolveStaticWebsiteUrls,l as resolveStaticWebsiteUrlsInEnv,i as retryInterceptor,a as staticWebsiteNameFromPlaceholder,I as userAgent};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{i as e,l as t}from"./validation-errors-DqCeUW4L.mjs";import{a as n,p as r,t as i}from"./errors-9OOL3xOM.mjs";import{t as a}from"./user-agent-vdHYF3QL.mjs";import{z as o}from"zod";import{create as s}from"@bufbuild/protobuf";import{MethodOptions_IdempotencyLevel as c}from"@bufbuild/protobuf/wkt";import{Code as l,ConnectError as u,createClient as d}from"@connectrpc/connect";import{OAuth2Client as f}from"@badgateway/oauth2-client";import p from"p-limit";const m=/^\d*[1-9]\d*$/;function parsePositiveInt(e){if(e===void 0)return;let t=e.trim();if(!m.test(t))return;let n=Number.parseInt(t,10);return Number.isSafeInteger(n)?n:void 0}function resolveApplyConcurrency(){return parsePositiveInt(process.env.TAILOR_APPLY_CONCURRENCY)??16}function createApplyLimiter(){return p(resolveApplyConcurrency())}function byName(e,t){return e.name<t.name?-1:+(e.name>t.name)}const h=`https://api.tailor.tech`,g=`https://console.tailor.tech`,_=`/.well-known/oauth-authorization-server/oauth2/platform`,v=3e4,y=/* @__PURE__ */ new Map,b=/* @__PURE__ */ new Set;function readRenamedEnv(e,t){let n=process.env[e];if(n)return n;let i=process.env[t];if(i)return b.has(t)||(b.add(t),r.warn(`${t} is deprecated. Please use ${e} instead.`)),i}function getEnvPlatformUrl(){return readRenamedEnv(`TAILOR_PLATFORM_URL`,`PLATFORM_URL`)}function getEnvOAuth2ClientId(){return readRenamedEnv(`TAILOR_PLATFORM_OAUTH2_CLIENT_ID`,`PLATFORM_OAUTH2_CLIENT_ID`)}function normalizeBaseUrl(e){let t=new URL(e);return t.hash=``,t.search=``,t.toString().replace(/\/$/,``)}function getEffectivePlatformConfig(e={}){let t=e.platformUrl??getEnvPlatformUrl(),n=e.oauth2ClientId??getEnvOAuth2ClientId(),r=e.consoleUrl??process.env.TAILOR_PLATFORM_CONSOLE_URL,i={...t?{platformUrl:t}:{},...n?{oauth2ClientId:n}:{},...r?{consoleUrl:r}:{}};return Object.keys(i).length>0?i:void 0}function rememberPlatformConfigForToken(e,t){let n=getEffectivePlatformConfig(t);n?y.set(e,n):y.delete(e)}function getPlatformConfigForToken(e){return y.get(e)}function getPlatformBaseUrl(e={}){return normalizeBaseUrl(e.platformUrl??getEnvPlatformUrl()??`https://api.tailor.tech`)}function isDefaultPlatform(e){return getPlatformBaseUrl(e)===normalizeBaseUrl(h)}function getOAuth2ClientId(e={}){return e.oauth2ClientId??getEnvOAuth2ClientId()??`cpoc_0Iudir72fqSpqC6GQ58ri1cLAqcq5vJl`}function inferConsoleBaseUrl(e){let t=new URL(e);return t.hostname.startsWith(`api.`)?(t.hostname=t.hostname.replace(/^api\./,`console.`),normalizeBaseUrl(t.toString())):g}function getConsoleBaseUrl(e={}){if(e.consoleUrl)return normalizeBaseUrl(e.consoleUrl);if(e.platformUrl){let t=inferConsoleBaseUrl(e.platformUrl);if(t!==`https://console.tailor.tech`)return t}return process.env.TAILOR_PLATFORM_CONSOLE_URL?normalizeBaseUrl(process.env.TAILOR_PLATFORM_CONSOLE_URL):inferConsoleBaseUrl(getPlatformBaseUrl(e))}function initOAuth2Client(e){return new f({clientId:getOAuth2ClientId(e),server:getPlatformBaseUrl(e),discoveryEndpoint:_,fetch:(e,t)=>fetch(e,{...t,signal:AbortSignal.any([...t?.signal?[t.signal]:[],AbortSignal.timeout(v)])})})}const x=/* @__PURE__ */ new Map;function registerAccessTokenSource(e,t){x.set(e,t)}function findAccessTokenSource(e){return x.get(e)}async function initOperatorClient(e,t,n={}){let r=t??getPlatformConfigForToken(e),[{createTracingInterceptor:i},{OperatorService:a}]=await Promise.all([import(`./interceptor-DQg3cR_9.mjs`),import(`./service_pb-Bethc2NW.mjs`)]),o=(n.renewToken===!1?void 0:findAccessTokenSource(e))??{current:async()=>e,replaceRejected:async()=>void 0},s=[await userAgentInterceptor(),await bearerTokenInterceptor(o),retryInterceptor(),errorHandlingInterceptor(),i(),concurrencyLimitInterceptor()],c=getPlatformBaseUrl(r),l=createPooledStreamTransport(await createTransport(c,s),()=>createTransport(c,s),4);return d(a,l)}async function createTransport(e,t){let{createConnectTransport:n}=await import(`@connectrpc/connect-node`);return n({httpVersion:`2`,baseUrl:e,interceptors:t})}const S=/* @__PURE__ */ new Set([`CreateFunctionRegistry`,`UpdateFunctionRegistry`,`UploadFile`]),C=4;function createPooledStreamTransport(e,t,n){if(!Number.isInteger(n)||n<1)throw Error(`createPooledStreamTransport: maxConnections must be a positive integer, got ${n}`);let r=[e],i=[0],a=[],o=0;function acquireTransportIndex(e,s){return new Promise((c,d)=>{let f=!1,p;function cleanup(){f=!0,clearTimeout(p),e?.removeEventListener(`abort`,onAbort);let t=a.indexOf(attempt);t!==-1&&a.splice(t,1)}function onAbort(){cleanup(),d(u.from(e?.reason,l.Canceled))}function onTimeout(){cleanup(),d(new u(`the operation timed out`,l.DeadlineExceeded))}function claim(e){f?release(e):(cleanup(),c(e))}function attempt(){let e=i.pop();e===void 0?r.length+o<n?(o++,t().then(e=>{o--;let t=r.length;r.push(e),claim(t)},e=>{o--,cleanup(),d(e instanceof Error?e:Error(String(e))),wakeOneWaiter()})):a.push(attempt):claim(e)}if(e?.aborted)onAbort();else{if(e?.addEventListener(`abort`,onAbort,{once:!0}),s!==void 0){let e=s-performance.now();if(e<=0){onTimeout();return}p=setTimeout(onTimeout,e)}attempt()}})}function wakeOneWaiter(){a.shift()?.()}function release(e){i.push(e),wakeOneWaiter()}return{unary(t,n,r,i,a,o){return e.unary(t,n,r,i,a,o)},async stream(t,n,i,a,o,s){if(!S.has(t.name))return e.stream(t,n,i,a,o,s);let c=i!==void 0&&i>0?performance.now()+i:void 0,d=await acquireTransportIndex(n,c),f=r[d],p;try{if(n?.aborted)throw u.from(n.reason,l.Canceled);let e=c===void 0?i:Math.ceil(c-performance.now());if(c!==void 0&&e!==void 0&&e<=0)throw new u(`the operation timed out`,l.DeadlineExceeded);p=await f.stream(t,n,e,a,o,s)}catch(e){throw release(d),e}return{...p,message:releaseAfter(p.message,()=>release(d))}}}}async function*releaseAfter(e,t){try{yield*e}finally{t()}}async function userAgentInterceptor(){let e=await a();return t=>async n=>(n.header.set(`User-Agent`,e),await t(n))}async function bearerTokenInterceptor(e){return t=>async n=>{let i=await currentAccessToken(e);n.header.set(`Authorization`,`Bearer ${i}`);try{return await t(n)}catch(a){if(n.stream||!(a instanceof u)||a.code!==l.Unauthenticated)throw a;let o=await e.replaceRejected(i).catch(e=>{r.debug(`Could not replace the rejected access token: ${String(e)}`)});if(!o||o===i)throw a;return n.header.set(`Authorization`,`Bearer ${o}`),await t(n)}}}async function currentAccessToken(e){try{return await e.current()}catch(e){throw t(new u(e instanceof Error?e.message:String(e),l.Unauthenticated,void 0,void 0,e),{...n(e)&&e.code?{code:e.code}:{},...n(e)&&e.suggestion?{suggestion:e.suggestion}:{},causes:{authentication:e}})}}function retryInterceptor(){return e=>async t=>{if(t.stream)return await e(t);let n,i=!1;for(let a=0;a<T;a++){a>0&&await waitRetryBackoff(a);try{return await e(t)}catch(e){if(isRetrySafeCreateAlreadyExists(e,t.method.name)){if(i)return r.debug(`retry: ${t.method.name} returned AlreadyExists on attempt ${a+1}; treating as success (prior attempt likely committed)`),synthesizeEmptyUnaryResponse(t);let{reportCrash:n}=await import(`./crashreport-GRnWyDnF.mjs`);await n(e,`handledError`)}let o=isPreHandshakeDisconnect(e);if(o||!E.has(t.method.name)&&isRetirable(e,t.method.idempotency)){n=e,i||=!o,r.debug(`retry: ${t.method.name} attempt ${a+1} failed with ${retryErrorCodeName(e)}; retrying`);continue}throw e}}throw n}}function concurrencyLimitInterceptor(){let e=createApplyLimiter();return t=>async n=>n.stream?await t(n):await e(()=>t(n))}function retryErrorCodeName(e){return e instanceof u?l[e.code]:isTransportDisconnectError(e)?e.code:`unknown`}const w=/* @__PURE__ */ new Set([`CreateAIGateway`,`CreateApplication`,`CreateAuthConnection`,`CreateAuthHook`,`CreateAuthIDPConfig`,`CreateAuthMachineUser`,`CreateAuthOAuth2Client`,`CreateAuthSCIMConfig`,`CreateAuthSCIMResource`,`CreateAuthService`,`CreateExecutorExecutor`,`CreateIdPService`,`CreatePipelineResolver`,`CreatePipelineService`,`CreateSecretManagerSecret`,`CreateSecretManagerVault`,`CreateStaticWebsite`,`CreateTailorDBGQLPermission`,`CreateTailorDBService`,`CreateTailorDBType`,`CreateTenantConfig`,`CreateUserProfileConfig`,`CreateWorkflow`,`CreateWorkflowJobFunctionExecutionPolicy`]);function isRetrySafeCreateAlreadyExists(e,t){return e instanceof u&&e.code===l.AlreadyExists&&w.has(t)}function synthesizeEmptyUnaryResponse(e){return{stream:!1,service:e.service,method:e.method,header:new Headers,message:s(e.method.output),trailer:new Headers}}const T=3,E=/* @__PURE__ */ new Set([`CloneApplicationData`,`CreateWorkspace`,`StartWorkflow`]);function waitRetryBackoff(e){let t=500*2**(e-1)*(1+.1*(Math.random()*2-1));return new Promise(e=>setTimeout(e,t))}const D=/* @__PURE__ */ new Set([`ERR_STREAM_PREMATURE_CLOSE`,`ECONNRESET`,`ETIMEDOUT`,`EPIPE`]);function isTransportDisconnectError(e){return e instanceof Error&&`code`in e&&typeof e.code==`string`&&D.has(e.code)}function isPreHandshakeDisconnect(e){if(!(e instanceof u))return!1;let{cause:t}=e;return isTransportDisconnectError(t)&&t.code===`ECONNRESET`&&t.message===`Client network socket disconnected before secure TLS connection was established`}function isRetirable(e,t){let n=t===c.NO_SIDE_EFFECTS||t===c.IDEMPOTENT;if(!(e instanceof u))return isTransportDisconnectError(e)&&n;switch(e.code){case l.ResourceExhausted:case l.Unavailable:return!0;case l.Aborted:case l.Internal:return n;default:return!1}}function errorHandlingInterceptor(){return e=>async n=>{try{return await e(n)}catch(e){if(e instanceof u){let{operation:r,resourceType:i}=parseMethodName(n.method.name),a=requestIdentifiers(n.message,n.method.name),o=Object.entries(a).map(([e,t])=>`${e}: ${t}`),s=o.length===0?``:` (${o.join(`, `)})`;throw t(Object.assign(new u(`Failed to ${r} ${i}${s}: ${e.rawMessage}`,e.code,e.metadata,void 0,e.cause),{details:e.details}),{context:{method:n.method.name,identifiers:a}})}throw isTransportDisconnectError(e)?t(e,{code:`TRANSPORT_DISCONNECTED`,suggestion:`Check network connectivity and platform availability. A write may already have completed; inspect the current resource state before retrying.`,context:{method:n.method.name,transportCode:e.code,identifiers:requestIdentifiers(n.message,n.method.name)}}):e}}}function parseMethodName(e){let t=e.match(/^(Create|Update|Delete|Set|List|Get)(.+)$/);if(!t)return{operation:`perform`,resourceType:`resource`};let[,n,r]=t;return{operation:n.toLowerCase(),resourceType:r}}const O=/* @__PURE__ */ new Set([`name`,`id`]),k=[`Name`,`Id`,`Namespace`],A=`name`,j={GetMetadata:[`trn`],SetMetadata:[`trn`],AddCustomDomain:[`domain`],GetCustomDomain:[`domain`],RemoveCustomDomain:[`domain`],RequestCustomDomainTransfer:[`domain`],CancelCustomDomainTransfer:[`domain`],AcceptCustomDomainTransfer:[`domain`],GetCustomDomainTransfer:[`domain`],CreateWorkflowJobFunctionExecutionPolicy:[`executionPolicyKey`],UpdateWorkflowJobFunctionExecutionPolicy:[`executionPolicyKey`],GetWorkflowJobFunctionExecutionPolicyByKey:[`executionPolicyKey`]};function isIdentityKey(e,t){return e.startsWith(`$`)?!1:O.has(e)||k.some(t=>e.endsWith(t))||(j[t]?.includes(e)??!1)}function requestIdentifiers(e,t){if(typeof e!=`object`||!e)return{};let n={};for(let[r,i]of Object.entries(e))if(typeof i==`string`&&i!==``&&isIdentityKey(r,t))n[r]=i;else if(!r.startsWith(`$`)&&typeof i==`object`&&i&&!Array.isArray(i)&&typeof i.$typeName==`string`){let e=i[A];typeof e==`string`&&e!==``&&(n[`${r}.${A}`]=e)}return n}const M=1e3;async function fetchAll(e){let t=[],n=``;for(;;){let[r,i]=await e(n,M);if(t.push(...r),!i)break;n=i}return t}function isNotFoundError(e){return e instanceof u&&e.code===l.NotFound}async function fetchAllTolerant(e){return await fetchAll(async(t,n)=>{try{return await e(t,n)}catch(e){if(isNotFoundError(e))return[[],``];throw e}})}async function getOrNull(e){try{return await e()}catch(e){if(isNotFoundError(e))return;throw e}}async function fetchPaged(e,t){let n=t?.limit,r=n===void 0||n===0,i=[],a=``;for(;;){let t=r?M:Math.min(n-i.length,M);if(!r&&t<=0)break;let[o,s]=await e(a,t);if(i.push(...o),!r&&i.length>=n||!s)break;a=s}return!r&&i.length>n?i.slice(0,n):i}async function fetchUserInfo(t,n){let r=new URL(`/auth/platform/userinfo`,getPlatformBaseUrl(n)).href,i=await fetch(r,{headers:{Authorization:`Bearer ${t}`,"User-Agent":await a()},signal:AbortSignal.timeout(v)});if(!i.ok)throw Error(`Failed to fetch user info: ${i.statusText}`);let s=await i.json(),c=o.object({sub:o.string(),email:o.string()}).safeParse(s);if(!c.success)throw e(`user info response`,c.error);return c.data}const N=/:url(\/.*)?$/;function hasStaticWebsiteUrlPlaceholder(e){return typeof e==`string`&&N.test(e)}function staticWebsiteNameFromPlaceholder(e){let t=e.match(N);return t?.index===void 0?e:e.substring(0,t.index)}async function resolveStaticWebsiteUrls(e,t,n,a,o={}){if(!n)return[];let{expectedLocalNames:s,keepUnresolved:c=!1,failOnUnexpectedError:l=!1}=o,unresolved=e=>c?[e]:[],u=c?`Leaving the ${a} value unresolved.`:`Excluding from ${a}.`,d=o.siteLookupCache??/* @__PURE__ */ new Map,lookupSite=n=>{let r=d.get(n);return r||(r=e.getStaticWebsite({workspaceId:t,name:n}),d.set(n,r)),r};return(await Promise.all(n.map(async e=>{let t=e.match(N);if(t&&t.index!==void 0){let n=e.substring(0,t.index),o=t[1]||``;try{let t=await lookupSite(n);if(t.staticwebsite?.url)return[t.staticwebsite.url+o];if(!s?.has(n)&&l)throw i({code:`STATIC_WEBSITE_URL_NOT_ASSIGNED`,message:`Static website "${n}" exists but has no URL assigned yet.`,suggestion:`Re-run the deploy once the static website's URL is available.`});return r.warn(`Static website "${n}" has no URL assigned yet. ${u}`),unresolved(e)}catch(t){if(isNotFoundError(t)){if(s?.has(n))return[e]}else if(l)throw t;return r.warn(`Static website "${n}" not found for ${a} configuration. ${u}`),unresolved(e)}}return[e]}))).flat()}async function resolveStaticWebsiteUrlsInEnv(e,t,n,r={}){if(!n||!Object.values(n).some(hasStaticWebsiteUrlPlaceholder))return n??{};let i=/* @__PURE__ */ new Map,a=await Promise.all(Object.entries(n).map(async([n,a])=>{if(!hasStaticWebsiteUrlPlaceholder(a))return[n,a];let[o]=await resolveStaticWebsiteUrls(e,t,[a],`env "${n}"`,{...r,keepUnresolved:!0,failOnUnexpectedError:!0,siteLookupCache:i});return[n,o??a]})),o=Object.fromEntries(a);return warnUnresolvedEnvPlaceholders(o,r.expectedLocalNames),o}function warnUnresolvedEnvPlaceholders(e,t){for(let[n,i]of Object.entries(e)){if(!hasStaticWebsiteUrlPlaceholder(i))continue;let e=i.slice(0,i.search(N));t?.has(e)?r.warn(`env "${n}" keeps the unresolved value "${i}" for now because static website "${e}" isn't available yet; this deploy rebuilds automatically once it is, to inject the real URL.`):r.warn(`env "${n}" keeps the unresolved value "${i}". The literal pattern is passed to your code at runtime.`)}}async function fetchMachineUserToken(t,n,i){r.registerSecret(i);let s=new URL(`/oauth2/token`,t).href,c=new URLSearchParams;c.append(`grant_type`,`client_credentials`),c.append(`client_id`,n),c.append(`client_secret`,i);let l={method:`POST`,headers:{"User-Agent":await a(),"Content-Type":`application/x-www-form-urlencoded`},body:c},u=await withConnectTimeoutRetry(`machine user token request`,()=>fetch(s,l));if(!u.ok){let e=await u.text().catch(()=>``);throw Error(`Failed to fetch machine user token: ${u.status} ${u.statusText} ${e.slice(0,500)}`)}let d=await u.json(),f=o.object({token_type:o.string(),access_token:o.string(),expires_in:o.number()}).safeParse(d);if(!f.success)throw e(`machine user token response`,f.error);return r.registerSecret(f.data.access_token),f.data}function isUndiciConnectTimeout(e){if(!(e instanceof TypeError))return!1;let t=e.cause;return t instanceof Error&&`code`in t&&t.code===`UND_ERR_CONNECT_TIMEOUT`}async function withConnectTimeoutRetry(e,t){for(let n=1;;n++)try{return await t()}catch(t){if(!isUndiciConnectTimeout(t)||n>=3)throw t;r.debug(`retry: ${e} attempt ${n} failed with UND_ERR_CONNECT_TIMEOUT; retrying`),await waitRetryBackoff(n)}}async function fetchPlatformMachineUserToken(e,t,n){r.registerSecret(t);let i=getPlatformBaseUrl(n),a=await withConnectTimeoutRetry(`platform machine user token request`,()=>new f({clientId:e,clientSecret:t,server:i,discoveryEndpoint:_}).clientCredentials());return r.registerSecret(a.accessToken),a.refreshToken&&r.registerSecret(a.refreshToken),a}async function closeConnectionPool(){let e=globalThis,t=e[Symbol.for(`undici.globalDispatcher.2`)]??e[Symbol.for(`undici.globalDispatcher.1`)];typeof t?.close==`function`&&await t.close()}export{parseMethodName as A,getPlatformBaseUrl as C,isDefaultPlatform as D,initOperatorClient as E,retryInterceptor as F,staticWebsiteNameFromPlaceholder as I,byName as L,rememberPlatformConfigForToken as M,resolveStaticWebsiteUrls as N,isNotFoundError as O,resolveStaticWebsiteUrlsInEnv as P,createApplyLimiter as R,getOrNull as S,initOAuth2Client as T,fetchUserInfo as _,closeConnectionPool as a,getEffectivePlatformConfig as b,createTransport as c,errorHandlingInterceptor as d,fetchAll as f,fetchPlatformMachineUserToken as g,fetchPaged as h,C as i,registerAccessTokenSource as j,normalizeBaseUrl as k,g as l,fetchMachineUserToken as m,S as n,concurrencyLimitInterceptor as o,fetchAllTolerant as p,w as r,createPooledStreamTransport as s,M as t,h as u,findAccessTokenSource as v,hasStaticWebsiteUrlPlaceholder as w,getOAuth2ClientId as x,getConsoleBaseUrl as y,parsePositiveInt as z};
|
|
2
|
+
//# sourceMappingURL=client-DOQv-BP8.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-DOQv-BP8.mjs","names":["invalidDataError","withErrorDiagnostics","isCLIError","logger","CLIError","userAgent","pLimit","POSITIVE_INT_PATTERN","value","normalized","parsed","a","b","defaultPlatformBaseUrl","defaultConsoleBaseUrl","oauth2DiscoveryEndpoint","OAUTH2_REQUEST_TIMEOUT_MS","tokenPlatformConfigs","warnedDeprecatedEnvNames","name","deprecatedValue","deprecatedName","url","platformUrl","config","oauth2ClientId","consoleUrl","effective","effectiveConfig","accessToken","platformBaseUrl","inferredUrl","OAuth2Client","input","init","accessTokenSources","source","platformConfig","tokenSource","options","interceptors","createTracingInterceptor","baseUrl","transport","createClient","OperatorService","createConnectTransport","POOLED_UPLOAD_METHODS","UPLOAD_POOL_MAX_CONNECTIONS","maxConnections","transports","primary","idle","waiters","pendingCreates","settled","timer","signal","waiterIndex","reject","ConnectError","Code","index","resolve","idleIndex","createAdditional","error","deadline","remainingMs","method","timeoutMs","header","contextValues","response","iterable","release","ua","req","next","token","replacement","replaceError","lastError","priorAttemptMayHaveCommitted","i","MAX_RETRY_ATTEMPTS","reportCrash","preHandshakeDisconnect","NON_RETRIED_METHODS","limit","RETRY_SAFE_CREATE_METHODS","methodName","create","backoff","attempt","TRANSPORT_DISCONNECT_ERROR_CODES","cause","isIdempotentOrSideEffectFree","idempotency","MethodOptions_IdempotencyLevel","identifiers","parts","key","identity","operation","resourceType","match","action","resource","IDENTITY_KEYS","IDENTITY_KEY_SUFFIXES","NESTED_IDENTITY_KEY","METHOD_IDENTITY_KEYS","suffix","message","nestedName","MAX_PAGE_SIZE","items","pageToken","batch","nextPageToken","fn","maxPageSize","unbounded","pageSize","userInfoUrl","resp","rawJson","result","z","STATIC_WEBSITE_URL_PATTERN","urls","keepUnresolved","fallbackNote","context","siteLookupCache","lookup","siteName","client","pathSuffix","expectedLocalNames","failOnUnexpectedError","env","entries","resolved","workspaceId","clientSecret","tokenEndpoint","formData","clientId","request","body","send","label","server","globals","dispatcher"],"sources":["../src/cli/shared/parse-positive-int.ts","../src/cli/shared/apply-concurrency.ts","../src/cli/shared/client.ts"],"sourcesContent":["const POSITIVE_INT_PATTERN = /^\\d*[1-9]\\d*$/;\n\n/**\n * Parse a string value as a positive integer.\n *\n * Only decimal digits are accepted (leading zeros allowed), so `0`, negative\n * numbers, decimals, exponent notation, and signed values are all rejected.\n * Values above `Number.MAX_SAFE_INTEGER` are rejected too: past that point the\n * parsed number no longer represents the digits it came from, so it cannot\n * describe a meaningful limit.\n *\n * Undefined, empty strings, and unrecognized values return `undefined` so\n * that callers can fall back to their own defaults.\n * @param value - The input string (e.g. an environment variable or CLI flag value)\n * @returns The parsed integer, or `undefined` when the value is unset or unrecognized\n */\nexport function parsePositiveInt(value: string | undefined): number | undefined {\n if (value === undefined) return undefined;\n const normalized = value.trim();\n if (!POSITIVE_INT_PATTERN.test(normalized)) return undefined;\n const parsed = Number.parseInt(normalized, 10);\n return Number.isSafeInteger(parsed) ? parsed : undefined;\n}\n","import pLimit from \"p-limit\";\nimport { parsePositiveInt } from \"./parse-positive-int\";\n\n/**\n * Default cap on concurrent operator RPCs when `TAILOR_APPLY_CONCURRENCY` is\n * unset. Chosen to tame the create burst (a fresh workspace fires one\n * `create*` per resource at once) that triggers the platform-side\n * `already_exists` race on compound creates, while still deploying quickly.\n */\nconst DEFAULT_APPLY_CONCURRENCY = 16;\n\n/**\n * Resolve the maximum number of operator RPCs to run in parallel.\n *\n * Resolution order:\n * 1. `TAILOR_APPLY_CONCURRENCY` env var (positive integer)\n * 2. `DEFAULT_APPLY_CONCURRENCY`\n *\n * A fresh-workspace apply creates every resource at once; firing all of them\n * concurrently overloads the platform, whose responses then come back as\n * `Unavailable`/`ResourceExhausted` and drive retries into the non-idempotent\n * compound-create `already_exists` race. Capping bounds the worst case.\n *\n * This is unrelated to the streaming-upload connection pool (see\n * `createPooledStreamTransport` in `client.ts`), which uses its own smaller,\n * internal connection cap: upload concurrency varies independently by call\n * site (e.g. static website deploys upload with their own fixed concurrency),\n * so this budget can't be assumed to bound how many uploads run at once.\n * @returns Concurrency cap (always >= 1)\n */\nexport function resolveApplyConcurrency(): number {\n return parsePositiveInt(process.env.TAILOR_APPLY_CONCURRENCY) ?? DEFAULT_APPLY_CONCURRENCY;\n}\n\n/**\n * Create a limiter capped at the resolved apply concurrency. The returned\n * function defers a task until a slot is free, then resolves with its result.\n *\n * Share a single instance across all RPCs that should contend for the same\n * budget (e.g. one per operator client) so the cap bounds total in-flight\n * calls, not per-call-site bursts.\n * @returns A limiter that defers tasks beyond the concurrency cap\n */\nexport function createApplyLimiter(): <R>(task: () => Promise<R>) => Promise<R> {\n return pLimit(resolveApplyConcurrency());\n}\n\n/**\n * Comparator that orders `name`-bearing items by `name`, for a stable,\n * reproducible apply order within the concurrency cap.\n *\n * Uses a code-point comparison rather than `localeCompare` so the order does\n * not depend on the runtime's default locale/collation.\n * @param a - Left item\n * @param b - Right item\n * @returns Negative, zero, or positive per code-point ordering of the names\n */\nexport function byName(a: { name: string }, b: { name: string }): number {\n if (a.name < b.name) return -1;\n if (a.name > b.name) return 1;\n return 0;\n}\n","import { OAuth2Client } from \"@badgateway/oauth2-client\";\nimport { create } from \"@bufbuild/protobuf\";\nimport { MethodOptions_IdempotencyLevel } from \"@bufbuild/protobuf/wkt\";\nimport {\n type Client,\n Code,\n ConnectError,\n createClient,\n type Interceptor,\n type StreamResponse,\n type Transport,\n type UnaryResponse,\n} from \"@connectrpc/connect\";\nimport { z } from \"zod\";\nimport { createApplyLimiter } from \"./apply-concurrency\";\nimport { withErrorDiagnostics } from \"./error-diagnostics\";\nimport { CLIError, isCLIError } from \"./errors\";\nimport { logger } from \"./logger\";\nimport { userAgent } from \"./user-agent\";\nimport { invalidDataError } from \"./validation-errors\";\nimport type { OperatorService } from \"@tailor-platform/tailor-proto/service_pb\";\n\nexport const defaultPlatformBaseUrl = \"https://api.tailor.tech\";\nexport const defaultConsoleBaseUrl = \"https://console.tailor.tech\";\n\nconst defaultOAuth2ClientId = \"cpoc_0Iudir72fqSpqC6GQ58ri1cLAqcq5vJl\";\nconst oauth2DiscoveryEndpoint = \"/.well-known/oauth-authorization-server/oauth2/platform\";\nconst OAUTH2_REQUEST_TIMEOUT_MS = 30_000;\n\nexport type PlatformClientConfig = {\n platformUrl?: string;\n oauth2ClientId?: string;\n consoleUrl?: string;\n};\n\nconst tokenPlatformConfigs = new Map<string, PlatformClientConfig>();\n\nconst warnedDeprecatedEnvNames = new Set<string>();\n\nfunction readRenamedEnv(name: string, deprecatedName: string): string | undefined {\n const value = process.env[name];\n if (value) return value;\n const deprecatedValue = process.env[deprecatedName];\n if (!deprecatedValue) return undefined;\n if (!warnedDeprecatedEnvNames.has(deprecatedName)) {\n warnedDeprecatedEnvNames.add(deprecatedName);\n logger.warn(`${deprecatedName} is deprecated. Please use ${name} instead.`);\n }\n return deprecatedValue;\n}\n\nfunction getEnvPlatformUrl(): string | undefined {\n return readRenamedEnv(\"TAILOR_PLATFORM_URL\", \"PLATFORM_URL\");\n}\n\nfunction getEnvOAuth2ClientId(): string | undefined {\n return readRenamedEnv(\"TAILOR_PLATFORM_OAUTH2_CLIENT_ID\", \"PLATFORM_OAUTH2_CLIENT_ID\");\n}\n\nexport function normalizeBaseUrl(value: string): string {\n const url = new URL(value);\n url.hash = \"\";\n url.search = \"\";\n return url.toString().replace(/\\/$/, \"\");\n}\n\nexport function getEffectivePlatformConfig(config: PlatformClientConfig = {}) {\n const platformUrl = config.platformUrl ?? getEnvPlatformUrl();\n const oauth2ClientId = config.oauth2ClientId ?? getEnvOAuth2ClientId();\n const consoleUrl = config.consoleUrl ?? process.env.TAILOR_PLATFORM_CONSOLE_URL;\n const effective = {\n ...(platformUrl ? { platformUrl } : {}),\n ...(oauth2ClientId ? { oauth2ClientId } : {}),\n ...(consoleUrl ? { consoleUrl } : {}),\n };\n return Object.keys(effective).length > 0 ? effective : undefined;\n}\n\nexport function rememberPlatformConfigForToken(accessToken: string, config?: PlatformClientConfig) {\n const effectiveConfig = getEffectivePlatformConfig(config);\n if (effectiveConfig) {\n tokenPlatformConfigs.set(accessToken, effectiveConfig);\n } else {\n tokenPlatformConfigs.delete(accessToken);\n }\n}\n\nfunction getPlatformConfigForToken(accessToken: string): PlatformClientConfig | undefined {\n return tokenPlatformConfigs.get(accessToken);\n}\n\nexport function getPlatformBaseUrl(config: PlatformClientConfig = {}) {\n return normalizeBaseUrl(config.platformUrl ?? getEnvPlatformUrl() ?? defaultPlatformBaseUrl);\n}\n\nexport function isDefaultPlatform(config?: PlatformClientConfig): boolean {\n return getPlatformBaseUrl(config) === normalizeBaseUrl(defaultPlatformBaseUrl);\n}\n\nexport function getOAuth2ClientId(config: PlatformClientConfig = {}) {\n return config.oauth2ClientId ?? getEnvOAuth2ClientId() ?? defaultOAuth2ClientId;\n}\n\nfunction inferConsoleBaseUrl(platformBaseUrl: string) {\n const platformUrl = new URL(platformBaseUrl);\n if (platformUrl.hostname.startsWith(\"api.\")) {\n platformUrl.hostname = platformUrl.hostname.replace(/^api\\./, \"console.\");\n return normalizeBaseUrl(platformUrl.toString());\n }\n return defaultConsoleBaseUrl;\n}\n\nexport function getConsoleBaseUrl(config: PlatformClientConfig = {}) {\n if (config.consoleUrl) return normalizeBaseUrl(config.consoleUrl);\n if (config.platformUrl) {\n const inferredUrl = inferConsoleBaseUrl(config.platformUrl);\n if (inferredUrl !== defaultConsoleBaseUrl) return inferredUrl;\n }\n if (process.env.TAILOR_PLATFORM_CONSOLE_URL)\n return normalizeBaseUrl(process.env.TAILOR_PLATFORM_CONSOLE_URL);\n return inferConsoleBaseUrl(getPlatformBaseUrl(config));\n}\n\n/**\n * Initialize an OAuth2 client for Tailor Platform.\n * @param config - Optional platform connection settings\n * @returns Configured OAuth2 client\n */\nexport function initOAuth2Client(config?: PlatformClientConfig) {\n return new OAuth2Client({\n clientId: getOAuth2ClientId(config),\n server: getPlatformBaseUrl(config),\n discoveryEndpoint: oauth2DiscoveryEndpoint,\n fetch: (input, init) =>\n fetch(input, {\n ...init,\n signal: AbortSignal.any([\n ...(init?.signal ? [init.signal] : []),\n AbortSignal.timeout(OAUTH2_REQUEST_TIMEOUT_MS),\n ]),\n }),\n });\n}\n\nexport type OperatorClient = Client<typeof OperatorService>;\n\n/**\n * Supplies the access token the Operator client sends, and a replacement after the\n * Platform rejects one.\n * @internal\n */\nexport type AccessTokenSource = {\n /** Token to send now. */\n current(): Promise<string>;\n /** A different token to retry with after `rejected` was refused, if there is one. */\n replaceRejected(rejected: string): Promise<string | undefined>;\n};\n\nconst accessTokenSources = new Map<string, AccessTokenSource>();\n\n/**\n * Let Operator clients created with `accessToken` take their token from `source`.\n * @internal\n * @param accessToken - Token a caller passes to {@link initOperatorClient}\n * @param source - Source that renews the token\n */\nexport function registerAccessTokenSource(accessToken: string, source: AccessTokenSource) {\n accessTokenSources.set(accessToken, source);\n}\n\n/**\n * Find the source registered for an access token.\n * @internal\n * @param accessToken - Token a caller passes to {@link initOperatorClient}\n * @returns The registered source, if any\n */\nexport function findAccessTokenSource(accessToken: string): AccessTokenSource | undefined {\n return accessTokenSources.get(accessToken);\n}\n\n/** Options for {@link initOperatorClient}. */\ninterface OperatorClientOptions {\n /**\n * Renew a browser-login token while the client runs (default true). Pass false for a\n * best-effort call that may be abandoned mid-flight, which must never rotate the stored login.\n */\n renewToken?: boolean;\n}\n\n/**\n * Initialize an Operator client with the given access token.\n * A client created with a token that `loadAccessToken` returned for a browser login\n * (`tailor login`) renews the token while it runs, so it keeps working past the token's\n * lifetime; this can refresh and save the stored login. Other tokens, and every token when\n * `renewToken` is false, are sent as given.\n * @param accessToken - Access token for authentication\n * @param config - Optional platform connection settings\n * @param options - Client options\n * @returns Configured Operator client\n */\nexport async function initOperatorClient(\n accessToken: string,\n config?: PlatformClientConfig,\n options: OperatorClientOptions = {},\n) {\n const platformConfig = config ?? getPlatformConfigForToken(accessToken);\n const [{ createTracingInterceptor }, { OperatorService }] = await Promise.all([\n import(\"#/cli/telemetry/interceptor\"),\n import(\"@tailor-platform/tailor-proto/service_pb\"),\n ]);\n const renewing = options.renewToken === false ? undefined : findAccessTokenSource(accessToken);\n const tokenSource = renewing ?? {\n current: async () => accessToken,\n replaceRejected: async () => undefined,\n };\n\n const interceptors: Interceptor[] = [\n await userAgentInterceptor(),\n await bearerTokenInterceptor(tokenSource),\n retryInterceptor(),\n errorHandlingInterceptor(),\n createTracingInterceptor(),\n // Innermost: gates the actual network attempt so each retry re-acquires a\n // slot and backoff waits happen outside the cap.\n concurrencyLimitInterceptor(),\n ];\n\n const baseUrl = getPlatformBaseUrl(platformConfig);\n const primary = await createTransport(baseUrl, interceptors);\n const transport = createPooledStreamTransport(\n primary,\n () => createTransport(baseUrl, interceptors),\n UPLOAD_POOL_MAX_CONNECTIONS,\n );\n return createClient(OperatorService, transport);\n}\n\n/**\n * Create a Connect transport using connect-node (HTTP/2).\n *\n * connect-node works on both Node.js and Bun. connect-web is not used because\n * it does not support client_streaming, which is required for function uploads.\n * @param baseUrl - Base URL for the transport\n * @param interceptors - Request interceptors\n * @returns Configured transport\n */\nexport async function createTransport(\n baseUrl: string,\n interceptors: Interceptor[],\n): Promise<Transport> {\n const { createConnectTransport } = await import(\"@connectrpc/connect-node\");\n return createConnectTransport({ httpVersion: \"2\", baseUrl, interceptors });\n}\n\n/**\n * RPCs that upload a request body via client streaming and are affected by\n * the connection-pooling workaround below. Deliberately an allowlist rather\n * than `method.methodKind === \"client_streaming\"`: the workaround targets\n * outbound-DATA scheduling for uploads specifically, so a future streaming\n * RPC (client- or server-streaming) is routed to `primary` — unaffected and\n * unpooled — until someone consciously adds it here.\n *\n * A drift guard (see client.test.ts) fails CI if any `client_streaming`\n * OperatorService method is neither listed here nor explicitly exempt, so a\n * newly added client-streaming RPC can't silently bypass the pool by omission.\n * @internal\n */\nexport const POOLED_UPLOAD_METHODS: ReadonlySet<string> = new Set([\n \"CreateFunctionRegistry\",\n \"UpdateFunctionRegistry\",\n \"UploadFile\",\n]);\n\n/**\n * Hard cap on the number of HTTP/2 connections `createPooledStreamTransport`\n * opens. Deliberately small and internal (not derived from\n * `TAILOR_APPLY_CONCURRENCY`, which bounds unrelated RPC concurrency and can\n * be set arbitrarily large by a user) rather than a public env var: the pool\n * now queues callers past this limit instead of relying on the caller never\n * exceeding it, so correctness does not depend on this exact number. Not\n * validated against production connection limits — kept conservative until\n * real-platform data says otherwise.\n * @internal\n */\nexport const UPLOAD_POOL_MAX_CONNECTIONS = 4;\n\n/**\n * Wrap a transport so upload RPCs (see `POOLED_UPLOAD_METHODS`) are spread\n * across a bounded pool of connections instead of sharing one. Unary calls,\n * and any streaming call not in `POOLED_UPLOAD_METHODS`, always use\n * `primary`, unaffected.\n *\n * Since Node 22.23.0/24.2.0, nghttp2 dropped its legacy priority-tree\n * scheduler. In our measurements this changed how Node's http2 client\n * schedules concurrent outbound DATA streams: uploads sharing one connection\n * can finish 12x+ apart in wall-clock time even though aggregate throughput\n * is unchanged, and there is no request header or API that opts a stream\n * into different client-side scheduling. Spreading uploads across\n * independent connections sidesteps that rather than fixing it; see this\n * change's changeset entry for the measurement.\n *\n * Acquiring a connection: reuse an idle one if any exists; otherwise open a\n * new one if the pool is below `maxConnections`; otherwise wait for a\n * connection to become idle. A connection is never reused for a second\n * concurrent upload while the pool still has room to grow or a caller is\n * waiting — at most one upload is ever in flight per connection, regardless\n * of how many uploads are requested concurrently or how they're divided\n * across call sites (independent limiters at different call sites no longer\n * need to agree on a shared concurrency cap for this invariant to hold).\n *\n * The caller's `signal` and `timeoutMs` are honored while an upload is\n * queued, not just once it's dispatched: an abort or an elapsed deadline\n * rejects the queued call immediately and frees its place in line without\n * consuming a pool slot, and time already spent queued is deducted from the\n * deadline passed to the underlying transport once a connection is acquired.\n * @internal\n * @param primary - Transport used for unary calls, non-upload streams, and as the first pool slot\n * @param createAdditional - Creates one more transport for the pool\n * @param maxConnections - Maximum number of connections in the pool (>= 1)\n * @returns A transport presenting the same interface, backed by the pool\n */\nexport function createPooledStreamTransport(\n primary: Transport,\n createAdditional: () => Promise<Transport>,\n maxConnections: number,\n): Transport {\n if (!Number.isInteger(maxConnections) || maxConnections < 1) {\n throw new Error(\n `createPooledStreamTransport: maxConnections must be a positive integer, got ${maxConnections}`,\n );\n }\n const transports: Transport[] = [primary];\n const idle: number[] = [0];\n const waiters: Array<() => void> = [];\n let pendingCreates = 0;\n\n // Finds (or creates) a connection and marks it busy in the same\n // synchronous step (no `await` in between) so that two `stream()` calls\n // issued back to back (e.g. via `Promise.all(uploads.map(...))`, which\n // starts each task synchronously) can't both claim the same idle\n // transport before either marks it busy. Growth and waiting are the only\n // async steps; every other transition (finding an idle slot, deciding to\n // grow, waking a waiter) happens synchronously within one of these steps.\n function acquireTransportIndex(\n signal: AbortSignal | undefined,\n deadline: number | undefined,\n ): Promise<number> {\n return new Promise<number>((resolve, reject) => {\n let settled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n function cleanup(): void {\n settled = true;\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n const waiterIndex = waiters.indexOf(attempt);\n if (waiterIndex !== -1) waiters.splice(waiterIndex, 1);\n }\n\n function onAbort(): void {\n cleanup();\n reject(ConnectError.from(signal?.reason, Code.Canceled));\n }\n\n function onTimeout(): void {\n cleanup();\n reject(new ConnectError(\"the operation timed out\", Code.DeadlineExceeded));\n }\n\n function claim(index: number): void {\n if (settled) {\n release(index);\n return;\n }\n cleanup();\n resolve(index);\n }\n\n function attempt(): void {\n const idleIndex = idle.pop();\n if (idleIndex !== undefined) {\n claim(idleIndex);\n return;\n }\n if (transports.length + pendingCreates < maxConnections) {\n pendingCreates++;\n createAdditional().then(\n (transport) => {\n pendingCreates--;\n const index = transports.length;\n transports.push(transport);\n claim(index);\n },\n (error: unknown) => {\n pendingCreates--;\n cleanup();\n reject(error instanceof Error ? error : new Error(String(error)));\n // The failed connection never joins the pool, so a waiter\n // stuck behind \"pool full\" would wait forever unless woken to\n // retry (it may now see room to grow, or another release).\n wakeOneWaiter();\n },\n );\n return;\n }\n waiters.push(attempt);\n }\n if (signal?.aborted) {\n onAbort();\n return;\n }\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n if (deadline !== undefined) {\n const remainingMs = deadline - performance.now();\n if (remainingMs <= 0) {\n onTimeout();\n return;\n }\n timer = setTimeout(onTimeout, remainingMs);\n }\n attempt();\n });\n }\n\n function wakeOneWaiter(): void {\n waiters.shift()?.();\n }\n\n function release(index: number): void {\n idle.push(index);\n wakeOneWaiter();\n }\n\n return {\n unary(method, signal, timeoutMs, header, input, contextValues) {\n return primary.unary(method, signal, timeoutMs, header, input, contextValues);\n },\n async stream(method, signal, timeoutMs, header, input, contextValues) {\n if (!POOLED_UPLOAD_METHODS.has(method.name)) {\n return primary.stream(method, signal, timeoutMs, header, input, contextValues);\n }\n const deadline =\n timeoutMs !== undefined && timeoutMs > 0 ? performance.now() + timeoutMs : undefined;\n const index = await acquireTransportIndex(signal, deadline);\n const transport = transports[index] as Transport;\n let response: StreamResponse<typeof method.input, typeof method.output>;\n try {\n if (signal?.aborted) throw ConnectError.from(signal.reason, Code.Canceled);\n const remainingMs =\n deadline === undefined ? timeoutMs : Math.ceil(deadline - performance.now());\n if (deadline !== undefined && remainingMs !== undefined && remainingMs <= 0) {\n throw new ConnectError(\"the operation timed out\", Code.DeadlineExceeded);\n }\n response = await transport.stream(\n method,\n signal,\n remainingMs,\n header,\n input,\n contextValues,\n );\n } catch (error) {\n release(index);\n throw error;\n }\n // `stream()` resolves once response headers arrive, not once the\n // response is fully read (or the request body fully sent) — connect's\n // node http2 client starts writing the request body without waiting\n // for it, and only awaits headers here. Keep the connection marked\n // busy until the caller finishes reading `message`, so a connection\n // isn't reused while this upload is still in flight.\n return { ...response, message: releaseAfter(response.message, () => release(index)) };\n },\n };\n}\n\nasync function* releaseAfter<T>(iterable: AsyncIterable<T>, release: () => void): AsyncIterable<T> {\n try {\n yield* iterable;\n } finally {\n release();\n }\n}\n\n/**\n * Create an interceptor that sets a User-Agent header.\n * @returns User-Agent interceptor\n */\nasync function userAgentInterceptor(): Promise<Interceptor> {\n const ua = await userAgent();\n return (next) => async (req) => {\n req.header.set(\"User-Agent\", ua);\n return await next(req);\n };\n}\n\nexport { userAgent };\n\n/**\n * Create an interceptor that sets the Authorization bearer token, and retries a unary request\n * once with a replacement token when the Platform rejects the token. A streaming request is not\n * retried because its body cannot be sent again.\n * @param source - Source of the token to send\n * @returns Bearer token interceptor\n */\nasync function bearerTokenInterceptor(source: AccessTokenSource): Promise<Interceptor> {\n return (next) => async (req) => {\n const token = await currentAccessToken(source);\n req.header.set(\"Authorization\", `Bearer ${token}`);\n try {\n return await next(req);\n } catch (error) {\n if (req.stream || !(error instanceof ConnectError) || error.code !== Code.Unauthenticated) {\n throw error;\n }\n const replacement = await source.replaceRejected(token).catch((replaceError: unknown) => {\n logger.debug(`Could not replace the rejected access token: ${String(replaceError)}`);\n return undefined;\n });\n if (!replacement || replacement === token) throw error;\n req.header.set(\"Authorization\", `Bearer ${replacement}`);\n return await next(req);\n }\n };\n}\n\nasync function currentAccessToken(source: AccessTokenSource): Promise<string> {\n try {\n return await source.current();\n } catch (error) {\n throw withErrorDiagnostics(\n new ConnectError(\n error instanceof Error ? error.message : String(error),\n Code.Unauthenticated,\n undefined,\n undefined,\n error,\n ),\n {\n ...(isCLIError(error) && error.code ? { code: error.code } : {}),\n ...(isCLIError(error) && error.suggestion ? { suggestion: error.suggestion } : {}),\n causes: { authentication: error },\n },\n );\n }\n}\n\n/**\n * Create an interceptor that retries failed unary requests with backoff.\n *\n * Retries unary methods on `Unavailable`/`ResourceExhausted`, and\n * `Aborted`/`Internal` only for methods declared side-effect-free or idempotent,\n * up to 3 attempts. Workspace creation, workflow starts, and application data\n * cloning are excluded because they have no idempotency key and a lost response\n * is ambiguous: a retry could start a second operation, or fail while the first\n * keeps running.\n * A connection that closed before the TLS handshake completed is retried for every\n * unary method, since no request reached the server.\n * As a targeted exception for the deploy/apply flow, a post-retry `AlreadyExists`\n * from an allowlisted Create (see `RETRY_SAFE_CREATE_METHODS`) is treated as\n * success, since it means a prior attempt already committed the resource\n * server-side. An `AlreadyExists` from such a Create that no prior attempt could\n * have committed still surfaces, but is routed to crash/error reporting first (the\n * top-level handler skips `ConnectError`), so the otherwise-silent compound-create\n * race is trackable.\n * @internal\n * @returns Retry interceptor\n */\nexport function retryInterceptor(): Interceptor {\n return (next) => async (req) => {\n if (req.stream) {\n return await next(req);\n }\n\n let lastError: unknown;\n let priorAttemptMayHaveCommitted = false;\n for (let i = 0; i < MAX_RETRY_ATTEMPTS; i++) {\n if (i > 0) {\n await waitRetryBackoff(i);\n }\n\n try {\n return await next(req);\n } catch (error) {\n // A retry that comes back AlreadyExists is treated as success: a prior\n // attempt (one whose retriable error sent us here) already created\n // the resource server-side, but its response was lost as\n // Unavailable/ResourceExhausted under load. The identical retry then\n // races against that committed write and fails with `already_exists`.\n // Restricted to RETRY_SAFE_CREATE_METHODS (deploy creates whose response\n // body is unused) and to retries after an attempt that may have committed.\n if (isRetrySafeCreateAlreadyExists(error, req.method.name)) {\n if (priorAttemptMayHaveCommitted) {\n logger.debug(\n `retry: ${req.method.name} returned AlreadyExists on attempt ${i + 1}; ` +\n `treating as success (prior attempt likely committed)`,\n );\n return synthesizeEmptyUnaryResponse(req);\n }\n // No prior attempt of ours could have committed it, so the resource was\n // committed out-of-band (a concurrent or non-idempotent compound create\n // under load — #1350). The top-level handler skips ConnectError, so\n // route it to error tracking here before letting it surface as the\n // deploy error.\n const { reportCrash } = await import(\"#/cli/crashreport/index\");\n await reportCrash(error, \"handledError\");\n }\n const preHandshakeDisconnect = isPreHandshakeDisconnect(error);\n if (\n preHandshakeDisconnect ||\n (!NON_RETRIED_METHODS.has(req.method.name) && isRetirable(error, req.method.idempotency))\n ) {\n lastError = error;\n priorAttemptMayHaveCommitted ||= !preHandshakeDisconnect;\n logger.debug(\n `retry: ${req.method.name} attempt ${i + 1} failed with ` +\n `${retryErrorCodeName(error)}; retrying`,\n );\n continue;\n }\n throw error;\n }\n }\n throw lastError;\n };\n}\n\n/**\n * Create an interceptor that caps the number of concurrent unary RPCs.\n *\n * A fresh-workspace apply fires one `create*` per resource at once; left\n * unbounded, the platform sheds load as `Unavailable`/`ResourceExhausted`,\n * which drives retries into the non-idempotent compound-create `already_exists`\n * race (#1350). One shared limiter per client bounds total in-flight calls\n * across every deploy resource, not just a single call site. Streaming RPCs\n * (e.g. function uploads) are not gated.\n * @internal\n * @returns Concurrency-limiting interceptor\n */\nexport function concurrencyLimitInterceptor(): Interceptor {\n const limit = createApplyLimiter();\n return (next) => async (req) => {\n if (req.stream) {\n return await next(req);\n }\n return await limit(() => next(req));\n };\n}\n\n/**\n * Human-readable name for a retried error, for diagnostics.\n * @param error - Error thrown by a request (a ConnectError or a transport disconnect)\n * @returns The Connect Code name (e.g., \"Unavailable\"), the raw transport error code\n * (e.g., \"ECONNRESET\"), or \"unknown\" if neither applies\n */\nfunction retryErrorCodeName(error: unknown): string {\n if (error instanceof ConnectError) return Code[error.code];\n if (isTransportDisconnectError(error)) return error.code;\n return \"unknown\";\n}\n\n/**\n * Create RPCs for which a post-retry `AlreadyExists` may be treated as success.\n *\n * Membership is deliberately an allowlist, not `startsWith(\"Create\")`: swallowing\n * synthesizes an empty response (see `synthesizeEmptyUnaryResponse`), which is only\n * safe when every caller tolerates an empty response body. These are the deploy/apply\n * resource creations that fire under heavy parallelism and discard their response —\n * except `CreateSecretManagerSecret`, whose caller reads `secret.updateTime` but\n * degrades safely when it is absent (the next deploy re-updates the secret).\n *\n * Intentionally excluded because their callers read the response body — swallowing\n * would hand back an empty message and corrupt downstream state:\n * - `CreateIdPClient` (uses `resp.client.clientSecret` to seed the secret vault)\n * - `CreateWorkflowJobFunction` (uses `response.jobFunction.version`)\n * - `CreateWorkspace` / `CreatePersonalAccessToken` / `CreateDeployment` /\n * `CreateOrganizationFolder` (interactive commands that return created data)\n *\n * `CreateFunctionRegistry` is client-streaming and never reaches this path\n * (streaming requests bypass the retry loop entirely).\n *\n * An allowlist miss is safe: the resource simply loses race protection and an\n * `already_exists` surfaces loudly, as before — never a silent empty response.\n *\n * A drift guard (see client.test.ts) fails CI if any `client.create*` used in the\n * deploy flow is neither listed here nor explicitly classified as response-consuming,\n * so a newly added apply create cannot silently miss this list.\n * @internal\n */\nexport const RETRY_SAFE_CREATE_METHODS: ReadonlySet<string> = new Set([\n \"CreateAIGateway\",\n \"CreateApplication\",\n \"CreateAuthConnection\",\n \"CreateAuthHook\",\n \"CreateAuthIDPConfig\",\n \"CreateAuthMachineUser\",\n \"CreateAuthOAuth2Client\",\n \"CreateAuthSCIMConfig\",\n \"CreateAuthSCIMResource\",\n \"CreateAuthService\",\n \"CreateExecutorExecutor\",\n \"CreateIdPService\",\n \"CreatePipelineResolver\",\n \"CreatePipelineService\",\n \"CreateSecretManagerSecret\",\n \"CreateSecretManagerVault\",\n \"CreateStaticWebsite\",\n \"CreateTailorDBGQLPermission\",\n \"CreateTailorDBService\",\n \"CreateTailorDBType\",\n \"CreateTenantConfig\",\n \"CreateUserProfileConfig\",\n \"CreateWorkflow\",\n \"CreateWorkflowJobFunctionExecutionPolicy\",\n]);\n\n/**\n * Whether an error is an `AlreadyExists` from a retry-safe Create RPC.\n *\n * Only `AlreadyExists` stands in for \"my prior write already landed\"; for other\n * verbs/codes it would be a real conflict that must surface.\n * @param error - Error thrown by the request\n * @param methodName - RPC method name (e.g., \"CreateTailorDBType\")\n * @returns True if the error is an `AlreadyExists` from a retry-safe Create method\n */\nfunction isRetrySafeCreateAlreadyExists(error: unknown, methodName: string): boolean {\n return (\n error instanceof ConnectError &&\n error.code === Code.AlreadyExists &&\n RETRY_SAFE_CREATE_METHODS.has(methodName)\n );\n}\n\n/**\n * Build a default (empty) unary response for the request's output message.\n *\n * Used when a retried Create is determined to have already succeeded on a prior\n * attempt: callers in the deploy pipeline ignore Create response bodies, so an\n * empty message faithfully represents the already-applied state.\n * @param req - Unary request whose output schema is used\n * @returns A synthesized unary response with an empty output message\n */\nfunction synthesizeEmptyUnaryResponse(req: {\n service: UnaryResponse[\"service\"];\n method: UnaryResponse[\"method\"];\n}): UnaryResponse {\n return {\n stream: false,\n service: req.service,\n method: req.method,\n header: new Headers(),\n message: create(req.method.output),\n trailer: new Headers(),\n };\n}\n\n/**\n * Base delay (ms) for the first retry. Subsequent attempts double it.\n *\n * Kept relatively large so a retry does not immediately race an original request\n * that is still settling server-side under load (e.g. a compound create whose\n * response was lost), which is what triggers the `already_exists` race.\n */\nconst RETRY_BASE_DELAY_MS = 500;\n\n/** Maximum number of attempts, including the initial one, for a retried request. */\nconst MAX_RETRY_ATTEMPTS = 3;\n\n/** Methods without an idempotency key, which a retry could apply twice. */\nconst NON_RETRIED_METHODS: ReadonlySet<string> = new Set([\n \"CloneApplicationData\",\n \"CreateWorkspace\",\n \"StartWorkflow\",\n]);\n\n/**\n * Wait for an exponential backoff delay with jitter.\n * @param attempt - Current retry attempt number (1-based)\n * @returns Promise that resolves after the delay\n */\nfunction waitRetryBackoff(attempt: number) {\n const base = RETRY_BASE_DELAY_MS * 2 ** (attempt - 1);\n const jitter = 0.1 * (Math.random() * 2 - 1);\n const backoff = base * (1 + jitter);\n return new Promise((resolve) => setTimeout(resolve, backoff));\n}\n\n// Node/undici error codes for a connection torn down mid-request. Whether the\n// request reached the server is unknown, same ambiguity as Code.Aborted/Internal,\n// so retry is scoped the same way (idempotent/no-side-effect methods only).\nconst TRANSPORT_DISCONNECT_ERROR_CODES: ReadonlySet<string> = new Set([\n \"ERR_STREAM_PREMATURE_CLOSE\",\n \"ECONNRESET\",\n \"ETIMEDOUT\",\n \"EPIPE\",\n]);\n\n/**\n * Whether an error is a raw Node/undici transport disconnect (not a `ConnectError`).\n * @param error - Error thrown by the request\n * @returns True if `error.code` is a known transport disconnect code\n */\nfunction isTransportDisconnectError(error: unknown): error is Error & { code: string } {\n return (\n error instanceof Error &&\n \"code\" in error &&\n typeof error.code === \"string\" &&\n TRANSPORT_DISCONNECT_ERROR_CODES.has(error.code)\n );\n}\n\n/**\n * Whether the connection closed before the TLS handshake completed, so no request\n * reached the server.\n * @param error - Error thrown by the request\n * @returns True if the error wraps Node's pre-handshake `ECONNRESET`\n */\nfunction isPreHandshakeDisconnect(error: unknown): boolean {\n if (!(error instanceof ConnectError)) return false;\n const { cause } = error;\n return (\n isTransportDisconnectError(cause) &&\n cause.code === \"ECONNRESET\" &&\n cause.message ===\n \"Client network socket disconnected before secure TLS connection was established\"\n );\n}\n\n/**\n * Determine whether the given error is retriable for the method idempotency.\n * @param error - Error thrown by the request\n * @param idempotency - Method idempotency level\n * @returns True if the error should be retried\n */\nfunction isRetirable(error: unknown, idempotency: MethodOptions_IdempotencyLevel) {\n const isIdempotentOrSideEffectFree =\n idempotency === MethodOptions_IdempotencyLevel.NO_SIDE_EFFECTS ||\n idempotency === MethodOptions_IdempotencyLevel.IDEMPOTENT;\n\n if (!(error instanceof ConnectError)) {\n return isTransportDisconnectError(error) && isIdempotentOrSideEffectFree;\n }\n\n switch (error.code) {\n case Code.ResourceExhausted:\n case Code.Unavailable:\n return true;\n case Code.Aborted:\n case Code.Internal:\n return isIdempotentOrSideEffectFree;\n default:\n return false;\n }\n}\n\n/**\n * Create an interceptor that enhances error messages from the Operator API.\n * @internal\n * @returns Error handling interceptor\n */\nexport function errorHandlingInterceptor(): Interceptor {\n return (next) => async (req) => {\n try {\n return await next(req);\n } catch (error) {\n if (error instanceof ConnectError) {\n const { operation, resourceType } = parseMethodName(req.method.name);\n const identifiers = requestIdentifiers(req.message, req.method.name);\n const parts = Object.entries(identifiers).map(([key, value]) => `${key}: ${value}`);\n const identity = parts.length === 0 ? \"\" : ` (${parts.join(\", \")})`;\n\n // Re-throw as ConnectError with enhanced message to avoid re-wrapping\n // Use rawMessage to avoid duplicating the error code prefix\n throw withErrorDiagnostics(\n Object.assign(\n new ConnectError(\n `Failed to ${operation} ${resourceType}${identity}: ${error.rawMessage}`,\n error.code,\n error.metadata,\n undefined,\n error.cause,\n ),\n { details: error.details },\n ),\n { context: { method: req.method.name, identifiers } },\n );\n }\n if (isTransportDisconnectError(error)) {\n throw withErrorDiagnostics(error, {\n code: \"TRANSPORT_DISCONNECTED\",\n suggestion:\n \"Check network connectivity and platform availability. A write may already have completed; inspect the current resource state before retrying.\",\n context: {\n method: req.method.name,\n transportCode: error.code,\n identifiers: requestIdentifiers(req.message, req.method.name),\n },\n });\n }\n throw error;\n }\n };\n}\n\n/**\n * @internal\n * @param methodName - RPC method name (e.g., \"CreateWorkspace\")\n * @returns Parsed operation and resource type\n */\nexport function parseMethodName(methodName: string): {\n operation: string;\n resourceType: string;\n} {\n const match = methodName.match(/^(Create|Update|Delete|Set|List|Get)(.+)$/);\n if (!match) {\n return { operation: \"perform\", resourceType: \"resource\" };\n }\n\n const [, action, resource] = match as [string, string, string];\n return { operation: action.toLowerCase(), resourceType: resource };\n}\n\n// Identifier fields surfaced in enhanced error messages. Never add fields\n// that can carry secrets or PII (tokens, scripts, query args, secret values,\n// emails), and never add a suffix that could match them (e.g. \"Key\" would\n// match future key material).\n//\n// Platform-wide naming conventions: on every API, a top-level string field\n// with one of these names or suffixes is a resource identifier.\nconst IDENTITY_KEYS = new Set([\"name\", \"id\"]);\nconst IDENTITY_KEY_SUFFIXES = [\"Name\", \"Id\", \"Namespace\"];\n// Key read from nested resource messages (e.g. the type in a create request).\n// Only materialized protobuf messages (marked by $typeName) qualify: map and\n// Struct fields materialize without one, and their entries can carry values\n// the SDK does not control (e.g. metadata labels merged from the remote).\nconst NESTED_IDENTITY_KEY = \"name\";\n// API-specific identifier fields, scoped to the RPC methods that define them\n// so a same-named field on an unrelated API is never surfaced by accident.\nconst METHOD_IDENTITY_KEYS: Readonly<Record<string, readonly string[]>> = {\n GetMetadata: [\"trn\"],\n SetMetadata: [\"trn\"],\n AddCustomDomain: [\"domain\"],\n GetCustomDomain: [\"domain\"],\n RemoveCustomDomain: [\"domain\"],\n RequestCustomDomainTransfer: [\"domain\"],\n CancelCustomDomainTransfer: [\"domain\"],\n AcceptCustomDomainTransfer: [\"domain\"],\n GetCustomDomainTransfer: [\"domain\"],\n CreateWorkflowJobFunctionExecutionPolicy: [\"executionPolicyKey\"],\n UpdateWorkflowJobFunctionExecutionPolicy: [\"executionPolicyKey\"],\n GetWorkflowJobFunctionExecutionPolicyByKey: [\"executionPolicyKey\"],\n};\n\nfunction isIdentityKey(key: string, methodName: string): boolean {\n if (key.startsWith(\"$\")) {\n return false;\n }\n return (\n IDENTITY_KEYS.has(key) ||\n IDENTITY_KEY_SUFFIXES.some((suffix) => key.endsWith(suffix)) ||\n (METHOD_IDENTITY_KEYS[methodName]?.includes(key) ?? false)\n );\n}\n\n/**\n * Extract allowlisted resource identifiers for error diagnostics.\n *\n * Only resource identifiers are included — the rest of the request payload\n * can carry credentials and must never reach terminal or CI logs.\n * @param message - Request message to extract identifiers from\n * @param methodName - RPC method name used to resolve method-scoped identifiers\n * @returns Resource identifiers keyed by request field\n */\nfunction requestIdentifiers(message: unknown, methodName: string): Record<string, string> {\n if (typeof message !== \"object\" || message === null) {\n return {};\n }\n const identifiers: Record<string, string> = {};\n for (const [key, value] of Object.entries(message)) {\n if (typeof value === \"string\" && value !== \"\" && isIdentityKey(key, methodName)) {\n identifiers[key] = value;\n } else if (\n !key.startsWith(\"$\") &&\n value !== null &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n typeof (value as Record<string, unknown>).$typeName === \"string\"\n ) {\n const nestedName = (value as Record<string, unknown>)[NESTED_IDENTITY_KEY];\n if (typeof nestedName === \"string\" && nestedName !== \"\") {\n identifiers[`${key}.${NESTED_IDENTITY_KEY}`] = nestedName;\n }\n }\n }\n return identifiers;\n}\n\nexport const MAX_PAGE_SIZE = 1000;\n\n/**\n * Fetch all paginated resources by repeatedly calling the given function.\n * @template T\n * @param fn - Page fetcher returning items and next page token\n * @returns All fetched items\n */\nexport async function fetchAll<T>(\n fn: (pageToken: string, maxPageSize: number) => Promise<[T[], string]>,\n) {\n const items: T[] = [];\n let pageToken = \"\";\n\n // loop exits when the platform stops returning a page token\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n while (true) {\n const [batch, nextPageToken] = await fn(pageToken, MAX_PAGE_SIZE);\n items.push(...batch);\n // loop exits when the platform stops returning a page token\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n if (!nextPageToken) break;\n pageToken = nextPageToken;\n }\n return items;\n}\n\n/**\n * @internal\n * @param error - Error value to inspect\n * @returns Whether the error is a Connect NotFound error\n */\nexport function isNotFoundError(error: unknown): boolean {\n return error instanceof ConnectError && error.code === Code.NotFound;\n}\n\n/**\n * Fetch all paginated resources, treating an absent resource group as empty.\n * @template T\n * @param fn - Page fetcher returning items and next page token\n * @returns Items fetched before pagination completes or the fetcher raises NotFound\n */\nexport async function fetchAllTolerant<T>(\n fn: (pageToken: string, maxPageSize: number) => Promise<[T[], string]>,\n): Promise<T[]> {\n return await fetchAll(async (pageToken, maxPageSize) => {\n try {\n return await fn(pageToken, maxPageSize);\n } catch (error) {\n if (isNotFoundError(error)) {\n return [[], \"\"];\n }\n throw error;\n }\n });\n}\n\n/**\n * Fetch a single resource, treating NotFound as an absent value.\n * @template T\n * @param fn - Resource getter\n * @returns Fetched resource, or undefined when the getter raises NotFound\n */\nexport async function getOrNull<T>(fn: () => Promise<T>): Promise<T | undefined> {\n try {\n return await fn();\n } catch (error) {\n if (isNotFoundError(error)) {\n return undefined;\n }\n throw error;\n }\n}\n\ninterface FetchPagedOptions {\n /** Maximum number of items to return. 0 or undefined means unlimited. */\n limit?: number;\n}\n\n/**\n * Fetch paginated resources with an optional upper bound on the number of\n * items returned. When `limit` is 0 or undefined the function behaves\n * like `fetchAll` and returns every page. When `limit` is positive the\n * function stops once enough items are collected, requesting smaller\n * pages as it approaches the boundary.\n * @template T\n * @param fn - Page fetcher returning items and next page token\n * @param options - Pagination options\n * @returns Fetched items (length <= limit when limit > 0)\n */\nexport async function fetchPaged<T>(\n fn: (pageToken: string, pageSize: number) => Promise<[T[], string]>,\n options?: FetchPagedOptions,\n): Promise<T[]> {\n const limit = options?.limit;\n const unbounded = limit === undefined || limit === 0;\n const items: T[] = [];\n let pageToken = \"\";\n\n // loop exits when the platform stops returning a page token\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n while (true) {\n const pageSize = unbounded ? MAX_PAGE_SIZE : Math.min(limit - items.length, MAX_PAGE_SIZE);\n if (!unbounded && pageSize <= 0) break;\n\n const [batch, nextPageToken] = await fn(pageToken, pageSize);\n items.push(...batch);\n if (!unbounded && items.length >= limit) break;\n // loop exits when the platform stops returning a page token\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n if (!nextPageToken) break;\n pageToken = nextPageToken;\n }\n\n if (!unbounded && items.length > limit) {\n return items.slice(0, limit);\n }\n return items;\n}\n\n/**\n * Fetch user info from the Tailor Platform userinfo endpoint.\n * @param accessToken - Access token for the current user\n * @param config - Optional platform connection settings\n * @returns Parsed user info\n */\nexport async function fetchUserInfo(accessToken: string, config?: PlatformClientConfig) {\n const userInfoUrl = new URL(\"/auth/platform/userinfo\", getPlatformBaseUrl(config)).href;\n const resp = await fetch(userInfoUrl, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"User-Agent\": await userAgent(),\n },\n signal: AbortSignal.timeout(OAUTH2_REQUEST_TIMEOUT_MS),\n });\n if (!resp.ok) {\n throw new Error(`Failed to fetch user info: ${resp.statusText}`);\n }\n\n const rawJson: unknown = await resp.json();\n // strip unknown keys\n const schema = z.object({\n sub: z.string(),\n email: z.string(),\n });\n const result = schema.safeParse(rawJson);\n if (!result.success) {\n throw invalidDataError(\"user info response\", result.error);\n }\n return result.data;\n}\n\n// Converting \"name:url\" patterns to actual Static Website URLs\n/**\n * Options for `resolveStaticWebsiteUrls`.\n */\nexport type ResolveStaticWebsiteUrlsOptions = {\n /**\n * Names of static websites that are defined locally in the current\n * configuration. When the platform-side lookup for a name in this set\n * fails specifically with a `NotFound` error, the warning is suppressed\n * and the original `name:url[/path]` pattern is returned unresolved\n * instead of being dropped.\n *\n * Use this from plan-phase callers to avoid noisy warnings on the first\n * deployment, where the static website will be created later in the same\n * apply run. Other failure modes (\"URL not yet assigned\", transient RPC\n * errors, permission errors) are unaffected by this option: they still log\n * a warning, and separately, `failOnUnexpectedError` decides whether they\n * abort instead.\n */\n expectedLocalNames?: ReadonlySet<string>;\n /**\n * When true, an entry that cannot be resolved keeps its original\n * `name:url[/path]` pattern instead of being dropped, and the warning says\n * so. Callers whose target is a fixed-shape value (an env var, for example)\n * rather than a list use this, because silently dropping the value would\n * change the shape of what user code receives.\n */\n keepUnresolved?: boolean;\n /**\n * When true, a lookup failure other than `NotFound` (a permission error, a\n * transient RPC failure, ...) is re-thrown instead of being downgraded to a\n * warning. A site that exists but has no URL assigned yet is treated the\n * same way, unless its name is in `expectedLocalNames` -- there, a rebuild\n * is expected to resolve it, so it is kept unresolved with a warning\n * instead. Callers where the fallback value ends up embedded in deployed\n * code use this, since shipping it silently is worse than failing the\n * deploy. A `NotFound` for a name in `expectedLocalNames` is unaffected.\n */\n failOnUnexpectedError?: boolean;\n /**\n * Shared `getStaticWebsite` lookups, keyed by site name. Pass the same map\n * across multiple calls that may reference the same site (for example, one\n * call per `env` key) so only the first caller for a given name issues the\n * platform lookup; the rest reuse its result.\n */\n siteLookupCache?: Map<string, ReturnType<OperatorClient[\"getStaticWebsite\"]>>;\n};\n\n/** `name:url[/path]` static website placeholder, anchored at the end. */\nconst STATIC_WEBSITE_URL_PATTERN = /:url(\\/.*)?$/;\n\n/**\n * Check whether a value is a `name:url[/path]` static website placeholder.\n * @param value - Value to test; non-strings are never placeholders\n * @returns True when the value still needs static website resolution\n */\nexport function hasStaticWebsiteUrlPlaceholder(value: unknown): value is string {\n return typeof value === \"string\" && STATIC_WEBSITE_URL_PATTERN.test(value);\n}\n\n/**\n * Extract the static website name from a `name:url[/path]` placeholder.\n * @param value - A value already confirmed via {@link hasStaticWebsiteUrlPlaceholder}\n * @returns The site name, or the whole value if it does not actually match (defensive fallback)\n */\nexport function staticWebsiteNameFromPlaceholder(value: string): string {\n const match = value.match(STATIC_WEBSITE_URL_PATTERN);\n return match?.index !== undefined ? value.substring(0, match.index) : value;\n}\n\n/**\n * Resolve \"name:url\" patterns to actual Static Website URLs.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param urls - URLs or name:url patterns\n * @param context - Logging context (e.g., \"CORS\", \"OAuth2 redirect URIs\")\n * @param options - Optional behavior overrides\n * @returns Resolved URLs (or the original pattern for entries marked as\n * expected-but-not-yet-deployed via `options.expectedLocalNames`)\n */\nexport async function resolveStaticWebsiteUrls(\n client: OperatorClient,\n workspaceId: string,\n urls: string[] | undefined,\n context: string, // for logging context (e.g., \"CORS\", \"OAuth2 redirect URIs\")\n options: ResolveStaticWebsiteUrlsOptions = {},\n): Promise<string[]> {\n if (!urls) {\n return [];\n }\n\n const { expectedLocalNames, keepUnresolved = false, failOnUnexpectedError = false } = options;\n const unresolved = (url: string) => (keepUnresolved ? [url] : []);\n const fallbackNote = keepUnresolved\n ? `Leaving the ${context} value unresolved.`\n : `Excluding from ${context}.`;\n const siteLookupCache: NonNullable<ResolveStaticWebsiteUrlsOptions[\"siteLookupCache\"]> =\n options.siteLookupCache ?? new Map<string, ReturnType<OperatorClient[\"getStaticWebsite\"]>>();\n const lookupSite = (siteName: string) => {\n let lookup = siteLookupCache.get(siteName);\n if (!lookup) {\n lookup = client.getStaticWebsite({ workspaceId, name: siteName });\n siteLookupCache.set(siteName, lookup);\n }\n return lookup;\n };\n\n const results = await Promise.all(\n urls.map(async (url) => {\n const match = url.match(STATIC_WEBSITE_URL_PATTERN);\n\n if (match && match.index !== undefined) {\n const siteName = url.substring(0, match.index);\n const pathSuffix = match[1] || \"\";\n\n try {\n const response = await lookupSite(siteName);\n\n if (response.staticwebsite?.url) {\n return [response.staticwebsite.url + pathSuffix];\n }\n // A site outside `expectedLocalNames` has no pending rebuild that\n // will ever re-check it, so this deploy is the only chance to catch\n // a missing URL -- keeping it unresolved here would ship the\n // literal placeholder with nothing left to fail on.\n if (!expectedLocalNames?.has(siteName) && failOnUnexpectedError) {\n throw CLIError({\n code: \"STATIC_WEBSITE_URL_NOT_ASSIGNED\",\n message: `Static website \"${siteName}\" exists but has no URL assigned yet.`,\n suggestion: \"Re-run the deploy once the static website's URL is available.\",\n });\n }\n logger.warn(`Static website \"${siteName}\" has no URL assigned yet. ${fallbackNote}`);\n return unresolved(url);\n } catch (error) {\n if (isNotFoundError(error)) {\n if (expectedLocalNames?.has(siteName)) {\n return [url];\n }\n } else if (failOnUnexpectedError) {\n throw error;\n }\n logger.warn(\n `Static website \"${siteName}\" not found for ${context} configuration. ${fallbackNote}`,\n );\n return unresolved(url);\n }\n }\n return [url];\n }),\n );\n\n return results.flat();\n}\n\n/** Application `env` as declared by `defineConfig({ env })`. */\nexport type ApplicationEnv = Readonly<Record<string, string | number | boolean>>;\n\n/**\n * Resolve `name:url` patterns held by an application's `env` values.\n *\n * `env` reaches user code verbatim -- it is embedded in the executor args and\n * resolver operationHook expressions -- so an unresolved placeholder is\n * delivered as the literal string `\"my-site:url\"`. Each placeholder value goes\n * through `resolveStaticWebsiteUrls`, which keeps the same first-deployment\n * semantics as `cors` and OAuth2 redirect URIs for a website this deploy run\n * is about to create (left as-is, with a warning naming the site and noting\n * this deploy will rebuild to inject the real URL once it exists), but --\n * unlike `cors` -- fails the deploy on any other lookup failure instead of\n * shipping the unresolved placeholder into deployed code.\n *\n * Values that are not placeholders -- and the record itself when it holds no\n * placeholder at all -- are returned untouched, so the common case costs no\n * platform round trip.\n * @param client - Operator client instance\n * @param workspaceId - Workspace ID\n * @param env - Application env record\n * @param options - Optional behavior overrides\n * @returns An env record with resolvable placeholders replaced by URLs\n */\nexport async function resolveStaticWebsiteUrlsInEnv(\n client: OperatorClient,\n workspaceId: string,\n env: ApplicationEnv | undefined,\n options: Omit<ResolveStaticWebsiteUrlsOptions, \"keepUnresolved\" | \"failOnUnexpectedError\"> = {},\n): Promise<ApplicationEnv> {\n if (!env || !Object.values(env).some(hasStaticWebsiteUrlPlaceholder)) {\n return env ?? {};\n }\n\n // Shared across every key below, so two keys referencing the same site\n // (e.g. `siteUrl` and `callbackUrl`) issue one getStaticWebsite call, not\n // one per key.\n const siteLookupCache: NonNullable<ResolveStaticWebsiteUrlsOptions[\"siteLookupCache\"]> =\n new Map();\n\n const entries = await Promise.all(\n Object.entries(env).map(async ([key, value]) => {\n if (!hasStaticWebsiteUrlPlaceholder(value)) {\n return [key, value] as const;\n }\n const [resolved] = await resolveStaticWebsiteUrls(\n client,\n workspaceId,\n [value],\n `env \"${key}\"`,\n { ...options, keepUnresolved: true, failOnUnexpectedError: true, siteLookupCache },\n );\n return [key, resolved ?? value] as const;\n }),\n );\n\n const resolved: ApplicationEnv = Object.fromEntries<string | number | boolean>(entries);\n warnUnresolvedEnvPlaceholders(resolved, options.expectedLocalNames);\n return resolved;\n}\n\n/**\n * Warn about env values that are still `name:url` placeholders after\n * resolution, so a gap surfaces at deploy time instead of as a malformed URL\n * inside a running function.\n * @param env - Env record after resolution\n * @param expectedLocalNames - Static websites this deploy run creates later\n */\nfunction warnUnresolvedEnvPlaceholders(\n env: ApplicationEnv,\n expectedLocalNames: ReadonlySet<string> | undefined,\n): void {\n for (const [key, value] of Object.entries(env)) {\n if (!hasStaticWebsiteUrlPlaceholder(value)) continue;\n const siteName = value.slice(0, value.search(STATIC_WEBSITE_URL_PATTERN));\n if (expectedLocalNames?.has(siteName)) {\n logger.warn(\n `env \"${key}\" keeps the unresolved value \"${value}\" for now because static website \"${siteName}\" ` +\n `isn't available yet; this deploy rebuilds automatically once it is, to inject the real URL.`,\n );\n continue;\n }\n logger.warn(\n `env \"${key}\" keeps the unresolved value \"${value}\". ` +\n `The literal pattern is passed to your code at runtime.`,\n );\n }\n}\n\n/**\n * Fetch an OAuth2 access token for a machine user.\n * @param url - OAuth2 server base URL\n * @param clientId - Client ID for the machine user\n * @param clientSecret - Client secret for the machine user\n * @returns Access token\n */\nexport async function fetchMachineUserToken(url: string, clientId: string, clientSecret: string) {\n logger.registerSecret(clientSecret);\n const tokenEndpoint = new URL(\"/oauth2/token\", url).href;\n const formData = new URLSearchParams();\n formData.append(\"grant_type\", \"client_credentials\");\n formData.append(\"client_id\", clientId);\n formData.append(\"client_secret\", clientSecret);\n\n const request = {\n method: \"POST\",\n headers: {\n \"User-Agent\": await userAgent(),\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: formData,\n };\n const resp = await withConnectTimeoutRetry(\"machine user token request\", () =>\n fetch(tokenEndpoint, request),\n );\n if (!resp.ok) {\n const body = await resp.text().catch(() => \"\");\n throw new Error(\n `Failed to fetch machine user token: ${resp.status} ${resp.statusText} ${body.slice(0, 500)}`,\n );\n }\n const rawJson: unknown = await resp.json();\n\n // strip unknown keys\n const schema = z.object({\n token_type: z.string(),\n access_token: z.string(),\n expires_in: z.number(),\n });\n const result = schema.safeParse(rawJson);\n if (!result.success) {\n throw invalidDataError(\"machine user token response\", result.error);\n }\n logger.registerSecret(result.data.access_token);\n return result.data;\n}\n\nfunction isUndiciConnectTimeout(error: unknown): boolean {\n if (!(error instanceof TypeError)) {\n return false;\n }\n const cause = error.cause;\n return cause instanceof Error && \"code\" in cause && cause.code === \"UND_ERR_CONNECT_TIMEOUT\";\n}\n\n/**\n * Retry a request that failed before the connection was established.\n *\n * Only `UND_ERR_CONNECT_TIMEOUT` is retried: the request provably never reached\n * the server, so replaying it cannot duplicate a server-side effect.\n * @param label - Request description for the retry debug log\n * @param send - Sends the request; called once per attempt\n * @returns The first successful result\n */\nasync function withConnectTimeoutRetry<T>(label: string, send: () => Promise<T>): Promise<T> {\n for (let attempt = 1; ; attempt++) {\n try {\n return await send();\n } catch (error) {\n if (!isUndiciConnectTimeout(error) || attempt >= MAX_RETRY_ATTEMPTS) {\n throw error;\n }\n logger.debug(\n `retry: ${label} attempt ${attempt} failed with UND_ERR_CONNECT_TIMEOUT; retrying`,\n );\n await waitRetryBackoff(attempt);\n }\n }\n}\n\n/**\n * Fetch an OAuth2 token for a platform machine user via client_credentials grant.\n * @param clientId - Client ID for the platform machine user\n * @param clientSecret - Client secret for the platform machine user\n * @param config - Optional platform connection settings\n * @returns OAuth2 token\n */\nexport async function fetchPlatformMachineUserToken(\n clientId: string,\n clientSecret: string,\n config?: PlatformClientConfig,\n) {\n logger.registerSecret(clientSecret);\n const server = getPlatformBaseUrl(config);\n // A new client per attempt: OAuth2Client caches its discovery promise even when\n // it rejects, so a reused client would replay the failure without re-requesting.\n const token = await withConnectTimeoutRetry(\"platform machine user token request\", () =>\n new OAuth2Client({\n clientId,\n clientSecret,\n server,\n discoveryEndpoint: oauth2DiscoveryEndpoint,\n }).clientCredentials(),\n );\n logger.registerSecret(token.accessToken);\n if (token.refreshToken) logger.registerSecret(token.refreshToken);\n return token;\n}\n\n/**\n * Close the global HTTP connection pool to prevent libuv UV_HANDLE_CLOSING\n * assertion failure on Windows at process exit (Node.js 23.x+).\n * See: https://github.com/nodejs/node/issues/56645\n *\n * The pool is reached through the global dispatcher symbol rather than the `undici`\n * package: importing that package installs its own Agent over these same globals,\n * replacing the HTTP stack Node's `fetch` already uses. The symbol is versioned per\n * Dispatcher API generation, and the newest one wins because older symbols hold a\n * wrapper around that same pool — closing both would destroy it twice.\n */\nexport async function closeConnectionPool() {\n const globals = globalThis as Record<symbol, { close?: () => Promise<void> } | undefined>;\n const dispatcher =\n globals[Symbol.for(\"undici.globalDispatcher.2\")] ??\n globals[Symbol.for(\"undici.globalDispatcher.1\")];\n if (typeof dispatcher?.close === \"function\") {\n await dispatcher.close();\n }\n}\n"],"mappings":"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"}
|