@tailor-platform/sdk 1.82.0 → 1.83.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/application-CP7JKG9R.mjs +3 -0
  3. package/dist/{application-CVeA53ok.mjs → application-Cp0FxIm2.mjs} +3 -3
  4. package/dist/application-Cp0FxIm2.mjs.map +1 -0
  5. package/dist/cli/index.mjs +3 -3
  6. package/dist/cli/lib.mjs +2 -2
  7. package/dist/completion/zsh-worker.zsh +1 -1
  8. package/dist/configure/index.mjs +3 -3
  9. package/dist/configure/index.mjs.map +1 -1
  10. package/dist/configure/services/workflow/execution-policy.d.mts +2 -2
  11. package/dist/{globals-DUqEetIh.mjs → globals-DraXTdqg.mjs} +6 -5
  12. package/dist/globals-DraXTdqg.mjs.map +1 -0
  13. package/dist/{register-typescript-runtime-O7zQNif0.mjs → register-typescript-runtime-CCHyKeXO.mjs} +125 -11
  14. package/dist/register-typescript-runtime-CCHyKeXO.mjs.map +1 -0
  15. package/dist/{registry-CXi7rJq7.mjs → registry-Ct0Wgxp1.mjs} +3 -3
  16. package/dist/registry-Ct0Wgxp1.mjs.map +1 -0
  17. package/dist/runtime/index.mjs +1 -1
  18. package/dist/runtime/workflow.d.mts +39 -21
  19. package/dist/runtime/workflow.mjs +2 -2
  20. package/dist/utils/test/index.mjs +18 -12
  21. package/dist/utils/test/index.mjs.map +1 -1
  22. package/dist/utils/test/mock.d.mts +2 -2
  23. package/dist/vitest/environment.mjs +1 -1
  24. package/dist/vitest/index.mjs +30 -24
  25. package/dist/vitest/index.mjs.map +1 -1
  26. package/dist/vitest/mocks/file.d.mts +1 -1
  27. package/dist/vitest/mocks/workflow.d.mts +20 -15
  28. package/dist/vitest/setup.mjs +1 -1
  29. package/dist/{workflow-CkIDJpdg.mjs → workflow-B2mwc7aT.mjs} +17 -9
  30. package/dist/workflow-B2mwc7aT.mjs.map +1 -0
  31. package/docs/runtime.md +1 -1
  32. package/docs/services/tailordb-migration.md +5 -3
  33. package/docs/services/workflow.md +2 -2
  34. package/docs/testing.md +1 -1
  35. package/package.json +2 -2
  36. package/dist/application-CP0W2sQo.mjs +0 -3
  37. package/dist/application-CVeA53ok.mjs.map +0 -1
  38. package/dist/globals-DUqEetIh.mjs.map +0 -1
  39. package/dist/register-typescript-runtime-O7zQNif0.mjs.map +0 -1
  40. package/dist/registry-CXi7rJq7.mjs.map +0 -1
  41. package/dist/workflow-CkIDJpdg.mjs.map +0 -1
@@ -58,10 +58,10 @@ declare function defineWorkflowExecutionPolicy<const N extends string, const D e
58
58
  * }));
59
59
  *
60
60
  * // In a workflow job function:
61
- * await tailor.workflow.startJobFunction("worker", args, {
61
+ * await tailor.workflow.execJobFunction("worker", args, {
62
62
  * executionPolicyKey: executionPolicies.premium.key,
63
63
  * });
64
- * await tailor.workflow.startJobFunction("worker", args, {
64
+ * await tailor.workflow.execJobFunction("worker", args, {
65
65
  * executionPolicyKey: executionPolicies["tenant-api"].keyFor(input.tenantId),
66
66
  * });
67
67
  */
@@ -1,13 +1,14 @@
1
- import { c as runRegisteredJob, l as runRegisteredWorkflow } from "./registry-CXi7rJq7.mjs";
1
+ import { c as runRegisteredJob, l as runRegisteredWorkflow } from "./registry-Ct0Wgxp1.mjs";
2
2
 
3
3
  //#region src/vitest/workflow-runtime.ts
4
4
  function createDefaultWorkflowRuntime() {
5
- const startJobFunction = (name, args) => runRegisteredJob(name, args);
5
+ const execJobFunction = (name, args) => runRegisteredJob(name, args);
6
6
  const startWorkflow = (name, args) => runRegisteredWorkflow(name, args);
7
7
  const resumeWorkflowExecution = async (executionId) => executionId;
8
8
  return {
9
- startJobFunction,
10
- triggerJobFunction: startJobFunction,
9
+ execJobFunction,
10
+ startJobFunction: execJobFunction,
11
+ triggerJobFunction: execJobFunction,
11
12
  startWorkflow,
12
13
  triggerWorkflow: startWorkflow,
13
14
  resumeWorkflowExecution,
@@ -128,4 +129,4 @@ function cleanupPlatformGlobals(global) {
128
129
 
129
130
  //#endregion
130
131
  export { cleanupPlatformGlobals as n, installPlatformGlobals as r, RUNTIME_FLAG_KEY as t };
131
- //# sourceMappingURL=globals-DUqEetIh.mjs.map
132
+ //# sourceMappingURL=globals-DraXTdqg.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"globals-DraXTdqg.mjs","names":[],"sources":["../src/vitest/workflow-runtime.ts","../src/vitest/globals.ts"],"sourcesContent":["// Default `tailor.workflow` runner installed by the `tailor-runtime` environment.\n// Must stay free of `vitest` (`vi`): it loads via `./globals` in the environment\n// realm where `vi` is unavailable, hence relative imports only (no `@/` alias).\nimport { runRegisteredJob, runRegisteredWorkflow } from \"../configure/services/workflow/registry\";\nimport type { ExecJobFunctionOptions, StartWorkflowOptions } from \"../runtime/workflow\";\n\nexport interface DefaultWorkflowRuntime {\n execJobFunction: (name: string, args?: unknown, options?: ExecJobFunctionOptions) => unknown;\n startJobFunction: (name: string, args?: unknown, options?: ExecJobFunctionOptions) => unknown;\n triggerJobFunction: (name: string, args?: unknown, options?: ExecJobFunctionOptions) => unknown;\n startWorkflow: (name: string, args?: unknown, options?: StartWorkflowOptions) => Promise<string>;\n triggerWorkflow: (\n name: string,\n args?: unknown,\n options?: StartWorkflowOptions,\n ) => Promise<string>;\n resumeWorkflowExecution: (executionId: string) => Promise<string>;\n resumeWorkflow: (executionId: string) => Promise<string>;\n wait: (key: string, payload?: unknown) => unknown;\n resolve: (\n executionId: string,\n key: string,\n callback: (payload: unknown) => unknown,\n ) => Promise<void>;\n}\n\nexport function createDefaultWorkflowRuntime(): DefaultWorkflowRuntime {\n const execJobFunction: DefaultWorkflowRuntime[\"execJobFunction\"] = (name, args) =>\n runRegisteredJob(name, args);\n const startWorkflow: DefaultWorkflowRuntime[\"startWorkflow\"] = (name, args) =>\n runRegisteredWorkflow(name, args);\n const resumeWorkflowExecution: DefaultWorkflowRuntime[\"resumeWorkflowExecution\"] = async (\n executionId,\n ) => executionId;\n return {\n execJobFunction,\n startJobFunction: execJobFunction,\n triggerJobFunction: execJobFunction,\n startWorkflow,\n triggerWorkflow: startWorkflow,\n resumeWorkflowExecution,\n resumeWorkflow: resumeWorkflowExecution,\n wait: (key: string): unknown => {\n throw new Error(\n `No wait handler for \"${key}\". Acquire mockWorkflow() and call setWaitHandler(...).`,\n );\n },\n resolve: async (): Promise<void> => {\n throw new Error(\n \"No resolve handler. Acquire mockWorkflow() and call setResolveHandler(...).\",\n );\n },\n };\n}\n","/**\n * Base platform globals for the tailor-runtime test environment.\n *\n * This module is intentionally free of any `vitest` (`vi`) dependency so it can\n * be imported from the Vitest *environment* module (which runs in a realm where\n * `vi` is not available). It installs only the always-present structural pieces:\n *\n * - `globalThis.tailor` / `globalThis.tailordb` container objects\n * - `globalThis.tailor.context.getInvoker` default stub\n * - the platform error classes (`TailorErrors`, `TailorErrorMessage`,\n * `TailorDBFileError`)\n * - the `__tailorRuntimeActive` sentinel flag\n *\n * The per-namespace mock behavior (TailorDB client, workflow, secretmanager, …)\n * is installed on demand by the `xMock()` factories in `./mock`, which run in\n * test context where `vi` *is* available.\n */\n\nimport { createDefaultWorkflowRuntime } from \"./workflow-runtime\";\nimport type { ContextInvoker } from \"../runtime/context\";\nimport type { TailorDBFileErrorCode } from \"../runtime/file\";\n\n// Sentinel set when the tailor-runtime environment is active. setup.ts reads it\n// to decide whether to run its blocked-globals lifecycle and config-secret\n// loading.\nexport const RUNTIME_FLAG_KEY = \"__tailorRuntimeActive\";\n\n// ---------------------------------------------------------------------------\n// Error class mocks\n// ---------------------------------------------------------------------------\n\ninterface TailorErrorItem {\n message: string;\n path: (string | number)[];\n}\n\nclass TailorErrorsMock extends Error {\n errors: TailorErrorItem[];\n\n constructor(errors: TailorErrorItem[]) {\n if (!Array.isArray(errors)) {\n throw new TypeError(\"TailorErrors: errors must be an array\");\n }\n const validated = errors.map((e, i) => {\n if (typeof e.message !== \"string\") {\n throw new TypeError(`TailorErrors: errors[${i}].message must be a string`);\n }\n if (!Array.isArray(e.path)) {\n throw new TypeError(`TailorErrors: errors[${i}].path must be an array`);\n }\n return { message: e.message, path: e.path };\n });\n // Match the PF runtime's TailorErrors serialization, which prefixes the\n // JSON payload with \"TailorErrors: \". Other SDK code (e.g. apply\n // integration fixtures) strips this prefix before JSON.parse.\n super(`TailorErrors: ${JSON.stringify({ errors: validated })}`);\n this.name = \"TailorErrors\";\n this.errors = validated;\n }\n}\n\nclass TailorErrorMessageMock extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TailorErrorMessage\";\n }\n}\n\nclass TailorDBFileErrorMock extends Error {\n code?: TailorDBFileErrorCode;\n override cause: unknown;\n\n constructor(message: string, code?: TailorDBFileErrorCode, cause?: unknown) {\n super(message);\n this.name = \"TailorDBFileError\";\n this.code = code;\n this.cause = cause;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Base install / cleanup\n// ---------------------------------------------------------------------------\n\n// Stub-only injection. SDK consumers configure invokers at the body level\n// (resolver/executor/workflow `.body()` `invoker` arg) or, for bundled tests,\n// via `vi.spyOn(globalThis.tailor.context, \"getInvoker\")`.\nfunction defaultGetInvoker(): ContextInvoker | null {\n return null;\n}\n\n// No-op logger stub so `tailor.logger.*` calls in code under test don't throw\n// without an explicit `mockLogger()`. `mockLogger()` overlays vi.fn spies and\n// restores this on dispose.\nfunction noop(): void {}\nconst defaultLogger = {\n debug: noop,\n info: noop,\n warn: noop,\n error: noop,\n setAttributes: noop,\n};\n\n/**\n * Install the always-present base platform globals (containers, context stub,\n * error classes, runtime flag). Per-namespace mocks are layered on top by the\n * `xMock()` factories in `./mock`.\n *\n * Acquire with a `using` declaration and the globals are removed when the\n * scope exits; alternatively call `cleanupPlatformGlobals` yourself.\n * @param global - The global object to install into (typically `globalThis`)\n * @returns A `Disposable` that removes the installed globals\n */\nexport function installPlatformGlobals(global: typeof globalThis): Disposable {\n const g = global as Record<string, unknown>;\n\n g[RUNTIME_FLAG_KEY] = true;\n\n // Containers. Namespace mocks (secretmanager, …) are added to these by the\n // corresponding `xMock()` on acquisition. `workflow` carries a default runner\n // so `.trigger()` runs the real job chain locally without `mockWorkflow()`;\n // `mockWorkflow()` overlays and restores it.\n g.tailor = {\n context: { getInvoker: defaultGetInvoker },\n workflow: createDefaultWorkflowRuntime(),\n logger: { ...defaultLogger },\n };\n g.tailordb = {};\n\n g.TailorErrors = TailorErrorsMock;\n g.TailorErrorMessage = TailorErrorMessageMock;\n g.TailorDBFileError = TailorDBFileErrorMock;\n\n return {\n [Symbol.dispose]() {\n cleanupPlatformGlobals(global);\n },\n };\n}\n\n/**\n * Remove the base platform globals (and anything the namespace mocks layered on\n * top, since they live under the same containers).\n * @param global - The global object to clean up (typically `globalThis`)\n */\nexport function cleanupPlatformGlobals(global: typeof globalThis): void {\n const g = global as Record<string, unknown>;\n delete g.tailordb;\n delete g.tailor;\n delete g.TailorErrors;\n delete g.TailorErrorMessage;\n delete g.TailorDBFileError;\n delete g[RUNTIME_FLAG_KEY];\n}\n"],"mappings":";;;AA0BA,SAAgB,+BAAuD;CACrE,MAAM,mBAA8D,MAAM,SACxE,iBAAiB,MAAM,IAAI;CAC7B,MAAM,iBAA0D,MAAM,SACpE,sBAAsB,MAAM,IAAI;CAClC,MAAM,0BAA6E,OACjF,gBACG;CACL,OAAO;EACL;EACA,kBAAkB;EAClB,oBAAoB;EACpB;EACA,iBAAiB;EACjB;EACA,gBAAgB;EAChB,OAAO,QAAyB;GAC9B,MAAM,IAAI,MACR,wBAAwB,IAAI,wDAC9B;EACF;EACA,SAAS,YAA2B;GAClC,MAAM,IAAI,MACR,6EACF;EACF;CACF;AACF;;;;;;;;;;;;;;;;;;;;;AC5BA,MAAa,mBAAmB;AAWhC,IAAM,mBAAN,cAA+B,MAAM;CACnC;CAEA,YAAY,QAA2B;EACrC,IAAI,CAAC,MAAM,QAAQ,MAAM,GACvB,MAAM,IAAI,UAAU,uCAAuC;EAE7D,MAAM,YAAY,OAAO,KAAK,GAAG,MAAM;GACrC,IAAI,OAAO,EAAE,YAAY,UACvB,MAAM,IAAI,UAAU,wBAAwB,EAAE,2BAA2B;GAE3E,IAAI,CAAC,MAAM,QAAQ,EAAE,IAAI,GACvB,MAAM,IAAI,UAAU,wBAAwB,EAAE,wBAAwB;GAExE,OAAO;IAAE,SAAS,EAAE;IAAS,MAAM,EAAE;GAAK;EAC5C,CAAC;EAID,MAAM,iBAAiB,KAAK,UAAU,EAAE,QAAQ,UAAU,CAAC,GAAG;EAC9D,KAAK,OAAO;EACZ,KAAK,SAAS;CAChB;AACF;AAEA,IAAM,yBAAN,cAAqC,MAAM;CACzC,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF;AAEA,IAAM,wBAAN,cAAoC,MAAM;CACxC;CACA,AAAS;CAET,YAAY,SAAiB,MAA8B,OAAiB;EAC1E,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,KAAK,QAAQ;CACf;AACF;AASA,SAAS,oBAA2C;CAClD,OAAO;AACT;AAKA,SAAS,OAAa,CAAC;AACvB,MAAM,gBAAgB;CACpB,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACP,eAAe;AACjB;;;;;;;;;;;AAYA,SAAgB,uBAAuB,QAAuC;CAC5E,MAAM,IAAI;CAEV,EAAE,oBAAoB;CAMtB,EAAE,SAAS;EACT,SAAS,EAAE,YAAY,kBAAkB;EACzC,UAAU,6BAA6B;EACvC,QAAQ,EAAE,GAAG,cAAc;CAC7B;CACA,EAAE,WAAW,CAAC;CAEd,EAAE,eAAe;CACjB,EAAE,qBAAqB;CACvB,EAAE,oBAAoB;CAEtB,OAAO,EACL,CAAC,OAAO,WAAW;EACjB,uBAAuB,MAAM;CAC/B,EACF;AACF;;;;;;AAOA,SAAgB,uBAAuB,QAAiC;CACtE,MAAM,IAAI;CACV,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;CACT,OAAO,EAAE;AACX"}
@@ -2,7 +2,7 @@ import { t as db } from "./schema-CYrle8JZ.mjs";
2
2
  import { $ as CreateAuthHookRequestSchema, B as IdPLang, Bt as Subgraph_ServiceType, C as CreateStaticWebsiteRequestSchema, Ct as AuthInvokerSchema, D as CreateSecretManagerSecretRequestSchema, Dt as AuthSCIMAttribute_Type, Et as AuthSCIMAttribute_Mutability, Ft as CreateApplicationRequestSchema, H as IdPPermissionPermit, Ht as UpdateAIGatewayRequestSchema, I as PipelineResolver_OperationType, It as GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus, Jt as FilterSchema, K as CreateExecutorExecutorRequestSchema, Kt as ConditionSchema, L as CreateIdPServiceRequestSchema, Lt as UpdateApplicationRequestSchema, M as CreatePipelineServiceRequestSchema, Mt as UserProfileProviderConfig_UserProfileProviderType, N as UpdatePipelineResolverRequestSchema, O as CreateSecretManagerVaultRequestSchema, Ot as AuthSCIMAttribute_Uniqueness, P as UpdatePipelineServiceRequestSchema, Q as CreateAuthConnectionRequestSchema, R as UpdateIdPServiceRequestSchema, S as AddCustomDomainRequestSchema, St as AuthIDPConfig_AuthType, Tt as AuthOAuth2Client_GrantType, U as FunctionExecution_Status, V as IdPPermissionOperator, Vt as CreateAIGatewayRequestSchema, X as ExecutorTargetType, Y as ExecutorJobStatus, Yt as PageDirection, Z as ExecutorTriggerType, _ as TailorDBGQLPermission_Permit, _t as UpdateUserProfileConfigRequestSchema, a as CreateWorkflowRequestSchema, at as CreateAuthServiceRequestSchema, b as TailorDBType_Permission_Permit, bt as AuthConnection_Type, ct as UpdateAuthConnectionRequestSchema, d as CreateTailorDBServiceRequestSchema, dt as UpdateAuthMachineUserRequestSchema, et as CreateAuthIDPConfigRequestSchema, f as CreateTailorDBTypeRequestSchema, ft as UpdateAuthOAuth2ClientRequestSchema, g as TailorDBGQLPermission_Operator, gt as UpdateTenantConfigRequestSchema, h as TailorDBGQLPermission_Action, ht as UpdateAuthServiceRequestSchema, i as CreateWorkflowJobFunctionRequestSchema, it as CreateAuthSCIMResourceRequestSchema, j as CreatePipelineResolverRequestSchema, jt as TenantProviderConfig_TenantProviderType, k as UpdateSecretManagerSecretRequestSchema, kt as AuthSCIMConfig_AuthorizationType, l as WorkflowExecution_Status, lt as UpdateAuthHookRequestSchema, mt as UpdateAuthSCIMResourceRequestSchema, nt as CreateAuthOAuth2ClientRequestSchema, o as UpdateWorkflowJobFunctionExecutionPolicyRequestSchema, ot as CreateTenantConfigRequestSchema, p as UpdateTailorDBTypeRequestSchema, pt as UpdateAuthSCIMConfigRequestSchema, q as UpdateExecutorExecutorRequestSchema, qt as Condition_Operator, r as CreateWorkflowJobFunctionExecutionPolicyRequestSchema, rt as CreateAuthSCIMConfigRequestSchema, s as UpdateWorkflowRequestSchema, st as CreateUserProfileConfigRequestSchema, t as WorkspacePlatformUserRole, tt as CreateAuthMachineUserRequestSchema, u as WorkflowJobExecution_Status, ut as UpdateAuthIDPConfigRequestSchema, v as TailorDBTypeSchema, w as UpdateStaticWebsiteRequestSchema, wt as AuthOAuth2Client_ClientType, x as TailorDBType_PermitAction, xt as AuthHookPoint, y as TailorDBType_Permission_Operator, yt as AuthConnection_Status, zt as ApplicationSchemaUpdateAttemptStatus } from "./workspace_resource_pb-UGK1SSn_.mjs";
3
3
  import { t as assertDefined } from "./assert-DBxo8jPo.mjs";
4
4
  import { a as parseBoolean, i as symbols, n as logger, o as renderTable, r as styles, t as CIPromptError } from "./logger-CXQq9YIp.mjs";
5
- import { A as defaultPlatformBaseUrl, B as getPlatformBaseUrl, C as getPluginGenerationDependencies, D as hashContent, E as getDistDir, G as rememberPlatformConfigForToken, H as initOperatorClient, J as createApplyLimiter, K as resolveStaticWebsiteUrls, L as getConsoleBaseUrl, M as fetchAllTolerant, N as fetchMachineUserToken, O as hashFile, P as fetchPaged, R as getOAuth2ClientId, T as createBundleCache, U as isDefaultPlatform, V as initOAuth2Client, W as normalizeBaseUrl, Y as LOG_LEVELS, _ as stringifyFunction, d as buildExecutorArgsExpr, f as buildResolverOperationHookExpr, g as TailorDBTypeSchema$1, h as assertUniqueTailorDBTypeNamesWithExternal, i as resolverBundleKey, j as fetchAll, l as HTTP_METHODS, m as assertUniqueLocalTailorDBTypeNames, n as generatePluginFilesIfNeeded, o as WorkflowJobFunctionExecutionPolicySchema, q as byName, r as loadApplication, t as defineApplication, v as resolveTSConfigWithFallback, w as hasGenerationHooks, y as platformBundleDefinePlugin, z as getOrNull } from "./application-CVeA53ok.mjs";
5
+ import { A as defaultPlatformBaseUrl, B as getPlatformBaseUrl, C as getPluginGenerationDependencies, D as hashContent, E as getDistDir, G as rememberPlatformConfigForToken, H as initOperatorClient, J as createApplyLimiter, K as resolveStaticWebsiteUrls, L as getConsoleBaseUrl, M as fetchAllTolerant, N as fetchMachineUserToken, O as hashFile, P as fetchPaged, R as getOAuth2ClientId, T as createBundleCache, U as isDefaultPlatform, V as initOAuth2Client, W as normalizeBaseUrl, Y as LOG_LEVELS, _ as stringifyFunction, d as buildExecutorArgsExpr, f as buildResolverOperationHookExpr, g as TailorDBTypeSchema$1, h as assertUniqueTailorDBTypeNamesWithExternal, i as resolverBundleKey, j as fetchAll, l as HTTP_METHODS, m as assertUniqueLocalTailorDBTypeNames, n as generatePluginFilesIfNeeded, o as WorkflowJobFunctionExecutionPolicySchema, q as byName, r as loadApplication, t as defineApplication, v as resolveTSConfigWithFallback, w as hasGenerationHooks, y as platformBundleDefinePlugin, z as getOrNull } from "./application-Cp0FxIm2.mjs";
6
6
  import { o as loadFilesWithIgnores, s as functionSchema, t as createExecutorService } from "./service-B0MaodSg.mjs";
7
7
  import { n as enumConstantsPlugin, t as EnumConstantsGeneratorID } from "./enum-constants-j9QBF0cB.mjs";
8
8
  import { t as multiline } from "./multiline-sfHpTZZK.mjs";
@@ -7964,6 +7964,29 @@ function compareTypeFields(ctx, typeName, prevType, currType) {
7964
7964
  }
7965
7965
  }
7966
7966
  /**
7967
+ * Determine if a type-level index change is breaking. Mirrors the field-level
7968
+ * unique reasoning: enforcing a unique constraint over existing rows can fail
7969
+ * on duplicates, so both adding a unique index and re-pointing an existing
7970
+ * unique index at a different field set require a data migration.
7971
+ * @param {string} typeName - Name of the type containing the index
7972
+ * @param {string} indexName - Name of the index being changed
7973
+ * @param {SnapshotIndexConfig | undefined} oldIndex - Old index configuration
7974
+ * @param {SnapshotIndexConfig | undefined} newIndex - New index configuration
7975
+ * @returns {BreakingChangeInfo | null} Breaking change info or null if not breaking
7976
+ */
7977
+ function isBreakingIndexChange(typeName, indexName, oldIndex, newIndex) {
7978
+ if (!newIndex || !(newIndex.unique ?? false)) return null;
7979
+ if (!oldIndex || !(oldIndex.unique ?? false)) return {
7980
+ typeName,
7981
+ reason: `Unique constraint added to index "${indexName}"`
7982
+ };
7983
+ if (JSON.stringify(oldIndex.fields.toSorted()) !== JSON.stringify(newIndex.fields.toSorted())) return {
7984
+ typeName,
7985
+ reason: `Unique index fields changed on index "${indexName}"`
7986
+ };
7987
+ return null;
7988
+ }
7989
+ /**
7967
7990
  * Compare type-level indexes
7968
7991
  * @param {DiffContext} ctx - Diff context
7969
7992
  * @param {string} typeName - Type name
@@ -7974,12 +7997,16 @@ function compareTypeFields(ctx, typeName, prevType, currType) {
7974
7997
  function compareIndexes(ctx, typeName, oldIndexes, newIndexes) {
7975
7998
  const oldKeys = new Set(Object.keys(oldIndexes || {}));
7976
7999
  const newKeys = new Set(Object.keys(newIndexes || {}));
7977
- for (const [indexName, indexConfig] of Object.entries(newIndexes ?? {})) if (!oldKeys.has(indexName)) ctx.changes.push({
7978
- kind: "index_added",
7979
- typeName,
7980
- indexName,
7981
- after: indexConfig
7982
- });
8000
+ for (const [indexName, indexConfig] of Object.entries(newIndexes ?? {})) if (!oldKeys.has(indexName)) {
8001
+ ctx.changes.push({
8002
+ kind: "index_added",
8003
+ typeName,
8004
+ indexName,
8005
+ after: indexConfig
8006
+ });
8007
+ const breaking = isBreakingIndexChange(typeName, indexName, void 0, indexConfig);
8008
+ if (breaking) ctx.breakingChanges.push(breaking);
8009
+ }
7983
8010
  for (const [indexName, indexConfig] of Object.entries(oldIndexes ?? {})) if (!newKeys.has(indexName)) ctx.changes.push({
7984
8011
  kind: "index_removed",
7985
8012
  typeName,
@@ -8002,6 +8029,8 @@ function compareIndexes(ctx, typeName, oldIndexes, newIndexes) {
8002
8029
  before: oldIndex,
8003
8030
  after: newIndex
8004
8031
  });
8032
+ const breaking = isBreakingIndexChange(typeName, indexName, oldIndex, newIndex);
8033
+ if (breaking) ctx.breakingChanges.push(breaking);
8005
8034
  }
8006
8035
  }
8007
8036
  }
@@ -9326,6 +9355,12 @@ function protoGqlOperand(operand) {
9326
9355
  * - `field_modified` optional→required, unique constraint added, enum
9327
9356
  * value removed: keep the looser side until Post-phase.
9328
9357
  *
9358
+ * and the type-level index adjustments:
9359
+ *
9360
+ * - `index_added` with `unique: true`: withhold the index until Post-phase.
9361
+ * - `index_modified` that gains a unique constraint or re-points a unique
9362
+ * index at different fields: keep the previous definition until Post-phase.
9363
+ *
9329
9364
  * Type-level deletions (`type_removed`) are handled by the deploy flow,
9330
9365
  * which retains the type until Post-phase rather than via this module.
9331
9366
  *
@@ -9407,6 +9442,45 @@ function applyPreMigrationFieldAdjustments(fields, typeChanges) {
9407
9442
  }
9408
9443
  }
9409
9444
  }
9445
+ /**
9446
+ * Build a map of type-level index changes that require pre-migration schema
9447
+ * adjustment (the breaking ones — see {@link isBreakingIndexChange}).
9448
+ * @param {PendingMigration[]} pendingMigrations - Pending migrations to scan
9449
+ * @returns {PreMigrationIndexChangesMap} Map of changes keyed by typeName/indexName
9450
+ */
9451
+ function buildPreMigrationIndexChangesMap(pendingMigrations) {
9452
+ const map = /* @__PURE__ */ new Map();
9453
+ for (const migration of pendingMigrations) for (const change of migration.diff.changes) {
9454
+ if (change.kind !== "index_added" && change.kind !== "index_modified") continue;
9455
+ const before = change.kind === "index_modified" ? change.before : void 0;
9456
+ if (!isBreakingIndexChange(change.typeName, change.indexName, before, change.after)) continue;
9457
+ const perType = map.get(change.typeName) ?? /* @__PURE__ */ new Map();
9458
+ perType.set(change.indexName, change);
9459
+ map.set(change.typeName, perType);
9460
+ }
9461
+ return map;
9462
+ }
9463
+ /**
9464
+ * Apply pre-migration schema adjustments to a type's index map in place.
9465
+ *
9466
+ * The indexes map is the proto-shape `TailorDBType.schema.indexes` that will
9467
+ * be sent in the Pre-phase. We mutate it so that:
9468
+ *
9469
+ * - Newly added unique indexes are withheld until Post-phase.
9470
+ * - Modified indexes keep their previous definition until Post-phase.
9471
+ *
9472
+ * @param {Record<string, MessageInitShape<typeof TailorDBType_IndexSchema>>} indexes - Index map to adjust (mutated in place)
9473
+ * @param {Map<string, IndexDiffChange>} typeIndexChanges - Changes for this type, keyed by indexName
9474
+ */
9475
+ function applyPreMigrationIndexAdjustments(indexes, typeIndexChanges) {
9476
+ for (const [indexName, change] of typeIndexChanges) {
9477
+ if (change.kind === "index_added") {
9478
+ delete indexes[indexName];
9479
+ continue;
9480
+ }
9481
+ if (change.kind === "index_modified") indexes[indexName] = convertIndexToProto(change.before);
9482
+ }
9483
+ }
9410
9484
 
9411
9485
  //#endregion
9412
9486
  //#region src/cli/commands/tailordb/migrate/types.ts
@@ -10401,6 +10475,7 @@ async function awaitAllSettledOrThrow(promises) {
10401
10475
  */
10402
10476
  async function executeSingleMigrationPrePhase(client, changeSet, migration, tailorDBInputs, executorUsedTypes) {
10403
10477
  const preMigrationChanges = buildPreMigrationChangesMap([migration]);
10478
+ const preMigrationIndexChanges = buildPreMigrationIndexChangesMap([migration]);
10404
10479
  const affectedTypes = getAffectedTypeNames(migration);
10405
10480
  const createdBeforeMigration = new Set(processedTypes.created);
10406
10481
  for (const create of changeSet.type.creates) {
@@ -10412,6 +10487,8 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
10412
10487
  clonedRequest.tailordbType = snapshotType;
10413
10488
  const typeChanges = preMigrationChanges.get(typeName);
10414
10489
  if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType.schema?.fields) applyPreMigrationFieldAdjustments(clonedRequest.tailordbType.schema.fields, typeChanges);
10490
+ const indexChanges = preMigrationIndexChanges.get(typeName);
10491
+ if (indexChanges && indexChanges.size > 0 && clonedRequest.tailordbType.schema?.indexes) applyPreMigrationIndexAdjustments(clonedRequest.tailordbType.schema.indexes, indexChanges);
10415
10492
  processedTypes.created.add(typeName);
10416
10493
  await client.createTailorDBType(clonedRequest);
10417
10494
  }
@@ -10423,6 +10500,8 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
10423
10500
  const clonedTypeRequest = structuredClone(snapshotType);
10424
10501
  const typeChanges = preMigrationChanges.get(typeName);
10425
10502
  if (typeChanges && typeChanges.size > 0 && clonedTypeRequest.schema?.fields) applyPreMigrationFieldAdjustments(clonedTypeRequest.schema.fields, typeChanges);
10503
+ const indexChanges = preMigrationIndexChanges.get(typeName);
10504
+ if (indexChanges && indexChanges.size > 0 && clonedTypeRequest.schema?.indexes) applyPreMigrationIndexAdjustments(clonedTypeRequest.schema.indexes, indexChanges);
10426
10505
  processedTypes.updated.add(typeName);
10427
10506
  await client.updateTailorDBType({
10428
10507
  workspaceId: create.request.workspaceId,
@@ -10439,6 +10518,8 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
10439
10518
  clonedRequest.tailordbType = snapshotType;
10440
10519
  const typeChanges = preMigrationChanges.get(typeName);
10441
10520
  if (typeChanges && typeChanges.size > 0 && clonedRequest.tailordbType.schema?.fields) applyPreMigrationFieldAdjustments(clonedRequest.tailordbType.schema.fields, typeChanges);
10521
+ const indexChanges = preMigrationIndexChanges.get(typeName);
10522
+ if (indexChanges && indexChanges.size > 0 && clonedRequest.tailordbType.schema?.indexes) applyPreMigrationIndexAdjustments(clonedRequest.tailordbType.schema.indexes, indexChanges);
10442
10523
  processedTypes.updated.add(typeName);
10443
10524
  await client.updateTailorDBType(clonedRequest);
10444
10525
  }
@@ -10481,12 +10562,14 @@ const deletedResources = {
10481
10562
  */
10482
10563
  async function executeSingleMigrationPostPhase(client, changeSet, migration, tailorDBInputs, executorUsedTypes) {
10483
10564
  const preMigrationChanges = buildPreMigrationChangesMap([migration]);
10565
+ const preMigrationIndexChanges = buildPreMigrationIndexChangesMap([migration]);
10566
+ const adjustedTypes = /* @__PURE__ */ new Set([...preMigrationChanges.keys(), ...preMigrationIndexChanges.keys()]);
10484
10567
  const affectedTypes = getAffectedTypeNames(migration);
10485
10568
  const deletedTypeNames = getDeletedTypeNames(migration);
10486
10569
  try {
10487
10570
  for (const create of changeSet.type.creates) {
10488
10571
  const typeName = create.request.tailordbType?.name;
10489
- if (!typeName || !affectedTypes.has(typeName) || !preMigrationChanges.has(typeName)) continue;
10572
+ if (!typeName || !affectedTypes.has(typeName) || !adjustedTypes.has(typeName)) continue;
10490
10573
  const snapshotType = buildSnapshotTypeManifest(migration, typeName, tailorDBInputs, executorUsedTypes);
10491
10574
  if (!snapshotType) continue;
10492
10575
  await client.updateTailorDBType({
@@ -10497,7 +10580,7 @@ async function executeSingleMigrationPostPhase(client, changeSet, migration, tai
10497
10580
  }
10498
10581
  for (const update of changeSet.type.updates) {
10499
10582
  const typeName = update.request.tailordbType?.name;
10500
- if (!typeName || !affectedTypes.has(typeName) || !preMigrationChanges.has(typeName)) continue;
10583
+ if (!typeName || !affectedTypes.has(typeName) || !adjustedTypes.has(typeName)) continue;
10501
10584
  const snapshotType = buildSnapshotTypeManifest(migration, typeName, tailorDBInputs, executorUsedTypes);
10502
10585
  if (!snapshotType) continue;
10503
10586
  await client.updateTailorDBType({
@@ -18808,6 +18891,37 @@ ${updates.join("\n\n")}
18808
18891
  * @returns {string | null} Script content or null if no script needed
18809
18892
  */
18810
18893
  function generateChangeScript(change) {
18894
+ if (change.kind === "index_added" || change.kind === "index_modified") {
18895
+ const before = change.kind === "index_modified" ? change.before : void 0;
18896
+ if (!isBreakingIndexChange(change.typeName, change.indexName, before, change.after)) return null;
18897
+ const fields = change.after.fields;
18898
+ const fieldList = fields.map((f) => `"${f}"`).join(", ");
18899
+ const whereClauses = fields.map((f) => `.where("${f}", "=", dup.${f})`).join("\n ");
18900
+ return ` // Resolve duplicate (${fields.join(", ")}) combinations before unique index "${change.indexName}" is enforced
18901
+ {
18902
+ const duplicates = await trx
18903
+ .selectFrom("${change.typeName}")
18904
+ .select([${fieldList}])
18905
+ .groupBy([${fieldList}])
18906
+ .having((eb) => eb.fn.count("id"), ">", 1)
18907
+ .execute();
18908
+ for (const dup of duplicates) {
18909
+ const records = await trx
18910
+ .selectFrom("${change.typeName}")
18911
+ .select(["id"])
18912
+ ${whereClauses}
18913
+ .execute();
18914
+ // Keep the first record; update or delete the others so the combination becomes unique
18915
+ for (let i = 1; i < records.length; i++) {
18916
+ await trx
18917
+ .updateTable("${change.typeName}")
18918
+ .set({ ${fields[0]}: null }) // TODO: Set appropriate unique value
18919
+ .where("id", "=", records[i].id)
18920
+ .execute();
18921
+ }
18922
+ }
18923
+ }`;
18924
+ }
18811
18925
  if (change.kind === "field_added") {
18812
18926
  if (change.after.required) return ` // Populate ${change.fieldName} for existing ${change.typeName} records
18813
18927
  await trx
@@ -18949,7 +19063,7 @@ async function generate(options) {
18949
19063
  if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
18950
19064
  let pluginManager;
18951
19065
  if (plugins.length > 0) pluginManager = new PluginManager(plugins);
18952
- const { defineApplication } = await import("./application-CP0W2sQo.mjs");
19066
+ const { defineApplication } = await import("./application-CP7JKG9R.mjs");
18953
19067
  const application = defineApplication({
18954
19068
  config,
18955
19069
  pluginManager
@@ -21078,4 +21192,4 @@ async function registerTypeScriptRuntime(hookUrl) {
21078
21192
 
21079
21193
  //#endregion
21080
21194
  export { listFolders as $, deploymentArgs as $n, handleOptionalToRequiredError as $t, generate as A, generateUserTypes as An, startCommand as At, remove as B, loadConsoleBaseUrl as Bn, deploy as Bt, waitWorkflowExecution as C, formatDiffSummary as Cn, listCommand$8 as Ct, listWorkflows as D, resourceTrn as Dn, jobsCommand as Dt, listCommand$2 as E, getNamespacesWithMigrations as En, getExecutorWaitFailureMessage as Et, openInConfiguredEditor as F, deleteUserTokens as Fn, getWorkflowExecution as Ft, treeCommand as G, readPlatformConfig as Gn, createWorkspace$1 as Gt, updateCommand$1 as H, loadStoredUserTokens as Hn, listCommand$9 as Ht, show as I, fetchLatestToken as In, listWorkflowExecutions as It, getCommand$1 as J, writePlatformConfig as Jn, ensureConfigId as Jt, listCommand$3 as K, resolveUserTokenKey as Kn, formatKeyValueTable as Kt, showCommand as L, hasAnyUserTokenEntry as Ln, functionExecutionStatusToString as Lt, generateMigrationScript as M, apiCall as Mn, getCommand$5 as Mt, writeDbTypesFile as N, assertWritable as Nn, getWorkflow as Nt, truncate as O, sdkNameLabelKey as On, listExecutorJobs as Ot, getConfiguredEditorCommand as P, loadConfig as Pn, executionsCommand as Pt, listCommand$4 as Q, confirmationArgs as Qn, MIGRATION_LABEL_KEY as Qt, extractOwnedNamespaces as R, hasUserTokenEntry as Rn, getCommand$6 as Rt, waitCommand as S, parseMigrationNumberArg as Sn, triggerExecutor as St, resumeWorkflow as T, hasChanges as Tn, getExecutorJob as Tt, updateOrganization as U, loadWorkspaceId as Un, listWorkspaces as Ut, removeCommand$1 as V, loadMachineUserName as Vn, deployFromCLI as Vt, organizationTree as W, platformConfigFromProfile as Wn, createCommand$1 as Wt, updateCommand$2 as X, commonArgs as Xn, waitForExecution as Xt, getOrganization as Y, defineAppCommand as Yn, executeScript as Yt, updateFolder as Z, configArg as Zn, bundleMigrationScript as Zt, deleteWorkspace as _, getNextMigrationNumber as _n, getCommand$4 as _t, updateUser as a, DIFF_FILE_NAME as an, toPageDirection as ar, createFolder as at, getAppHealth as b, reconstructSnapshotFromMigrations as bn, webhookCommand as bt, listCommand as c, SCHEMA_FILE_NAME as cn, getCommand$3 as ct, inviteUser as d, compareSnapshots as dn, tokenCommand as dt, parseMigrationLabelNumber as en, isVerbose as er, getCommand$2 as et, restoreCommand as f, createSnapshotFromLocalTypes as fn, listCommand$6 as ft, deleteCommand as g, getMigrationFiles as gn, listFunctionRegistries as gt, getWorkspace as h, getMigrationFilePath as hn, listCommand$7 as ht, updateCommand as i, DB_TYPES_FILE_NAME as in, resolveMachineUserInputSource as ir, createCommand as it, generateCommand as j, prompt as jn, startWorkflow as jt, truncateCommand as k, PluginManager as kn, watchExecutorJob as kt, listUsers as l, assertValidMigrationFiles as ln, getOAuth2Client as lt, getCommand as m, getMigrationDirPath as mn, generate$1 as mt, query as n, generateAllTypeManifestsFromSnapshot as nn, pagedLogArgs as nr, deleteCommand$1 as nt, removeCommand as o, INITIAL_SCHEMA_NUMBER as on, workspaceArgs as or, listCommand$5 as ot, restoreWorkspace as p, getLatestMigrationNumber as pn, listMachineUsers as pt, listOrganizations as q, saveUserTokens as qn, workspaceNameSchema as qt, queryCommand as r, protoGqlPermission as rn, paginationArgs as rr, deleteFolder as rt, removeUser as s, MIGRATE_FILE_NAME as sn, listOAuth2Clients as st, registerTypeScriptRuntime as t, compareSnapshotWithRemote as tn, multiConfigArg as tr, getFolder as tt, inviteCommand as u, compareLocalTypesWithSnapshot as un, getMachineUserToken as ut, listApps as v, isValidMigrationNumber as vn, getFunctionRegistry as vt, resumeCommand as w, formatMigrationDiff as wn, listExecutors as wt, healthCommand as x, formatMigrationNumber as xn, triggerCommand as xt, listCommand$1 as y, loadDiff as yn, listWebhookExecutors as yt, logBetaWarning as z, loadAccessToken as zn, getExecutor as zt };
21081
- //# sourceMappingURL=register-typescript-runtime-O7zQNif0.mjs.map
21195
+ //# sourceMappingURL=register-typescript-runtime-CCHyKeXO.mjs.map