@tailor-platform/sdk 1.83.0 → 1.84.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 +32 -0
- package/dist/application-5FOWIxFQ.mjs +3 -0
- package/dist/{application-Cp0FxIm2.mjs → application-CnCljDwk.mjs} +13 -8
- package/dist/application-CnCljDwk.mjs.map +1 -0
- package/dist/cli/commands/deploy/tailordb/index.d.mts +1 -0
- package/dist/cli/commands/generate/service.d.mts +1 -1
- package/dist/cli/commands/generate/types.d.mts +1 -1
- package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +11 -1
- package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +1 -1
- package/dist/cli/index.mjs +65 -10
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lib.d.mts +1 -1
- package/dist/cli/lib.mjs +2 -2
- package/dist/cli/shared/client.d.mts +28 -3
- package/dist/cli/skills.d.mts +1 -1
- package/dist/completion/zsh-worker.zsh +35 -22
- package/dist/configure/index.d.mts +2 -2
- package/dist/configure/index.mjs +170 -2
- package/dist/configure/index.mjs.map +1 -1
- package/dist/configure/services/executor/index.d.mts +2 -2
- package/dist/configure/services/executor/trigger/event.d.mts +245 -2
- package/dist/configure/services/executor/trigger/index.d.mts +3 -3
- package/dist/configure/services/index.d.mts +2 -2
- package/dist/configure/services/tailordb/index.d.mts +0 -1
- package/dist/configure/services/workflow/job.d.mts +9 -0
- package/dist/configure/services/workflow/workflow.d.mts +10 -0
- package/dist/{register-typescript-runtime-CCHyKeXO.mjs → register-typescript-runtime-BCvWR3HC.mjs} +398 -117
- package/dist/register-typescript-runtime-BCvWR3HC.mjs.map +1 -0
- package/dist/{service-B0MaodSg.mjs → service-CPJWhTLn.mjs} +29 -2
- package/dist/service-CPJWhTLn.mjs.map +1 -0
- package/dist/service-Cigg_U-v.mjs +3 -0
- package/dist/{service_pb-BwZRiNug.mjs → service_pb-D5--My_M.mjs} +5 -5
- package/dist/service_pb-D5--My_M.mjs.map +1 -0
- package/dist/{service_pb-wRkxUta6.mjs → service_pb-i8CmnQP4.mjs} +1 -1
- package/dist/tailor-proto/src/tailor/v1/application_pb.d.mts +106 -1
- package/dist/tailor-proto/src/tailor/v1/executor_resource_pb.d.mts +24 -1
- package/dist/tailor-proto/src/tailor/v1/function_pb.d.mts +49 -1
- package/dist/tailor-proto/src/tailor/v1/service_pb.d.mts +89 -6
- package/dist/tailor-proto/src/tailor/v1/telemetryrouter_resource_pb.d.mts +26 -1
- package/dist/tailor-proto/src/tailor/v1/workflow_pb.d.mts +101 -1
- package/dist/tailor-proto/src/tailor/v1/workflow_resource_pb.d.mts +22 -1
- package/dist/types/executor.generated.d.mts +23 -3
- package/dist/{workspace_resource_pb-UGK1SSn_.mjs → workspace_resource_pb-DXnO2AT-.mjs} +7 -7
- package/dist/workspace_resource_pb-DXnO2AT-.mjs.map +1 -0
- package/docs/cli/tailordb.md +14 -12
- package/docs/cli-reference.md +15 -15
- package/docs/services/executor.md +83 -3
- package/docs/services/idp.md +3 -3
- package/docs/services/tailordb-migration.md +13 -2
- package/docs/services/workflow.md +26 -0
- package/package.json +16 -16
- package/dist/application-CP7JKG9R.mjs +0 -3
- package/dist/application-Cp0FxIm2.mjs.map +0 -1
- package/dist/register-typescript-runtime-CCHyKeXO.mjs.map +0 -1
- package/dist/service-B0MaodSg.mjs.map +0 -1
- package/dist/service-KnAiVofD.mjs +0 -3
- package/dist/service_pb-BwZRiNug.mjs.map +0 -1
- package/dist/workspace_resource_pb-UGK1SSn_.mjs.map +0 -1
package/dist/{register-typescript-runtime-CCHyKeXO.mjs → register-typescript-runtime-BCvWR3HC.mjs}
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as db } from "./schema-CYrle8JZ.mjs";
|
|
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-
|
|
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-DXnO2AT-.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
|
|
6
|
-
import { o as loadFilesWithIgnores, s as functionSchema, t as createExecutorService } from "./service-
|
|
5
|
+
import { A as defaultPlatformBaseUrl, B as getPlatformBaseUrl, C as getPluginGenerationDependencies, D as hashContent, E as getDistDir, G as normalizeBaseUrl, H as initOperatorClient, J as byName, K as rememberPlatformConfigForToken, 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 isNotFoundError, X as LOG_LEVELS, Y as createApplyLimiter, _ 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 resolveStaticWebsiteUrls, r as loadApplication, t as defineApplication, v as resolveTSConfigWithFallback, w as hasGenerationHooks, y as platformBundleDefinePlugin, z as getOrNull } from "./application-CnCljDwk.mjs";
|
|
6
|
+
import { o as loadFilesWithIgnores, s as functionSchema, t as createExecutorService } from "./service-CPJWhTLn.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";
|
|
9
9
|
import { n as fileUtilsPlugin, t as FileUtilsGeneratorID } from "./file-utils-DcyIPFQh.mjs";
|
|
@@ -5926,6 +5926,18 @@ function protoExecutor(context, executor) {
|
|
|
5926
5926
|
}
|
|
5927
5927
|
});
|
|
5928
5928
|
break;
|
|
5929
|
+
case "workflowExecution":
|
|
5930
|
+
case "workflowJobExecution":
|
|
5931
|
+
triggerType = ExecutorTriggerType.EVENT;
|
|
5932
|
+
triggerConfig = typedEventTrigger({
|
|
5933
|
+
case: "workflow",
|
|
5934
|
+
value: {
|
|
5935
|
+
eventTypes: trigger.events,
|
|
5936
|
+
workflowName: trigger.workflowName,
|
|
5937
|
+
...trigger.condition ? { condition: { expr: `(${stringifyFunction(trigger.condition)})(${argsExpr})` } } : {}
|
|
5938
|
+
}
|
|
5939
|
+
});
|
|
5940
|
+
break;
|
|
5929
5941
|
default: throw new Error(`Unknown trigger: ${trigger}`);
|
|
5930
5942
|
}
|
|
5931
5943
|
const target = executor.operation;
|
|
@@ -7200,6 +7212,10 @@ const warningChangeInfoSchema = z.looseObject({
|
|
|
7200
7212
|
fieldName: z.string().optional(),
|
|
7201
7213
|
reason: z.string()
|
|
7202
7214
|
});
|
|
7215
|
+
const scriptSkippedInfoSchema = z.looseObject({
|
|
7216
|
+
reason: z.string().trim().min(1),
|
|
7217
|
+
acknowledgedAt: z.string()
|
|
7218
|
+
});
|
|
7203
7219
|
const migrationDiffSchema = z.looseObject({
|
|
7204
7220
|
version: z.number(),
|
|
7205
7221
|
namespace: z.string(),
|
|
@@ -7210,7 +7226,8 @@ const migrationDiffSchema = z.looseObject({
|
|
|
7210
7226
|
breakingChanges: z.array(breakingChangeInfoSchema),
|
|
7211
7227
|
hasWarnings: z.boolean().optional(),
|
|
7212
7228
|
warnings: z.array(warningChangeInfoSchema).optional(),
|
|
7213
|
-
requiresMigrationScript: z.boolean()
|
|
7229
|
+
requiresMigrationScript: z.boolean(),
|
|
7230
|
+
scriptSkipped: scriptSkippedInfoSchema.optional()
|
|
7214
7231
|
});
|
|
7215
7232
|
|
|
7216
7233
|
//#endregion
|
|
@@ -7852,75 +7869,81 @@ function areFieldsDifferent(oldField, newField) {
|
|
|
7852
7869
|
return false;
|
|
7853
7870
|
}
|
|
7854
7871
|
/**
|
|
7855
|
-
*
|
|
7872
|
+
* Collect breaking changes for a field change
|
|
7856
7873
|
* @param {string} typeName - Name of the type containing the field
|
|
7857
7874
|
* @param {string} fieldName - Name of the field being changed
|
|
7858
7875
|
* @param {SnapshotFieldConfig | undefined} oldField - Old field configuration
|
|
7859
7876
|
* @param {SnapshotFieldConfig | undefined} newField - New field configuration
|
|
7860
|
-
* @returns {BreakingChangeInfo
|
|
7877
|
+
* @returns {BreakingChangeInfo[]} Breaking change information
|
|
7861
7878
|
*/
|
|
7862
|
-
function
|
|
7863
|
-
|
|
7879
|
+
function getBreakingFieldChanges(typeName, fieldName, oldField, newField) {
|
|
7880
|
+
const breakingChanges = [];
|
|
7881
|
+
if (!oldField && newField && newField.required) breakingChanges.push({
|
|
7864
7882
|
typeName,
|
|
7865
7883
|
fieldName,
|
|
7866
7884
|
reason: "Required field added"
|
|
7867
|
-
};
|
|
7868
|
-
if (oldField && newField && oldField.type !== newField.type)
|
|
7885
|
+
});
|
|
7886
|
+
if (oldField && newField && oldField.type !== newField.type) breakingChanges.push({
|
|
7869
7887
|
typeName,
|
|
7870
7888
|
fieldName,
|
|
7871
7889
|
reason: `Field type changed from ${oldField.type} to ${newField.type}`,
|
|
7872
7890
|
unsupported: true,
|
|
7873
7891
|
showThreeStepHint: true
|
|
7874
|
-
};
|
|
7875
|
-
if (oldField && newField && !oldField.required && newField.required)
|
|
7892
|
+
});
|
|
7893
|
+
if (oldField && newField && !oldField.required && newField.required) breakingChanges.push({
|
|
7876
7894
|
typeName,
|
|
7877
7895
|
fieldName,
|
|
7878
7896
|
reason: "Field changed from optional to required"
|
|
7879
|
-
};
|
|
7897
|
+
});
|
|
7880
7898
|
if (oldField && newField && (oldField.array ?? false) !== (newField.array ?? false)) {
|
|
7881
7899
|
const [fromType, toType] = oldField.array ? ["array", "single value"] : ["single value", "array"];
|
|
7882
|
-
|
|
7900
|
+
breakingChanges.push({
|
|
7883
7901
|
typeName,
|
|
7884
7902
|
fieldName,
|
|
7885
7903
|
reason: `Field changed from ${fromType} to ${toType}`,
|
|
7886
7904
|
unsupported: true,
|
|
7887
7905
|
showThreeStepHint: true
|
|
7888
|
-
};
|
|
7906
|
+
});
|
|
7889
7907
|
}
|
|
7890
7908
|
if (oldField && newField) {
|
|
7891
7909
|
const oldForeignKeyType = oldField.foreignKeyType;
|
|
7892
7910
|
const newForeignKeyType = newField.foreignKeyType;
|
|
7893
|
-
if (oldForeignKeyType && newForeignKeyType && oldForeignKeyType !== newForeignKeyType)
|
|
7911
|
+
if (oldForeignKeyType && newForeignKeyType && oldForeignKeyType !== newForeignKeyType) breakingChanges.push({
|
|
7894
7912
|
typeName,
|
|
7895
7913
|
fieldName,
|
|
7896
7914
|
reason: `Foreign key target type changed from ${oldForeignKeyType} to ${newForeignKeyType}`
|
|
7897
|
-
};
|
|
7915
|
+
});
|
|
7898
7916
|
}
|
|
7899
|
-
if (oldField && newField && !(oldField.unique ?? false) && (newField.unique ?? false))
|
|
7917
|
+
if (oldField && newField && !(oldField.unique ?? false) && (newField.unique ?? false)) breakingChanges.push({
|
|
7900
7918
|
typeName,
|
|
7901
7919
|
fieldName,
|
|
7902
7920
|
reason: "Unique constraint added to field"
|
|
7903
|
-
};
|
|
7921
|
+
});
|
|
7922
|
+
if (oldField?.type === "decimal" && newField?.type === "decimal" && oldField.scale !== newField.scale) breakingChanges.push({
|
|
7923
|
+
typeName,
|
|
7924
|
+
fieldName,
|
|
7925
|
+
reason: `Decimal scale changed from ${oldField.scale} to ${newField.scale}`
|
|
7926
|
+
});
|
|
7904
7927
|
if (oldField && newField && oldField.type === "enum" && newField.type === "enum") {
|
|
7905
7928
|
const oldAllowed = oldField.allowedValues ?? [];
|
|
7906
7929
|
const newAllowed = newField.allowedValues ?? [];
|
|
7907
7930
|
const oldValues = oldAllowed.map((v) => v.value);
|
|
7908
7931
|
const newValuesSet = new Set(newAllowed.map((v) => v.value));
|
|
7909
7932
|
const removedValues = oldValues.filter((v) => !newValuesSet.has(v));
|
|
7910
|
-
if (removedValues.length > 0)
|
|
7933
|
+
if (removedValues.length > 0) breakingChanges.push({
|
|
7911
7934
|
typeName,
|
|
7912
7935
|
fieldName,
|
|
7913
7936
|
reason: `Enum values removed: ${removedValues.join(", ")}`
|
|
7914
|
-
};
|
|
7937
|
+
});
|
|
7915
7938
|
}
|
|
7916
|
-
return
|
|
7939
|
+
return breakingChanges;
|
|
7917
7940
|
}
|
|
7918
7941
|
function addChange(ctx, change, oldField, newField) {
|
|
7919
7942
|
ctx.changes.push(change);
|
|
7920
7943
|
if (!change.fieldName) return;
|
|
7921
|
-
const
|
|
7922
|
-
if (
|
|
7923
|
-
ctx.breakingChanges.push(
|
|
7944
|
+
const breakingChanges = getBreakingFieldChanges(change.typeName, change.fieldName, oldField, newField);
|
|
7945
|
+
if (breakingChanges.length > 0) {
|
|
7946
|
+
ctx.breakingChanges.push(...breakingChanges);
|
|
7924
7947
|
return;
|
|
7925
7948
|
}
|
|
7926
7949
|
if (change.kind === "field_removed") ctx.warnings.push({
|
|
@@ -9855,8 +9878,9 @@ async function getCurrentMigrationNumber(client, workspaceId, namespace) {
|
|
|
9855
9878
|
const label = metadata?.labels[MIGRATION_LABEL_KEY];
|
|
9856
9879
|
if (!label) return 0;
|
|
9857
9880
|
return parseMigrationLabelNumber(label) ?? 0;
|
|
9858
|
-
} catch {
|
|
9859
|
-
return 0;
|
|
9881
|
+
} catch (error) {
|
|
9882
|
+
if (isNotFoundError(error)) return 0;
|
|
9883
|
+
throw error;
|
|
9860
9884
|
}
|
|
9861
9885
|
}
|
|
9862
9886
|
/**
|
|
@@ -9864,9 +9888,10 @@ async function getCurrentMigrationNumber(client, workspaceId, namespace) {
|
|
|
9864
9888
|
* @param {OperatorClient} client - Operator client instance
|
|
9865
9889
|
* @param {string} workspaceId - Workspace ID
|
|
9866
9890
|
* @param {NamespaceWithMigrations[]} namespacesWithMigrations - Namespaces with migrations config
|
|
9891
|
+
* @param {string} [configPath] - Config file path, included in remediation guidance when provided
|
|
9867
9892
|
* @returns {Promise<PendingMigration[]>} List of pending migrations
|
|
9868
9893
|
*/
|
|
9869
|
-
async function detectPendingMigrations(client, workspaceId, namespacesWithMigrations) {
|
|
9894
|
+
async function detectPendingMigrations(client, workspaceId, namespacesWithMigrations, configPath) {
|
|
9870
9895
|
const pendingMigrations = [];
|
|
9871
9896
|
for (const { namespace, migrationsDir } of namespacesWithMigrations) {
|
|
9872
9897
|
const currentMigration = await getCurrentMigrationNumber(client, workspaceId, namespace);
|
|
@@ -9878,9 +9903,15 @@ async function detectPendingMigrations(client, workspaceId, namespacesWithMigrat
|
|
|
9878
9903
|
const diff = loadDiff(diffPath);
|
|
9879
9904
|
const scriptPath = getMigrationFilePath(migrationsDir, file.number, "migrate");
|
|
9880
9905
|
const hasScript = fs$1.existsSync(scriptPath);
|
|
9881
|
-
if (diff.requiresMigrationScript && !hasScript) {
|
|
9882
|
-
|
|
9883
|
-
|
|
9906
|
+
if (diff.requiresMigrationScript && !hasScript && !diff.scriptSkipped) {
|
|
9907
|
+
const configArg = configPath ? ` --config "${path.relative(process.cwd(), configPath) || configPath}"` : "";
|
|
9908
|
+
const scriptCmd = `tailor-sdk tailordb migration script ${file.number} --namespace ${namespace}${configArg}`;
|
|
9909
|
+
throw new Error(`Migration ${namespace}/${formatMigrationNumber(file.number)} requires a migration script but migrate.ts was not found.\nTo resolve, either:\n - Add a script: ${scriptCmd}\n - Or record that no script is needed: ${scriptCmd} --no-script --reason "<why no data migration is needed>"`);
|
|
9910
|
+
}
|
|
9911
|
+
if (diff.scriptSkipped) {
|
|
9912
|
+
const migrationLabel = `${namespace}/${formatMigrationNumber(file.number)}`;
|
|
9913
|
+
if (hasScript) logger.warn(`Migration ${migrationLabel} has both a skip acknowledgment and migrate.ts; executing migrate.ts.`);
|
|
9914
|
+
else logger.info(`Migration ${migrationLabel} runs without a script (skip acknowledged at ${diff.scriptSkipped.acknowledgedAt}: ${diff.scriptSkipped.reason})`);
|
|
9884
9915
|
}
|
|
9885
9916
|
pendingMigrations.push({
|
|
9886
9917
|
number: file.number,
|
|
@@ -10177,6 +10208,38 @@ function formatRemoteVerificationResults(results) {
|
|
|
10177
10208
|
}
|
|
10178
10209
|
return lines.join("\n");
|
|
10179
10210
|
}
|
|
10211
|
+
const MIGRATION_FILE_KINDS = [
|
|
10212
|
+
"schema",
|
|
10213
|
+
"diff",
|
|
10214
|
+
"migrate",
|
|
10215
|
+
"db"
|
|
10216
|
+
];
|
|
10217
|
+
/**
|
|
10218
|
+
* Capture the migration files that a deployment plan depends on.
|
|
10219
|
+
* @param namespacesWithMigrations - Configured migration directories by namespace
|
|
10220
|
+
* @returns SHA-256 digest by namespace
|
|
10221
|
+
*/
|
|
10222
|
+
function captureMigrationFileState(namespacesWithMigrations) {
|
|
10223
|
+
const state = {};
|
|
10224
|
+
for (const { namespace, migrationsDir } of namespacesWithMigrations.toSorted((a, b) => a.namespace.localeCompare(b.namespace))) {
|
|
10225
|
+
const hash = createHash("sha256");
|
|
10226
|
+
const migrationNumbers = [...new Set(getMigrationFiles(migrationsDir).map(({ number }) => number))].toSorted((a, b) => a - b);
|
|
10227
|
+
for (const migrationNumber of migrationNumbers) for (const kind of MIGRATION_FILE_KINDS) {
|
|
10228
|
+
const filePath = getMigrationFilePath(migrationsDir, migrationNumber, kind);
|
|
10229
|
+
hash.update(`${formatMigrationNumber(migrationNumber)}/${kind}\0`);
|
|
10230
|
+
if (fs$1.existsSync(filePath)) hash.update(fs$1.readFileSync(filePath));
|
|
10231
|
+
else hash.update("<missing>");
|
|
10232
|
+
hash.update("\0");
|
|
10233
|
+
}
|
|
10234
|
+
state[namespace] = hash.digest("hex");
|
|
10235
|
+
}
|
|
10236
|
+
return state;
|
|
10237
|
+
}
|
|
10238
|
+
function migrationFileStatesEqual(planned, current) {
|
|
10239
|
+
const plannedNamespaces = Object.keys(planned).toSorted();
|
|
10240
|
+
const currentNamespaces = Object.keys(current).toSorted();
|
|
10241
|
+
return plannedNamespaces.length === currentNamespaces.length && plannedNamespaces.every((namespace, index) => namespace === currentNamespaces[index] && planned[namespace] === current[namespace]);
|
|
10242
|
+
}
|
|
10180
10243
|
/**
|
|
10181
10244
|
* Validate migration files and detect pending migrations
|
|
10182
10245
|
* @param {OperatorClient} client - Operator client instance
|
|
@@ -10222,19 +10285,20 @@ async function validateAndDetectMigrations(client, workspaceId, typesByNamespace
|
|
|
10222
10285
|
throw new Error("Remote schema verification failed");
|
|
10223
10286
|
}
|
|
10224
10287
|
}
|
|
10225
|
-
pendingMigrations = await detectPendingMigrations(client, workspaceId, namespacesWithMigrations);
|
|
10288
|
+
pendingMigrations = await detectPendingMigrations(client, workspaceId, namespacesWithMigrations, config.path);
|
|
10226
10289
|
if (pendingMigrations.length > 0) {
|
|
10227
10290
|
logger.newline();
|
|
10228
10291
|
const withScripts = pendingMigrations.filter((m) => m.hasScript);
|
|
10229
10292
|
const withoutScripts = pendingMigrations.filter((m) => !m.hasScript);
|
|
10230
|
-
logger.info(
|
|
10293
|
+
logger.info(`${pendingMigrations.length} pending migration(s) will be applied:`);
|
|
10231
10294
|
if (withoutScripts.length > 0) logger.info(` • ${withoutScripts.length} schema change(s) (applied automatically with schema deployment)`, { mode: "plain" });
|
|
10232
10295
|
if (withScripts.length > 0) logger.info(` • ${withScripts.length} data migration(s) (requires migration script execution)`, { mode: "plain" });
|
|
10233
10296
|
}
|
|
10234
10297
|
}
|
|
10235
10298
|
return {
|
|
10236
10299
|
pendingMigrations,
|
|
10237
|
-
namespacesWithMigrations
|
|
10300
|
+
namespacesWithMigrations,
|
|
10301
|
+
migrationFileState: captureMigrationFileState(namespacesWithMigrations)
|
|
10238
10302
|
};
|
|
10239
10303
|
}
|
|
10240
10304
|
/**
|
|
@@ -10282,6 +10346,22 @@ function buildMigrationContextForScripts(client, migrationContext, migrationsReq
|
|
|
10282
10346
|
configDir: path.dirname(migrationContext.config.path)
|
|
10283
10347
|
};
|
|
10284
10348
|
}
|
|
10349
|
+
async function validateTailorDBMigrationState(client, result) {
|
|
10350
|
+
const { context } = result;
|
|
10351
|
+
const typesByNamespace = /* @__PURE__ */ new Map();
|
|
10352
|
+
for (const tailordb of context.tailorDBInputs) typesByNamespace.set(tailordb.namespace, tailordb.types);
|
|
10353
|
+
const validation = await validateAndDetectMigrations(client, context.workspaceId, typesByNamespace, context.config, context.noSchemaCheck, context.tailorDBInputs);
|
|
10354
|
+
if (!migrationFileStatesEqual(context.migrationFileState, validation.migrationFileState)) throw new Error("Migration files changed after deployment planning. Run the deployment again to create a fresh plan.");
|
|
10355
|
+
return validation;
|
|
10356
|
+
}
|
|
10357
|
+
/**
|
|
10358
|
+
* Revalidate migration state before the deployment enters any mutation phase.
|
|
10359
|
+
* @param client - Operator client instance
|
|
10360
|
+
* @param result - Planned TailorDB changes
|
|
10361
|
+
*/
|
|
10362
|
+
async function preflightTailorDB(client, result) {
|
|
10363
|
+
await validateTailorDBMigrationState(client, result);
|
|
10364
|
+
}
|
|
10285
10365
|
/**
|
|
10286
10366
|
* Apply TailorDB-related changes for the given phase.
|
|
10287
10367
|
* @param client - Operator client instance
|
|
@@ -10291,9 +10371,7 @@ function buildMigrationContextForScripts(client, migrationContext, migrationsReq
|
|
|
10291
10371
|
async function applyTailorDB(client, result, phase = "create-update") {
|
|
10292
10372
|
const { changeSet, context: migrationContext } = result;
|
|
10293
10373
|
if (phase === "create-update") {
|
|
10294
|
-
const
|
|
10295
|
-
for (const tailordb of migrationContext.tailorDBInputs) typesByNamespace.set(tailordb.namespace, tailordb.types);
|
|
10296
|
-
const { pendingMigrations, namespacesWithMigrations } = await validateAndDetectMigrations(client, migrationContext.workspaceId, typesByNamespace, migrationContext.config, migrationContext.noSchemaCheck, migrationContext.tailorDBInputs);
|
|
10374
|
+
const { pendingMigrations, namespacesWithMigrations } = await validateTailorDBMigrationState(client, result);
|
|
10297
10375
|
if (pendingMigrations.length > 0) {
|
|
10298
10376
|
processedTypes.reset();
|
|
10299
10377
|
deletedResources.reset();
|
|
@@ -10701,6 +10779,12 @@ async function planTailorDB(context) {
|
|
|
10701
10779
|
const executors = forRemoval ? [] : Object.values(await application.executorService?.loadExecutors() ?? {});
|
|
10702
10780
|
const executorUsedTypes = new Set(context.executorUsedTailorDBTypes ?? []);
|
|
10703
10781
|
for (const executor of executors) if (executor.trigger.kind === "tailordb") executorUsedTypes.add(executor.trigger.typeName);
|
|
10782
|
+
const typesByNamespace = /* @__PURE__ */ new Map();
|
|
10783
|
+
for (const tailordb of tailordbs) typesByNamespace.set(tailordb.namespace, tailordb.types);
|
|
10784
|
+
const { namespacesWithMigrations, migrationFileState } = forRemoval ? {
|
|
10785
|
+
namespacesWithMigrations: [],
|
|
10786
|
+
migrationFileState: {}
|
|
10787
|
+
} : await validateAndDetectMigrations(client, workspaceId, typesByNamespace, config, noSchemaCheck ?? false, tailordbs);
|
|
10704
10788
|
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices(client, workspaceId, application.name, application.id, tailordbs);
|
|
10705
10789
|
const deletedServices = serviceChangeSet.deletes.map((del) => del.name);
|
|
10706
10790
|
const [typeChangeSet, gqlPermissionChangeSet] = await Promise.all([planTypes(client, workspaceId, tailordbs, executorUsedTypes, deletedServices, void 0, forceApplyAll), planGqlPermissions(client, workspaceId, tailordbs, deletedServices, forceApplyAll)]);
|
|
@@ -10722,7 +10806,9 @@ async function planTailorDB(context) {
|
|
|
10722
10806
|
tailorDBInputs: tailordbs,
|
|
10723
10807
|
executorUsedTypes,
|
|
10724
10808
|
config,
|
|
10725
|
-
noSchemaCheck: noSchemaCheck ?? false
|
|
10809
|
+
noSchemaCheck: noSchemaCheck ?? false,
|
|
10810
|
+
namespacesWithMigrations,
|
|
10811
|
+
migrationFileState
|
|
10726
10812
|
}
|
|
10727
10813
|
};
|
|
10728
10814
|
}
|
|
@@ -11134,7 +11220,7 @@ function formatMigrationCheckResults(results) {
|
|
|
11134
11220
|
async function applyWorkflow(client, result, phase = "create-update") {
|
|
11135
11221
|
const { changeSet, appName, appId } = result;
|
|
11136
11222
|
if (phase === "create-update") {
|
|
11137
|
-
const jobFunctionVersions = await registerJobFunctions(client, changeSet, appName, appId, result.unchangedWorkflowJobNames);
|
|
11223
|
+
const jobFunctionVersions = await registerJobFunctions(client, changeSet, appName, appId, result.unchangedWorkflowJobNames, result.jobFunctionPublishEvents);
|
|
11138
11224
|
await Promise.all([...changeSet.creates.map(async (create) => {
|
|
11139
11225
|
const filteredVersions = filterJobFunctionVersions(jobFunctionVersions, create.usedJobNames);
|
|
11140
11226
|
const shape = buildWorkflowValidationShape(create.workspaceId, create.workflow);
|
|
@@ -11144,7 +11230,8 @@ async function applyWorkflow(client, result, phase = "create-update") {
|
|
|
11144
11230
|
mainJobFunctionName: shape.mainJobFunctionName,
|
|
11145
11231
|
retryPolicy: shape.retryPolicy,
|
|
11146
11232
|
concurrencyPolicy: shape.concurrencyPolicy,
|
|
11147
|
-
jobFunctions: filteredVersions
|
|
11233
|
+
jobFunctions: filteredVersions,
|
|
11234
|
+
publishExecutionEvents: shape.publishExecutionEvents
|
|
11148
11235
|
});
|
|
11149
11236
|
await client.setMetadata(create.metaRequest);
|
|
11150
11237
|
}), ...changeSet.updates.map(async (update) => {
|
|
@@ -11156,7 +11243,8 @@ async function applyWorkflow(client, result, phase = "create-update") {
|
|
|
11156
11243
|
mainJobFunctionName: shape.mainJobFunctionName,
|
|
11157
11244
|
retryPolicy: shape.retryPolicy,
|
|
11158
11245
|
concurrencyPolicy: shape.concurrencyPolicy,
|
|
11159
|
-
jobFunctions: filteredVersions
|
|
11246
|
+
jobFunctions: filteredVersions,
|
|
11247
|
+
publishExecutionEvents: shape.publishExecutionEvents
|
|
11160
11248
|
});
|
|
11161
11249
|
await client.setMetadata(update.metaRequest);
|
|
11162
11250
|
})]);
|
|
@@ -11217,9 +11305,10 @@ function filterJobFunctionVersions(allVersions, usedJobNames) {
|
|
|
11217
11305
|
* @param appName - Application name
|
|
11218
11306
|
* @param appId - Application ID used for job function metadata when available
|
|
11219
11307
|
* @param unchangedWorkflowJobNames - Job function names used by unchanged workflows
|
|
11308
|
+
* @param jobFunctionPublishEvents - Resolved `publishExecutionEvents` keyed by job function name
|
|
11220
11309
|
* @returns Map of job function names to versions
|
|
11221
11310
|
*/
|
|
11222
|
-
async function registerJobFunctions(client, changeSet, appName, appId, unchangedWorkflowJobNames = /* @__PURE__ */ new Set()) {
|
|
11311
|
+
async function registerJobFunctions(client, changeSet, appName, appId, unchangedWorkflowJobNames = /* @__PURE__ */ new Set(), jobFunctionPublishEvents = /* @__PURE__ */ new Map()) {
|
|
11223
11312
|
const jobFunctionVersions = {};
|
|
11224
11313
|
const firstWorkflow = changeSet.creates[0] || changeSet.updates[0] || changeSet.deletes[0];
|
|
11225
11314
|
if (!firstWorkflow) return jobFunctionVersions;
|
|
@@ -11238,15 +11327,14 @@ async function registerJobFunctions(client, changeSet, appName, appId, unchanged
|
|
|
11238
11327
|
const existingJobNamesSet = new Set(existingJobFunctions);
|
|
11239
11328
|
if (changeSet.creates.length > 0 || changeSet.updates.length > 0) {
|
|
11240
11329
|
const results = await Promise.all(Array.from(allUsedJobNames).map(async (jobName) => {
|
|
11241
|
-
const
|
|
11242
|
-
|
|
11243
|
-
jobFunctionName: jobName,
|
|
11244
|
-
scriptRef: workflowJobFunctionName(jobName)
|
|
11245
|
-
}) : await client.createWorkflowJobFunction({
|
|
11330
|
+
const isExisting = existingJobNamesSet.has(jobName);
|
|
11331
|
+
const request = {
|
|
11246
11332
|
workspaceId,
|
|
11247
11333
|
jobFunctionName: jobName,
|
|
11248
|
-
scriptRef: workflowJobFunctionName(jobName)
|
|
11249
|
-
|
|
11334
|
+
scriptRef: workflowJobFunctionName(jobName),
|
|
11335
|
+
publishExecutionEvents: jobFunctionPublishEvents.get(jobName) ?? false
|
|
11336
|
+
};
|
|
11337
|
+
const response = isExisting ? await client.updateWorkflowJobFunction(request) : await client.createWorkflowJobFunction(request);
|
|
11250
11338
|
await client.setMetadata(await buildMetaRequest({
|
|
11251
11339
|
trn: resourceTrn(workspaceId, "workflow_job_function", jobName),
|
|
11252
11340
|
appName,
|
|
@@ -11293,9 +11381,64 @@ function buildWorkflowValidationShape(workspaceId, workflow) {
|
|
|
11293
11381
|
workflowName: workflow.name,
|
|
11294
11382
|
mainJobFunctionName: workflow.mainJob.name,
|
|
11295
11383
|
...workflow.retryPolicy && { retryPolicy: toRetryPolicy(workflow.retryPolicy) },
|
|
11296
|
-
...workflow.concurrencyPolicy && { concurrencyPolicy: toConcurrencyPolicy(workflow.concurrencyPolicy) }
|
|
11384
|
+
...workflow.concurrencyPolicy && { concurrencyPolicy: toConcurrencyPolicy(workflow.concurrencyPolicy) },
|
|
11385
|
+
publishExecutionEvents: workflow.publishEvents ?? false
|
|
11297
11386
|
};
|
|
11298
11387
|
}
|
|
11388
|
+
const NO_EVENT_SUBSCRIBERS = { workflowNames: /* @__PURE__ */ new Set() };
|
|
11389
|
+
function isSubscribed(subscribers, workflowName) {
|
|
11390
|
+
return subscribers.workflowNames.has(workflowName);
|
|
11391
|
+
}
|
|
11392
|
+
function resolvePublishEvents(params) {
|
|
11393
|
+
const { explicit, subscribed, remote, conflictError } = params;
|
|
11394
|
+
if (explicit === false && subscribed) throw new Error(conflictError);
|
|
11395
|
+
if (explicit !== void 0) return explicit;
|
|
11396
|
+
return subscribed || (remote ?? false);
|
|
11397
|
+
}
|
|
11398
|
+
/**
|
|
11399
|
+
* Resolve `publishExecutionEvents` for every job function used by a workflow.
|
|
11400
|
+
*
|
|
11401
|
+
* A job execution trigger names a workflow rather than a job, so a subscription
|
|
11402
|
+
* opts in every job that workflow runs.
|
|
11403
|
+
* @param params - Workflows, their job dependencies, subscribers, explicit job flags, and existing job functions
|
|
11404
|
+
* @returns Resolved flags keyed by job function name
|
|
11405
|
+
*/
|
|
11406
|
+
function resolveJobPublishEvents(params) {
|
|
11407
|
+
const { workflows, mainJobDeps, subscribers, explicit, existing } = params;
|
|
11408
|
+
const usedJobNames = /* @__PURE__ */ new Set();
|
|
11409
|
+
const subscribedJobNames = /* @__PURE__ */ new Set();
|
|
11410
|
+
for (const workflow of Object.values(workflows)) {
|
|
11411
|
+
const jobNames = mainJobDeps[workflow.mainJob.name];
|
|
11412
|
+
if (!jobNames) continue;
|
|
11413
|
+
const subscribed = isSubscribed(subscribers, workflow.name);
|
|
11414
|
+
for (const jobName of jobNames) {
|
|
11415
|
+
usedJobNames.add(jobName);
|
|
11416
|
+
if (subscribed) subscribedJobNames.add(jobName);
|
|
11417
|
+
}
|
|
11418
|
+
}
|
|
11419
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
11420
|
+
for (const jobName of usedJobNames) resolved.set(jobName, resolvePublishEvents({
|
|
11421
|
+
explicit: explicit.get(jobName),
|
|
11422
|
+
subscribed: subscribedJobNames.has(jobName),
|
|
11423
|
+
remote: existing.get(jobName)?.publishExecutionEvents,
|
|
11424
|
+
conflictError: `Job "${jobName}" has "publishEvents: false", but executors with a workflowJobExecution trigger subscribe to a workflow that runs it. Either remove "publishEvents: false" or remove the matching executor triggers.`
|
|
11425
|
+
}));
|
|
11426
|
+
return resolved;
|
|
11427
|
+
}
|
|
11428
|
+
/**
|
|
11429
|
+
* Collect job functions whose remote publishing flag no longer matches the plan.
|
|
11430
|
+
* @param existing - Existing job functions keyed by name
|
|
11431
|
+
* @param resolved - Resolved `publishExecutionEvents` keyed by job function name
|
|
11432
|
+
* @returns Job function names needing re-registration
|
|
11433
|
+
*/
|
|
11434
|
+
function collectStaleJobFunctionNames(existing, resolved) {
|
|
11435
|
+
const stale = /* @__PURE__ */ new Set();
|
|
11436
|
+
for (const [jobName, publishEvents] of resolved) {
|
|
11437
|
+
const remote = existing.get(jobName);
|
|
11438
|
+
if (remote && remote.publishExecutionEvents !== publishEvents) stale.add(jobName);
|
|
11439
|
+
}
|
|
11440
|
+
return stale;
|
|
11441
|
+
}
|
|
11299
11442
|
/**
|
|
11300
11443
|
* Plan workflow changes and job functions based on current and desired state.
|
|
11301
11444
|
* @param client - Operator client instance
|
|
@@ -11305,15 +11448,26 @@ function buildWorkflowValidationShape(workspaceId, workflow) {
|
|
|
11305
11448
|
* @param workflows - Parsed workflows
|
|
11306
11449
|
* @param mainJobDeps - Main job dependencies by workflow
|
|
11307
11450
|
* @param unchangedJobFunctions - Job functions already proven unchanged by function registry plan
|
|
11451
|
+
* @param eventPublishing - Executor subscriptions and explicit job flags driving execution event publishing
|
|
11308
11452
|
* @returns Planned workflow changes
|
|
11309
11453
|
*/
|
|
11310
|
-
async function planWorkflow(client, workspaceId, appName, appId, workflows, mainJobDeps, unchangedJobFunctions = /* @__PURE__ */ new Set()) {
|
|
11454
|
+
async function planWorkflow(client, workspaceId, appName, appId, workflows, mainJobDeps, unchangedJobFunctions = /* @__PURE__ */ new Set(), eventPublishing = {}) {
|
|
11311
11455
|
const changeSet = createChangeSet("Workflows");
|
|
11312
11456
|
const conflicts = [];
|
|
11313
11457
|
const unmanaged = [];
|
|
11314
11458
|
const resourceOwners = /* @__PURE__ */ new Set();
|
|
11315
11459
|
const unchangedWorkflowJobNames = /* @__PURE__ */ new Set();
|
|
11316
11460
|
const retainedWorkflowJobNames = /* @__PURE__ */ new Set();
|
|
11461
|
+
const executionSubscribers = eventPublishing.execution ?? NO_EVENT_SUBSCRIBERS;
|
|
11462
|
+
const existingJobFunctions = await fetchExistingJobFunctions(client, workspaceId);
|
|
11463
|
+
const jobFunctionPublishEvents = resolveJobPublishEvents({
|
|
11464
|
+
workflows,
|
|
11465
|
+
mainJobDeps,
|
|
11466
|
+
subscribers: eventPublishing.jobExecution ?? NO_EVENT_SUBSCRIBERS,
|
|
11467
|
+
explicit: eventPublishing.jobPublishEvents ?? /* @__PURE__ */ new Map(),
|
|
11468
|
+
existing: existingJobFunctions
|
|
11469
|
+
});
|
|
11470
|
+
const staleJobFunctionNames = collectStaleJobFunctionNames(existingJobFunctions, jobFunctionPublishEvents);
|
|
11317
11471
|
const existingWorkflows = await fetchExistingResourcesWithLabels({
|
|
11318
11472
|
client,
|
|
11319
11473
|
fetchPage: async (pageToken, pageSize) => {
|
|
@@ -11337,6 +11491,15 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
|
|
|
11337
11491
|
const usedJobNames = mainJobDeps[workflow.mainJob.name];
|
|
11338
11492
|
if (!usedJobNames) throw new Error(`Job "${workflow.mainJob.name}" (mainJob of workflow "${workflow.name}") was not found.\n\nPossible causes:\n - The job is not exported as a named export\n - The file containing the job is not included in workflow.files glob pattern\n\nSolution:\n export const ${workflow.mainJob.name} = createWorkflowJob({ name: "${workflow.mainJob.name}", ... })`);
|
|
11339
11493
|
usedJobNames.forEach((jobName) => retainedWorkflowJobNames.add(jobName));
|
|
11494
|
+
const desiredWorkflow = {
|
|
11495
|
+
...workflow,
|
|
11496
|
+
publishEvents: resolvePublishEvents({
|
|
11497
|
+
explicit: workflow.publishEvents,
|
|
11498
|
+
subscribed: isSubscribed(executionSubscribers, workflow.name),
|
|
11499
|
+
remote: existing?.resource.publishExecutionEvents,
|
|
11500
|
+
conflictError: `Workflow "${workflow.name}" has "publishEvents: false", but executors with a workflowExecution trigger subscribe to it. Either remove "publishEvents: false" or remove the matching executor triggers.`
|
|
11501
|
+
})
|
|
11502
|
+
};
|
|
11340
11503
|
if (existing) {
|
|
11341
11504
|
if (trackDesiredResourceOwnership({
|
|
11342
11505
|
labels: existing.allLabels,
|
|
@@ -11347,13 +11510,19 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
|
|
|
11347
11510
|
resourceName: workflow.name,
|
|
11348
11511
|
conflicts,
|
|
11349
11512
|
unmanaged
|
|
11350
|
-
}) && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && canTreatWorkflowAsUnchanged(
|
|
11513
|
+
}) && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && canTreatWorkflowAsUnchanged({
|
|
11514
|
+
existing: existing.resource,
|
|
11515
|
+
workflow: desiredWorkflow,
|
|
11516
|
+
usedJobNames,
|
|
11517
|
+
unchangedJobFunctions,
|
|
11518
|
+
staleJobFunctionNames
|
|
11519
|
+
})) {
|
|
11351
11520
|
changeSet.unchanged.push({ name: workflow.name });
|
|
11352
11521
|
for (const jobName of usedJobNames) unchangedWorkflowJobNames.add(jobName);
|
|
11353
11522
|
} else changeSet.updates.push({
|
|
11354
11523
|
name: workflow.name,
|
|
11355
11524
|
workspaceId,
|
|
11356
|
-
workflow,
|
|
11525
|
+
workflow: desiredWorkflow,
|
|
11357
11526
|
usedJobNames,
|
|
11358
11527
|
metaRequest
|
|
11359
11528
|
});
|
|
@@ -11361,7 +11530,7 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
|
|
|
11361
11530
|
} else changeSet.creates.push({
|
|
11362
11531
|
name: workflow.name,
|
|
11363
11532
|
workspaceId,
|
|
11364
|
-
workflow,
|
|
11533
|
+
workflow: desiredWorkflow,
|
|
11365
11534
|
usedJobNames,
|
|
11366
11535
|
metaRequest
|
|
11367
11536
|
});
|
|
@@ -11391,6 +11560,7 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
|
|
|
11391
11560
|
workspaceId,
|
|
11392
11561
|
appName,
|
|
11393
11562
|
appId,
|
|
11563
|
+
existingJobFunctionNames: [...existingJobFunctions.keys()],
|
|
11394
11564
|
retainedWorkflowJobNames
|
|
11395
11565
|
});
|
|
11396
11566
|
const deletableJobNames = new Set(jobFunctionDeletes.map((del) => del.jobFunctionName));
|
|
@@ -11406,20 +11576,24 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
|
|
|
11406
11576
|
appName,
|
|
11407
11577
|
appId,
|
|
11408
11578
|
unchangedWorkflowJobNames,
|
|
11409
|
-
jobFunctionDeletes
|
|
11579
|
+
jobFunctionDeletes,
|
|
11580
|
+
jobFunctionPublishEvents
|
|
11410
11581
|
};
|
|
11411
11582
|
}
|
|
11412
|
-
async function
|
|
11413
|
-
const
|
|
11414
|
-
const existingJobFunctions = await fetchAll(async (pageToken, maxPageSize) => {
|
|
11583
|
+
async function fetchExistingJobFunctions(client, workspaceId) {
|
|
11584
|
+
const jobFunctions = await fetchAll(async (pageToken, maxPageSize) => {
|
|
11415
11585
|
const response = await client.listWorkflowJobFunctions({
|
|
11416
11586
|
workspaceId,
|
|
11417
11587
|
pageToken,
|
|
11418
11588
|
pageSize: maxPageSize
|
|
11419
11589
|
});
|
|
11420
|
-
return [response.jobFunctions
|
|
11590
|
+
return [response.jobFunctions, response.nextPageToken];
|
|
11421
11591
|
});
|
|
11422
|
-
|
|
11592
|
+
return new Map(jobFunctions.map((jobFunction) => [jobFunction.name, jobFunction]));
|
|
11593
|
+
}
|
|
11594
|
+
async function planWorkflowJobFunctionDeletes(params) {
|
|
11595
|
+
const { client, workspaceId, appName, appId, existingJobFunctionNames, retainedWorkflowJobNames } = params;
|
|
11596
|
+
const candidates = existingJobFunctionNames.filter((jobName) => !retainedWorkflowJobNames.has(jobName));
|
|
11423
11597
|
return (await Promise.all(candidates.map(async (jobFunctionName) => {
|
|
11424
11598
|
const { metadata } = await client.getMetadata({ trn: resourceTrn(workspaceId, "workflow_job_function", jobFunctionName) });
|
|
11425
11599
|
return isOwnedByApp(metadata?.labels, appName, appId) ? {
|
|
@@ -11437,12 +11611,14 @@ async function planWorkflowJobFunctionDeletes(params) {
|
|
|
11437
11611
|
function formatWorkflowChangeEntries(changeSet, workflowJobFunctionChanges) {
|
|
11438
11612
|
return formatChangeEntriesWithFunctionRegistry("workflow", changeSet, workflowJobFunctionChanges, (item) => "usedJobNames" in item ? item.usedJobNames.map((jobName) => workflowJobFunctionName(jobName)) : []);
|
|
11439
11613
|
}
|
|
11440
|
-
function canTreatWorkflowAsUnchanged(
|
|
11614
|
+
function canTreatWorkflowAsUnchanged(params) {
|
|
11615
|
+
const { existing, workflow, usedJobNames, unchangedJobFunctions, staleJobFunctionNames } = params;
|
|
11441
11616
|
if (!usedJobNames.every((jobName) => unchangedJobFunctions.has(jobName))) return false;
|
|
11617
|
+
if (usedJobNames.some((jobName) => staleJobFunctionNames.has(jobName))) return false;
|
|
11442
11618
|
return areWorkflowsEqual(existing, workflow, usedJobNames);
|
|
11443
11619
|
}
|
|
11444
11620
|
function areWorkflowsEqual(existing, workflow, usedJobNames) {
|
|
11445
|
-
return existing.mainJobFunctionName === workflow.mainJob.name && areNormalizedEqual(normalizeComparableExistingWorkflowRetryPolicy(existing.retryPolicy), normalizeComparableWorkflowRetryPolicy(workflow.retryPolicy)) && areNormalizedEqual(normalizeComparableConcurrencyPolicy(existing.concurrencyPolicy), normalizeComparableConcurrencyPolicy(workflow.concurrencyPolicy)) && areNormalizedEqual(normalizeComparableWorkflowJobNames(existing.jobFunctions), normalizeComparableWorkflowJobNames(usedJobNames));
|
|
11621
|
+
return existing.mainJobFunctionName === workflow.mainJob.name && (existing.publishExecutionEvents ?? false) === (workflow.publishEvents ?? false) && areNormalizedEqual(normalizeComparableExistingWorkflowRetryPolicy(existing.retryPolicy), normalizeComparableWorkflowRetryPolicy(workflow.retryPolicy)) && areNormalizedEqual(normalizeComparableConcurrencyPolicy(existing.concurrencyPolicy), normalizeComparableConcurrencyPolicy(workflow.concurrencyPolicy)) && areNormalizedEqual(normalizeComparableWorkflowJobNames(existing.jobFunctions), normalizeComparableWorkflowJobNames(usedJobNames));
|
|
11446
11622
|
}
|
|
11447
11623
|
function normalizeComparableExistingWorkflowRetryPolicy(policy) {
|
|
11448
11624
|
if (!policy) return;
|
|
@@ -11699,6 +11875,9 @@ async function applyDeploymentPlans(client, workspaceId, deployments) {
|
|
|
11699
11875
|
const forEachDeployment = async (apply) => {
|
|
11700
11876
|
for (const deployment of deployments) await apply(deployment);
|
|
11701
11877
|
};
|
|
11878
|
+
await withSpan("apply.preflight", async () => {
|
|
11879
|
+
await forEachDeployment((d) => preflightTailorDB(client, d.tailorDB));
|
|
11880
|
+
});
|
|
11702
11881
|
await withSpan("apply.createUpdateServices", async () => {
|
|
11703
11882
|
await forEachDeployment((d) => applySecretManager(client, d.secretManager, "create-update", d.application));
|
|
11704
11883
|
await forEachDeployment((d) => applyFunctionRegistry(client, workspaceId, d.functionRegistry, "create-update"));
|
|
@@ -13137,6 +13316,39 @@ function collectExecutorUsedResolvers(owner, targets) {
|
|
|
13137
13316
|
}
|
|
13138
13317
|
return usedResolvers;
|
|
13139
13318
|
}
|
|
13319
|
+
/**
|
|
13320
|
+
* Resolve which workflows this target's executors subscribe to, per event
|
|
13321
|
+
* granularity level.
|
|
13322
|
+
*
|
|
13323
|
+
* Scoped to the owning target: unlike TailorDB, Auth and IdP, a workflow has no
|
|
13324
|
+
* `external` declaration, so no supported configuration shares a workflow and a
|
|
13325
|
+
* subscribing executor across configs.
|
|
13326
|
+
* @param target - Deployment target being planned
|
|
13327
|
+
* @returns Subscribers keyed by event granularity level
|
|
13328
|
+
*/
|
|
13329
|
+
function collectWorkflowEventSubscribers(target) {
|
|
13330
|
+
const execution = { workflowNames: /* @__PURE__ */ new Set() };
|
|
13331
|
+
const jobExecution = { workflowNames: /* @__PURE__ */ new Set() };
|
|
13332
|
+
for (const executor of Object.values(target.application.executorService?.executors ?? {})) {
|
|
13333
|
+
const { trigger } = executor;
|
|
13334
|
+
if (trigger.kind !== "workflowExecution" && trigger.kind !== "workflowJobExecution") continue;
|
|
13335
|
+
(trigger.kind === "workflowExecution" ? execution : jobExecution).workflowNames.add(trigger.workflowName);
|
|
13336
|
+
}
|
|
13337
|
+
return {
|
|
13338
|
+
execution,
|
|
13339
|
+
jobExecution
|
|
13340
|
+
};
|
|
13341
|
+
}
|
|
13342
|
+
/**
|
|
13343
|
+
* Collect explicit `publishEvents` values declared on this target's workflow jobs.
|
|
13344
|
+
* @param target - Deployment target being planned
|
|
13345
|
+
* @returns Explicit flags keyed by job name
|
|
13346
|
+
*/
|
|
13347
|
+
function collectWorkflowJobPublishEvents(target) {
|
|
13348
|
+
const jobPublishEvents = /* @__PURE__ */ new Map();
|
|
13349
|
+
for (const job of target.application.workflowService?.jobs ?? []) if (job.publishEvents !== void 0) jobPublishEvents.set(job.name, job.publishEvents);
|
|
13350
|
+
return jobPublishEvents;
|
|
13351
|
+
}
|
|
13140
13352
|
function collectExpectedLocalStaticWebsiteNames(targets) {
|
|
13141
13353
|
const websiteNames = /* @__PURE__ */ new Set();
|
|
13142
13354
|
for (const target of targets) for (const website of target.application.staticWebsiteServices) websiteNames.add(website.name);
|
|
@@ -13738,7 +13950,10 @@ async function planDeploymentTarget(params) {
|
|
|
13738
13950
|
withSpan("plan.pipeline", () => planPipeline(ctx)),
|
|
13739
13951
|
withSpan("plan.application", () => planApplication(ctx, httpAdapterBuildResult)),
|
|
13740
13952
|
withSpan("plan.executor", () => planExecutor(ctx)),
|
|
13741
|
-
withSpan("plan.workflow", () => planWorkflow(client, workspaceId, application.name, application.id, workflowService?.workflows ?? {}, workflowBuildResult?.mainJobDeps ?? {}, unchangedWorkflowJobs
|
|
13953
|
+
withSpan("plan.workflow", () => planWorkflow(client, workspaceId, application.name, application.id, workflowService?.workflows ?? {}, workflowBuildResult?.mainJobDeps ?? {}, unchangedWorkflowJobs, {
|
|
13954
|
+
...collectWorkflowEventSubscribers(target),
|
|
13955
|
+
jobPublishEvents: collectWorkflowJobPublishEvents(target)
|
|
13956
|
+
})),
|
|
13742
13957
|
withSpan("plan.workflowExecutionPolicy", () => planWorkflowJobFunctionExecutionPolicy(client, workspaceId, application.name, application.id, config.workflow?.executionPolicies ?? {})),
|
|
13743
13958
|
withSpan("plan.secretManager", () => planSecretManager(ctx))
|
|
13744
13959
|
]);
|
|
@@ -14553,6 +14768,12 @@ function formatEventTriggerConfig(config) {
|
|
|
14553
14768
|
eventType: config.eventType,
|
|
14554
14769
|
condition: config.condition?.expr || ""
|
|
14555
14770
|
};
|
|
14771
|
+
if (typedConfig.case === "workflow") return {
|
|
14772
|
+
kind: typedConfig.case,
|
|
14773
|
+
eventTypes: typedConfig.value.eventTypes,
|
|
14774
|
+
condition: typedConfig.value.condition?.expr || "",
|
|
14775
|
+
...typedConfig.value.workflowName && { workflowName: typedConfig.value.workflowName }
|
|
14776
|
+
};
|
|
14556
14777
|
const base = {
|
|
14557
14778
|
kind: typedConfig.case,
|
|
14558
14779
|
eventTypes: typedConfig.value.eventTypes,
|
|
@@ -18860,8 +19081,13 @@ async function generateDiffFiles(diff, migrationsDir, migrationNumber, previousS
|
|
|
18860
19081
|
function generateMigrationScript(diff) {
|
|
18861
19082
|
const updates = [];
|
|
18862
19083
|
for (const change of diff.changes) {
|
|
18863
|
-
const
|
|
18864
|
-
|
|
19084
|
+
const decimalScaleScript = generateDecimalScaleChangeScript(change);
|
|
19085
|
+
updates.push(...generateChangeScripts(change, decimalScaleScript !== null));
|
|
19086
|
+
if (decimalScaleScript) {
|
|
19087
|
+
updates.push(decimalScaleScript);
|
|
19088
|
+
const uniqueConstraintScript = generateUniqueConstraintScript(change);
|
|
19089
|
+
if (uniqueConstraintScript) updates.push(uniqueConstraintScript);
|
|
19090
|
+
}
|
|
18865
19091
|
}
|
|
18866
19092
|
if (updates.length === 0) updates.push(` // No data migration needed for this schema change
|
|
18867
19093
|
// Add custom data transformations if required`);
|
|
@@ -18886,18 +19112,19 @@ ${updates.join("\n\n")}
|
|
|
18886
19112
|
`;
|
|
18887
19113
|
}
|
|
18888
19114
|
/**
|
|
18889
|
-
* Generate
|
|
19115
|
+
* Generate scripts for a single change
|
|
18890
19116
|
* @param {DiffChange} change - Diff change to generate script for
|
|
18891
|
-
* @
|
|
19117
|
+
* @param {boolean} deferUniqueConstraint - Generate the unique check after decimal re-serialization
|
|
19118
|
+
* @returns {string[]} Script contents, or an empty array if no script is needed
|
|
18892
19119
|
*/
|
|
18893
|
-
function
|
|
19120
|
+
function generateChangeScripts(change, deferUniqueConstraint = false) {
|
|
18894
19121
|
if (change.kind === "index_added" || change.kind === "index_modified") {
|
|
18895
19122
|
const before = change.kind === "index_modified" ? change.before : void 0;
|
|
18896
|
-
if (!isBreakingIndexChange(change.typeName, change.indexName, before, change.after)) return
|
|
19123
|
+
if (!isBreakingIndexChange(change.typeName, change.indexName, before, change.after)) return [];
|
|
18897
19124
|
const fields = change.after.fields;
|
|
18898
19125
|
const fieldList = fields.map((f) => `"${f}"`).join(", ");
|
|
18899
19126
|
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
|
|
19127
|
+
return [` // Resolve duplicate (${fields.join(", ")}) combinations before unique index "${change.indexName}" is enforced
|
|
18901
19128
|
{
|
|
18902
19129
|
const duplicates = await trx
|
|
18903
19130
|
.selectFrom("${change.typeName}")
|
|
@@ -18920,81 +19147,135 @@ function generateChangeScript(change) {
|
|
|
18920
19147
|
.execute();
|
|
18921
19148
|
}
|
|
18922
19149
|
}
|
|
18923
|
-
}
|
|
19150
|
+
}`];
|
|
18924
19151
|
}
|
|
18925
19152
|
if (change.kind === "field_added") {
|
|
18926
|
-
if (change.after.required) return ` // Populate ${change.fieldName} for existing ${change.typeName} records
|
|
19153
|
+
if (change.after.required) return [` // Populate ${change.fieldName} for existing ${change.typeName} records
|
|
18927
19154
|
await trx
|
|
18928
19155
|
.updateTable("${change.typeName}")
|
|
18929
19156
|
.set({
|
|
18930
19157
|
${change.fieldName}: null, // TODO: Set appropriate default value
|
|
18931
19158
|
})
|
|
18932
|
-
.execute()
|
|
18933
|
-
return
|
|
19159
|
+
.execute();`];
|
|
19160
|
+
return [];
|
|
18934
19161
|
}
|
|
18935
|
-
if (change.kind !== "field_modified") return
|
|
19162
|
+
if (change.kind !== "field_modified") return [];
|
|
18936
19163
|
const { before, after } = change;
|
|
18937
|
-
|
|
19164
|
+
const scripts = [];
|
|
19165
|
+
if (!before.required && after.required) scripts.push(` // Set ${change.fieldName} for ${change.typeName} records where it is null
|
|
18938
19166
|
await trx
|
|
18939
19167
|
.updateTable("${change.typeName}")
|
|
18940
19168
|
.set({
|
|
18941
19169
|
${change.fieldName}: null, // TODO: Set appropriate default value
|
|
18942
19170
|
})
|
|
18943
19171
|
.where("${change.fieldName}", "is", null)
|
|
18944
|
-
.execute()
|
|
18945
|
-
if (!
|
|
18946
|
-
|
|
18947
|
-
|
|
18948
|
-
|
|
18949
|
-
.groupBy("${change.fieldName}")
|
|
18950
|
-
.having((eb) => eb.fn.count("id"), ">", 1)
|
|
18951
|
-
.execute();
|
|
18952
|
-
for (const dup of duplicates) {
|
|
18953
|
-
// Keep first record, add suffix to others
|
|
18954
|
-
const records = await trx
|
|
18955
|
-
.selectFrom("${change.typeName}")
|
|
18956
|
-
.select(["id", "${change.fieldName}"])
|
|
18957
|
-
.where("${change.fieldName}", "=", dup.${change.fieldName})
|
|
18958
|
-
.execute();
|
|
18959
|
-
for (let i = 1; i < records.length; i++) {
|
|
18960
|
-
await trx
|
|
18961
|
-
.updateTable("${change.typeName}")
|
|
18962
|
-
.set({ ${change.fieldName}: \`\${records[i].${change.fieldName}}_\${i}\` }) // TODO: Set appropriate unique value
|
|
18963
|
-
.where("id", "=", records[i].id)
|
|
18964
|
-
.execute();
|
|
18965
|
-
}
|
|
18966
|
-
}`;
|
|
19172
|
+
.execute();`);
|
|
19173
|
+
if (!deferUniqueConstraint) {
|
|
19174
|
+
const uniqueConstraintScript = generateUniqueConstraintScript(change);
|
|
19175
|
+
if (uniqueConstraintScript) scripts.push(uniqueConstraintScript);
|
|
19176
|
+
}
|
|
18967
19177
|
if (before.type === "enum" && after.type === "enum") {
|
|
18968
19178
|
const beforeValues = (before.allowedValues ?? []).map((v) => v.value);
|
|
18969
19179
|
const afterValues = (after.allowedValues ?? []).map((v) => v.value);
|
|
18970
19180
|
const removedValues = beforeValues.filter((v) => !afterValues.includes(v));
|
|
18971
19181
|
if (removedValues.length > 0) {
|
|
18972
19182
|
const defaultValue = afterValues[0] ?? "NEW_VALUE";
|
|
18973
|
-
|
|
19183
|
+
scripts.push(` // Migrate records with removed enum values: ${removedValues.join(", ")}
|
|
18974
19184
|
await trx
|
|
18975
19185
|
.updateTable("${change.typeName}")
|
|
18976
19186
|
.set({ ${change.fieldName}: "${defaultValue}" }) // TODO: Set appropriate value
|
|
18977
19187
|
.where("${change.fieldName}", "in", [${removedValues.map((v) => `"${v}"`).join(", ")}])
|
|
18978
|
-
.execute()
|
|
19188
|
+
.execute();`);
|
|
18979
19189
|
}
|
|
18980
19190
|
}
|
|
18981
|
-
if (before.foreignKeyType && after.foreignKeyType && before.foreignKeyType !== after.foreignKeyType)
|
|
19191
|
+
if (before.foreignKeyType && after.foreignKeyType && before.foreignKeyType !== after.foreignKeyType) scripts.push(` // Migrate ${change.fieldName} references from ${before.foreignKeyType} to ${after.foreignKeyType}
|
|
18982
19192
|
// Find records that don't have a valid reference in the new target table
|
|
18983
|
-
|
|
18984
|
-
|
|
18985
|
-
|
|
18986
|
-
|
|
18987
|
-
|
|
18988
|
-
|
|
18989
|
-
|
|
18990
|
-
for (const record of orphanedRecords) {
|
|
18991
|
-
await trx
|
|
18992
|
-
.updateTable("${change.typeName}")
|
|
18993
|
-
.set({ ${change.fieldName}: null }) // TODO: Set appropriate new reference
|
|
18994
|
-
.where("id", "=", record.id)
|
|
19193
|
+
{
|
|
19194
|
+
const orphanedRecords = await trx
|
|
19195
|
+
.selectFrom("${change.typeName}")
|
|
19196
|
+
.leftJoin("${after.foreignKeyType}", "${change.typeName}.${change.fieldName}", "${after.foreignKeyType}.id")
|
|
19197
|
+
.select(["${change.typeName}.id", "${change.typeName}.${change.fieldName}"])
|
|
19198
|
+
.where("${after.foreignKeyType}.id", "is", null)
|
|
19199
|
+
.where("${change.typeName}.${change.fieldName}", "is not", null)
|
|
18995
19200
|
.execute();
|
|
19201
|
+
for (const record of orphanedRecords) {
|
|
19202
|
+
await trx
|
|
19203
|
+
.updateTable("${change.typeName}")
|
|
19204
|
+
.set({ ${change.fieldName}: null }) // TODO: Set appropriate new reference
|
|
19205
|
+
.where("id", "=", record.id)
|
|
19206
|
+
.execute();
|
|
19207
|
+
}
|
|
19208
|
+
}`);
|
|
19209
|
+
return scripts;
|
|
19210
|
+
}
|
|
19211
|
+
function generateUniqueConstraintScript(change) {
|
|
19212
|
+
if (change.kind !== "field_modified") return null;
|
|
19213
|
+
const { before, after } = change;
|
|
19214
|
+
if ((before.unique ?? false) || !(after.unique ?? false)) return null;
|
|
19215
|
+
return ` // Ensure ${change.fieldName} values are unique before adding constraint
|
|
19216
|
+
{
|
|
19217
|
+
const duplicates = await trx
|
|
19218
|
+
.selectFrom("${change.typeName}")
|
|
19219
|
+
.select(["${change.fieldName}"])
|
|
19220
|
+
.groupBy("${change.fieldName}")
|
|
19221
|
+
.having((eb) => eb.fn.count("id"), ">", 1)
|
|
19222
|
+
.execute();
|
|
19223
|
+
for (const dup of duplicates) {
|
|
19224
|
+
// Keep first record, add suffix to others
|
|
19225
|
+
const records = await trx
|
|
19226
|
+
.selectFrom("${change.typeName}")
|
|
19227
|
+
.select(["id", "${change.fieldName}"])
|
|
19228
|
+
.where("${change.fieldName}", "=", dup.${change.fieldName})
|
|
19229
|
+
.execute();
|
|
19230
|
+
for (let i = 1; i < records.length; i++) {
|
|
19231
|
+
await trx
|
|
19232
|
+
.updateTable("${change.typeName}")
|
|
19233
|
+
.set({ ${change.fieldName}: \`\${records[i].${change.fieldName}}_\${i}\` }) // TODO: Set appropriate unique value
|
|
19234
|
+
.where("id", "=", records[i].id)
|
|
19235
|
+
.execute();
|
|
19236
|
+
}
|
|
19237
|
+
}
|
|
19238
|
+
}`;
|
|
19239
|
+
}
|
|
19240
|
+
function generateDecimalScaleChangeScript(change) {
|
|
19241
|
+
if (change.kind !== "field_modified") return null;
|
|
19242
|
+
const { before, after } = change;
|
|
19243
|
+
if (before.type !== "decimal" || after.type !== "decimal" || before.scale === after.scale) return null;
|
|
19244
|
+
const valueExpression = !before.required && after.required ? `row.${change.fieldName}!` : `row.${change.fieldName}`;
|
|
19245
|
+
const beforeScale = before.scale ?? 6;
|
|
19246
|
+
const roundingWarning = (after.scale ?? 6) < beforeScale ? `
|
|
19247
|
+
// Values that exceed the new scale may be rounded half-up, so review the
|
|
19248
|
+
// resulting precision before deploying.` : "";
|
|
19249
|
+
return ` // Re-save existing ${change.typeName} rows so ${change.fieldName} is stored under the new scale.
|
|
19250
|
+
// This is a workaround for a platform-side gap where rows written under the
|
|
19251
|
+
// previous scale could fail on later updates until re-saved. Keep it unless
|
|
19252
|
+
// your platform is confirmed to handle stored values across scale changes.${roundingWarning}
|
|
19253
|
+
{
|
|
19254
|
+
let lastId: string | undefined;
|
|
19255
|
+
while (true) {
|
|
19256
|
+
let query = trx
|
|
19257
|
+
.selectFrom("${change.typeName}")
|
|
19258
|
+
.select(["id", "${change.fieldName}"])
|
|
19259
|
+
.where("${change.fieldName}", "is not", null)
|
|
19260
|
+
.orderBy("id", "asc")
|
|
19261
|
+
.limit(100);
|
|
19262
|
+
if (lastId) {
|
|
19263
|
+
query = query.where("id", ">", lastId);
|
|
19264
|
+
}
|
|
19265
|
+
const rows = await query.execute();
|
|
19266
|
+
if (rows.length === 0) break;
|
|
19267
|
+
|
|
19268
|
+
for (const row of rows) {
|
|
19269
|
+
await trx
|
|
19270
|
+
.updateTable("${change.typeName}")
|
|
19271
|
+
.set({ ${change.fieldName}: ${valueExpression} })
|
|
19272
|
+
.where("id", "=", row.id)
|
|
19273
|
+
.where("${change.fieldName}", "=", ${valueExpression})
|
|
19274
|
+
.execute();
|
|
19275
|
+
}
|
|
19276
|
+
lastId = rows[rows.length - 1]!.id;
|
|
19277
|
+
}
|
|
18996
19278
|
}`;
|
|
18997
|
-
return null;
|
|
18998
19279
|
}
|
|
18999
19280
|
|
|
19000
19281
|
//#endregion
|
|
@@ -19063,7 +19344,7 @@ async function generate(options) {
|
|
|
19063
19344
|
if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
|
|
19064
19345
|
let pluginManager;
|
|
19065
19346
|
if (plugins.length > 0) pluginManager = new PluginManager(plugins);
|
|
19066
|
-
const { defineApplication } = await import("./application-
|
|
19347
|
+
const { defineApplication } = await import("./application-5FOWIxFQ.mjs");
|
|
19067
19348
|
const application = defineApplication({
|
|
19068
19349
|
config,
|
|
19069
19350
|
pluginManager
|
|
@@ -21192,4 +21473,4 @@ async function registerTypeScriptRuntime(hookUrl) {
|
|
|
21192
21473
|
|
|
21193
21474
|
//#endregion
|
|
21194
21475
|
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 };
|
|
21195
|
-
//# sourceMappingURL=register-typescript-runtime-
|
|
21476
|
+
//# sourceMappingURL=register-typescript-runtime-BCvWR3HC.mjs.map
|