@tailor-platform/sdk 2.3.0 → 2.4.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 +68 -0
- package/README.md +1 -1
- package/dist/{application-F-nl107y.mjs → application-C8a0UJ-z.mjs} +201 -149
- package/dist/application-C8a0UJ-z.mjs.map +1 -0
- package/dist/application-D4zOiLLa.mjs +3 -0
- package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +4 -4
- package/dist/cli/commands/tailordb/migrate/generate.d.mts +3 -3
- package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +5 -5
- package/dist/cli/commands/tailordb/truncate.d.mts +2 -2
- package/dist/cli/lib.mjs +2 -2
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/main.mjs +174 -106
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/ts-hook.mjs +3 -1
- package/dist/completion/zsh-worker.zsh +19 -11
- package/dist/configure/config/index.d.mts +1 -1
- package/dist/configure/index.d.mts +2 -1
- package/dist/configure/index.mjs +2 -2
- package/dist/configure/index.mjs.map +1 -1
- package/dist/configure/services/aigateway/index.d.mts +5 -4
- package/dist/configure/services/aigateway/types.d.mts +6 -1
- package/dist/configure/services/auth/types.d.mts +2 -2
- package/dist/configure/services/tailordb/permission.d.mts +1 -1
- package/dist/configure/services/tailordb/schema.d.mts +1 -1
- package/dist/configure/services/tailordb/types.d.mts +7 -4
- package/dist/configure/types/auth-namespace-name.d.mts +18 -0
- package/dist/{crashreport-CINZ5dVN.mjs → crashreport-Cd4TqfZq.mjs} +1 -1
- package/dist/{crashreport-CIIfLnoO.mjs → crashreport-Q0pDAlrj.mjs} +8 -4
- package/dist/{crashreport-CIIfLnoO.mjs.map → crashreport-Q0pDAlrj.mjs.map} +1 -1
- package/dist/{errors-BVb6vYGy.mjs → errors-Bxut5_Sy.mjs} +2 -2
- package/dist/{errors-BVb6vYGy.mjs.map → errors-Bxut5_Sy.mjs.map} +1 -1
- package/dist/file-BUcmVIH2.mjs.map +1 -1
- package/dist/kysely/index.mjs +2 -1
- package/dist/kysely/index.mjs.map +1 -1
- package/dist/{logger-DSdExfor.mjs → logger-D0bEznPv.mjs} +9 -5
- package/dist/{logger-DSdExfor.mjs.map → logger-D0bEznPv.mjs.map} +1 -1
- package/dist/package-json-8b0O9TlX.mjs.map +1 -1
- package/dist/plugin/builtin/enum-constants/index.d.mts +1 -1
- package/dist/plugin/builtin/enum-constants/index.mjs +5 -5
- package/dist/plugin/builtin/enum-constants/index.mjs.map +1 -1
- package/dist/plugin/builtin/file-utils/index.d.mts +1 -1
- package/dist/plugin/builtin/file-utils/index.mjs +14 -11
- package/dist/plugin/builtin/file-utils/index.mjs.map +1 -1
- package/dist/plugin/builtin/kysely-type/index.d.mts +1 -1
- package/dist/plugin/builtin/kysely-type/index.mjs +9 -9
- package/dist/plugin/builtin/kysely-type/index.mjs.map +1 -1
- package/dist/plugin/builtin/seed/index.mjs +1 -1
- package/dist/plugin/builtin/seed/seed-type-processor.d.mts +4 -4
- package/dist/plugin/get-generated-type.d.mts +4 -4
- package/dist/plugin/index.mjs +13 -13
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/plugin/types.d.mts +2 -2
- package/dist/plugin/with-context.d.mts +1 -1
- package/dist/{register-ts-hook-ClI226n2.mjs → register-ts-hook-Vqjza10T.mjs} +552 -416
- package/dist/register-ts-hook-Vqjza10T.mjs.map +1 -0
- package/dist/{repl-editor-BCozyiNq.mjs → repl-editor-F9LotMNx.mjs} +3 -2
- package/dist/{repl-editor-BCozyiNq.mjs.map → repl-editor-F9LotMNx.mjs.map} +1 -1
- package/dist/runtime/file.d.mts +14 -14
- package/dist/{schema--xYWRGfe.mjs → schema-D4TC4BC3.mjs} +4 -3
- package/dist/schema-D4TC4BC3.mjs.map +1 -0
- package/dist/seed/index.d.mts +4 -4
- package/dist/seed/index.mjs +3 -3
- package/dist/seed/index.mjs.map +1 -1
- package/dist/{seed-xqM9WIHP.mjs → seed-Cibjmtry.mjs} +46 -40
- package/dist/seed-Cibjmtry.mjs.map +1 -0
- package/dist/{service-C_WpbKHu.mjs → service-2grcAOCJ.mjs} +24 -24
- package/dist/service-2grcAOCJ.mjs.map +1 -0
- package/dist/service-CaBPNDIZ.mjs +3 -0
- package/dist/{service-hZskxZmg.mjs → service-LTfp03ZZ.mjs} +7 -5
- package/dist/{service-hZskxZmg.mjs.map → service-LTfp03ZZ.mjs.map} +1 -1
- package/dist/types/aigateway.generated.d.mts +2 -2
- package/dist/types/auth.generated.d.mts +3 -3
- package/dist/types/executor.generated.d.mts +1 -1
- package/dist/types/tailordb.generated.d.mts +12 -12
- package/dist/utils/test/index.d.mts +4 -4
- package/dist/utils/test/index.mjs +4 -4
- package/dist/utils/test/index.mjs.map +1 -1
- package/dist/vitest/index.mjs +13 -7
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/mocks/file.d.mts +1 -1
- package/docs/cli/application.md +3 -1
- package/docs/cli/function.md +17 -13
- package/docs/cli/tailordb.md +30 -30
- package/docs/cli/workspace.md +2 -2
- package/docs/cli-reference.md +21 -21
- package/docs/configuration.md +2 -2
- package/docs/migration/v2.md +4 -4
- package/docs/migration/v3.md +41 -0
- package/docs/quickstart.md +1 -1
- package/docs/services/aigateway.md +33 -9
- package/docs/services/executor.md +5 -1
- package/docs/services/tailordb-migration.md +47 -47
- package/docs/services/tailordb.md +7 -7
- package/docs/testing.md +1 -1
- package/package.json +6 -6
- package/dist/application-BZfk4HKm.mjs +0 -3
- package/dist/application-F-nl107y.mjs.map +0 -1
- package/dist/register-ts-hook-ClI226n2.mjs.map +0 -1
- package/dist/schema--xYWRGfe.mjs.map +0 -1
- package/dist/seed-xqM9WIHP.mjs.map +0 -1
- package/dist/service-C_WpbKHu.mjs.map +0 -1
- package/dist/service-D1RCdzIL.mjs +0 -3
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { t as db } from "./schema
|
|
1
|
+
import { t as db } from "./schema-D4TC4BC3.mjs";
|
|
2
2
|
import { t as beginWaitPointScope } from "./wait-point-registry-TL99zotw.mjs";
|
|
3
3
|
import { $ as CreateAuthHookRequestSchema, B as IdPLang, Bt as ApplicationSchemaUpdateAttemptStatus, C as CreateStaticWebsiteRequestSchema, Ct as AuthInvokerSchema, D as CreateSecretManagerSecretRequestSchema, Dt as AuthSCIMAttribute_Type, Et as AuthSCIMAttribute_Mutability, H as IdPPermissionPermit, Ht as CreateAIGatewayRequestSchema, I as PipelineResolver_OperationType, It as CreateApplicationRequestSchema, Jt as Condition_Operator, K as CreateExecutorExecutorRequestSchema, L as CreateIdPServiceRequestSchema, Lt as GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus, 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, Rt as UpdateApplicationRequestSchema, S as AddCustomDomainRequestSchema, St as AuthIDPConfig_AuthType, Tt as AuthOAuth2Client_GrantType, U as FunctionExecution_Status, Ut as UpdateAIGatewayRequestSchema, V as IdPPermissionOperator, Vt as Subgraph_ServiceType, X as ExecutorTargetType, Xt as PageDirection, Y as ExecutorJobStatus, Yt as FilterSchema, 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 ConditionSchema, 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 } from "./workspace_resource_pb-HNIL_Vfj.mjs";
|
|
4
4
|
import { t as assertDefined } from "./assert-DBxo8jPo.mjs";
|
|
5
|
-
import { a as parseBoolean, i as symbols, n as logger, o as renderTable, r as styles, s as renderFor, t as CIPromptError } from "./logger-
|
|
6
|
-
import { $ as
|
|
7
|
-
import { _ as beginUserModuleRun, b as functionSchema, c as stripTailorDBTypeBuilderHelpers, g as IMPORT_NONCE_PARAM, h as loadFilesWithIgnores, t as createExecutorService, u as TailorDBTypeSchema$1, v as currentImportNonce } from "./service-
|
|
5
|
+
import { a as parseBoolean, i as symbols, n as logger, o as renderTable, r as styles, s as renderFor, t as CIPromptError } from "./logger-D0bEznPv.mjs";
|
|
6
|
+
import { $ as rememberPlatformConfigForToken, A as getPluginGenerationDependencies, B as fetchMachineUserToken, C as createTsconfigPathsPlugin, F as hashFile, G as getOAuth2ClientId, J as initOAuth2Client, K as getOrNull, L as defaultPlatformBaseUrl, M as createBundleCache, N as getDistDir, P as hashContent, Q as normalizeBaseUrl, R as fetchAll, S as createGeneratedEntryResolverPlugin, T as platformBundleDefinePlugin, U as fetchUserInfo, V as fetchPaged, W as getConsoleBaseUrl, X as isDefaultPlatform, Y as initOperatorClient, Z as isNotFoundError, _ as assertUniqueLocalTailorDBTypeNames, b as stringifyFunction, c as WorkflowJobFunctionExecutionPolicySchema, et as resolveStaticWebsiteUrls, f as HTTP_METHODS, h as buildResolverOperationHookExpr, i as resolverBundleKey, j as hasGenerationHooks, k as createBundleLog, m as buildExecutorArgsExpr, n as generatePluginFilesIfNeeded, nt as createApplyLimiter, o as getApplicationAuthNamespace, q as getPlatformBaseUrl, r as loadApplication, rt as LOG_LEVELS, s as requireApplicationAuthNamespace, t as defineApplication, tt as byName, v as assertUniqueTailorDBTypeNamesWithExternal, w as resolveTSConfigWithFallback, x as tailorPrincipalMap, y as PRINCIPAL_VAR, z as fetchAllTolerant } from "./application-C8a0UJ-z.mjs";
|
|
7
|
+
import { _ as beginUserModuleRun, b as functionSchema, c as stripTailorDBTypeBuilderHelpers, g as IMPORT_NONCE_PARAM, h as loadFilesWithIgnores, t as createExecutorService, u as TailorDBTypeSchema$1, v as currentImportNonce } from "./service-2grcAOCJ.mjs";
|
|
8
8
|
import { t as multiline } from "./multiline-sfHpTZZK.mjs";
|
|
9
9
|
import { t as readPackageJson } from "./package-json-8b0O9TlX.mjs";
|
|
10
10
|
import { t as userAgent } from "./user-agent-Bgsszb5I.mjs";
|
|
11
|
-
import { a as typeOnlyImportHint, i as isCLIError, n as formatCopyableCommand, t as createCLIError } from "./errors-
|
|
11
|
+
import { a as typeOnlyImportHint, i as isCLIError, n as formatCopyableCommand, t as createCLIError } from "./errors-Bxut5_Sy.mjs";
|
|
12
12
|
import { n as tightenSecretFilePermissions, r as writeSecretFile } from "./secret-file-C3J4Gy8r.mjs";
|
|
13
13
|
import { r as withSpan } from "./telemetry-BRVdwh14.mjs";
|
|
14
|
-
import { a as generateIdpTruncateScriptCode, i as generateIdpSeedScriptCode, o as processIdpUser, r as processLinesDb, t as SeedGeneratorID } from "./seed-
|
|
14
|
+
import { a as generateIdpTruncateScriptCode, i as generateIdpSeedScriptCode, o as processIdpUser, r as processLinesDb, t as SeedGeneratorID } from "./seed-Cibjmtry.mjs";
|
|
15
15
|
import * as mod from "node:module";
|
|
16
16
|
import * as path from "pathe";
|
|
17
17
|
import { basename, dirname, join, resolve } from "pathe";
|
|
@@ -57,7 +57,7 @@ import { parse as parse$1 } from "@0no-co/graphql.web";
|
|
|
57
57
|
const unitToMs = {
|
|
58
58
|
ms: 1,
|
|
59
59
|
s: 1e3,
|
|
60
|
-
m:
|
|
60
|
+
m: 6e4
|
|
61
61
|
};
|
|
62
62
|
const durationPattern = /^(\d+)(ms|s|m)$/;
|
|
63
63
|
/**
|
|
@@ -141,7 +141,8 @@ function loadEnvFiles(envFiles, envFilesIfExists) {
|
|
|
141
141
|
if (required) throw new Error(`Environment file not found: ${envPath}`);
|
|
142
142
|
continue;
|
|
143
143
|
}
|
|
144
|
-
const
|
|
144
|
+
const content = fs$2.readFileSync(envPath, "utf-8");
|
|
145
|
+
const parsed = parseEnv(content);
|
|
145
146
|
for (const [key, value] of Object.entries(parsed)) {
|
|
146
147
|
if (originalEnvKeys.has(key)) continue;
|
|
147
148
|
process.env[key] = value;
|
|
@@ -697,7 +698,8 @@ async function trySaveTokensInKeyring(user, tokens) {
|
|
|
697
698
|
}
|
|
698
699
|
async function warnIfNewerConfigAvailable(config) {
|
|
699
700
|
if (!config.latest_min_sdk_version) return;
|
|
700
|
-
|
|
701
|
+
const sdkVersion = (await readPackageJson()).version ?? "0.0.0";
|
|
702
|
+
if (lt(sdkVersion, config.latest_min_sdk_version)) logger.warn(multiline`
|
|
701
703
|
A newer config version (${String(config.latest_version)}) is available.
|
|
702
704
|
Please update your SDK to >= ${config.latest_min_sdk_version}: pnpm update @tailor-platform/sdk
|
|
703
705
|
`);
|
|
@@ -799,7 +801,8 @@ function toLatestForDisk(config) {
|
|
|
799
801
|
function writePlatformConfig(config) {
|
|
800
802
|
const configPath = platformConfigPath();
|
|
801
803
|
const hasKeyringUser = config.version !== 1 && Object.values(config.users).some((u) => u?.storage === "keyring");
|
|
802
|
-
|
|
804
|
+
const diskConfig = config.version === LATEST_CONFIG_VERSION || hasProfilePlatformSettings(config) || hasScopedUserKeys(config) || hasUserEmailMetadata(config) ? toLatestForDisk(config) : config.version === V2_CONFIG_VERSION && !hasKeyringUser ? toV1ForDisk(config) : config;
|
|
805
|
+
writeSecretFile(configPath, stringifyYAML(diskConfig));
|
|
803
806
|
}
|
|
804
807
|
function validateUUID(value, source) {
|
|
805
808
|
const result = z.uuid().safeParse(value);
|
|
@@ -893,10 +896,11 @@ async function loadAccessToken(opts) {
|
|
|
893
896
|
const envToken = process.env.TAILOR_PLATFORM_TOKEN ?? process.env.TAILOR_TOKEN;
|
|
894
897
|
if (envToken && !process.env.TAILOR_PLATFORM_TOKEN) logger.warn("TAILOR_TOKEN is deprecated. Please use TAILOR_PLATFORM_TOKEN instead.");
|
|
895
898
|
if (envToken) {
|
|
896
|
-
|
|
899
|
+
const platformConfig = await loadPlatformClientConfig({
|
|
897
900
|
profile,
|
|
898
901
|
allowMissingProfile: true
|
|
899
|
-
})
|
|
902
|
+
});
|
|
903
|
+
rememberPlatformConfigForToken(envToken, platformConfig);
|
|
900
904
|
return envToken;
|
|
901
905
|
}
|
|
902
906
|
const pfConfig = await readPlatformConfig();
|
|
@@ -937,7 +941,8 @@ async function loadPlatformClientConfig(opts) {
|
|
|
937
941
|
* @returns Resolved Console base URL
|
|
938
942
|
*/
|
|
939
943
|
async function loadConsoleBaseUrl(opts) {
|
|
940
|
-
|
|
944
|
+
const platformConfig = await loadPlatformClientConfig(opts);
|
|
945
|
+
return getConsoleBaseUrl(platformConfig);
|
|
941
946
|
}
|
|
942
947
|
/**
|
|
943
948
|
* Resolve the actual token values for a user, reading from keyring or config as appropriate.
|
|
@@ -1660,7 +1665,8 @@ function createCacheManager(options) {
|
|
|
1660
1665
|
},
|
|
1661
1666
|
finalize() {}
|
|
1662
1667
|
};
|
|
1663
|
-
const
|
|
1668
|
+
const cacheDir = options.cacheDir ?? path.resolve(getDistDir(), "cache");
|
|
1669
|
+
const store = createCacheStore({ cacheDir });
|
|
1664
1670
|
const existingManifest = store.loadManifest();
|
|
1665
1671
|
if (existingManifest) {
|
|
1666
1672
|
if (existingManifest.sdkVersion !== options.sdkVersion) {
|
|
@@ -1734,7 +1740,7 @@ function parseMigrationNumberArg(numberStr) {
|
|
|
1734
1740
|
* confirmation that lists the same resource cannot drift apart.
|
|
1735
1741
|
*/
|
|
1736
1742
|
const eventSourceLabel = {
|
|
1737
|
-
tailorDBType: (name) => `TailorDB
|
|
1743
|
+
tailorDBType: (name) => `TailorDB table "${name}"`,
|
|
1738
1744
|
resolver: (name) => `Resolver "${name}"`,
|
|
1739
1745
|
idpService: (name) => `IdP service "${name}"`,
|
|
1740
1746
|
workflow: (name) => `Workflow "${name}"`,
|
|
@@ -1823,9 +1829,10 @@ const isValidIdentifier = (s) => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(s);
|
|
|
1823
1829
|
* @param idpNames - Registered IdP names (used to narrow `idpUser*Trigger({ idp })` strings)
|
|
1824
1830
|
* @param connectionNames - Registered auth connection names (used to narrow `getConnectionToken()` strings)
|
|
1825
1831
|
* @param aiGatewayNames - Registered AI Gateway names (used to narrow `aigateway.get()` strings)
|
|
1832
|
+
* @param authNamespaceNames - Registered auth namespace names (used to narrow `authNamespace` strings)
|
|
1826
1833
|
* @returns Generated type definition source
|
|
1827
1834
|
*/
|
|
1828
|
-
function generateTypeDefinition(attributes, attributeList, env, machineUserNames, idpNames, connectionNames, aiGatewayNames) {
|
|
1835
|
+
function generateTypeDefinition(attributes, attributeList, env, machineUserNames, idpNames, connectionNames, aiGatewayNames, authNamespaceNames) {
|
|
1829
1836
|
const attributeFields = attributes ? Object.entries(attributes).map(([key, { type, optional }]) => ` ${key}${optional ? "?" : ""}: ${type};`).join("\n") : "";
|
|
1830
1837
|
const attributesBody = !attributes || Object.keys(attributes).length === 0 ? "{}" : `{
|
|
1831
1838
|
${attributeFields}
|
|
@@ -1850,6 +1857,13 @@ ${idpNameFields}
|
|
|
1850
1857
|
${connectionNameFields}
|
|
1851
1858
|
}`;
|
|
1852
1859
|
const aiGatewayNameFields = aiGatewayNames?.length ? aiGatewayNames.map((name) => ` ${isValidIdentifier(name) ? name : JSON.stringify(name)}: true;`).join("\n") : "";
|
|
1860
|
+
const aiGatewayNameBody = !aiGatewayNames || aiGatewayNames.length === 0 ? "{}" : `{
|
|
1861
|
+
${aiGatewayNameFields}
|
|
1862
|
+
}`;
|
|
1863
|
+
const authNamespaceNameFields = authNamespaceNames?.length ? authNamespaceNames.map((name) => ` ${isValidIdentifier(name) ? name : JSON.stringify(name)}: true;`).join("\n") : "";
|
|
1864
|
+
const authNamespaceNameBody = !authNamespaceNames || authNamespaceNames.length === 0 ? "{}" : `{
|
|
1865
|
+
${authNamespaceNameFields}
|
|
1866
|
+
}`;
|
|
1853
1867
|
return multiline`
|
|
1854
1868
|
// This file is auto-generated by @tailor-platform/sdk
|
|
1855
1869
|
// Do not edit this file manually
|
|
@@ -1862,9 +1876,8 @@ declare module "@tailor-platform/sdk" {
|
|
|
1862
1876
|
interface MachineUserNameRegistry ${machineUserBody}
|
|
1863
1877
|
interface IdpNameRegistry ${idpNameBody}
|
|
1864
1878
|
interface ConnectionNameRegistry ${connectionNameBody}
|
|
1865
|
-
interface AIGatewayNameRegistry ${
|
|
1866
|
-
${
|
|
1867
|
-
}`}
|
|
1879
|
+
interface AIGatewayNameRegistry ${aiGatewayNameBody}
|
|
1880
|
+
interface AuthNamespaceNameRegistry ${authNamespaceNameBody}
|
|
1868
1881
|
}
|
|
1869
1882
|
|
|
1870
1883
|
export {};
|
|
@@ -1875,10 +1888,12 @@ function collectAttributesFromConfig(config) {
|
|
|
1875
1888
|
const idpNames = config.idp?.length ? [...new Set(config.idp.map((idp) => idp.name))] : void 0;
|
|
1876
1889
|
const aiGatewayNames = config.aiGateways?.length ? [...new Set(config.aiGateways.map((gateway) => gateway.name))] : void 0;
|
|
1877
1890
|
const auth = config.auth;
|
|
1878
|
-
|
|
1891
|
+
const authNamespaceNames = auth && typeof auth === "object" && typeof auth.name === "string" ? [auth.name] : void 0;
|
|
1892
|
+
if (!auth || typeof auth !== "object") return {
|
|
1879
1893
|
idpNames,
|
|
1880
|
-
aiGatewayNames
|
|
1881
|
-
|
|
1894
|
+
aiGatewayNames,
|
|
1895
|
+
authNamespaceNames
|
|
1896
|
+
};
|
|
1882
1897
|
const machineUsersObj = auth.machineUsers;
|
|
1883
1898
|
const machineUserNames = machineUsersObj && typeof machineUsersObj === "object" ? Object.keys(machineUsersObj) : void 0;
|
|
1884
1899
|
const connectionsObj = auth.connections;
|
|
@@ -1910,7 +1925,8 @@ function collectAttributesFromConfig(config) {
|
|
|
1910
1925
|
machineUserNames,
|
|
1911
1926
|
idpNames,
|
|
1912
1927
|
connectionNames,
|
|
1913
|
-
aiGatewayNames
|
|
1928
|
+
aiGatewayNames,
|
|
1929
|
+
authNamespaceNames
|
|
1914
1930
|
};
|
|
1915
1931
|
}
|
|
1916
1932
|
if ("machineUserAttributes" in auth) {
|
|
@@ -1919,7 +1935,8 @@ function collectAttributesFromConfig(config) {
|
|
|
1919
1935
|
machineUserNames,
|
|
1920
1936
|
idpNames,
|
|
1921
1937
|
connectionNames,
|
|
1922
|
-
aiGatewayNames
|
|
1938
|
+
aiGatewayNames,
|
|
1939
|
+
authNamespaceNames
|
|
1923
1940
|
};
|
|
1924
1941
|
return {
|
|
1925
1942
|
attributes: Object.entries(machineUserAttributes).reduce((acc, [key, field]) => {
|
|
@@ -1929,14 +1946,16 @@ function collectAttributesFromConfig(config) {
|
|
|
1929
1946
|
machineUserNames,
|
|
1930
1947
|
idpNames,
|
|
1931
1948
|
connectionNames,
|
|
1932
|
-
aiGatewayNames
|
|
1949
|
+
aiGatewayNames,
|
|
1950
|
+
authNamespaceNames
|
|
1933
1951
|
};
|
|
1934
1952
|
}
|
|
1935
1953
|
return {
|
|
1936
1954
|
machineUserNames,
|
|
1937
1955
|
idpNames,
|
|
1938
1956
|
connectionNames,
|
|
1939
|
-
aiGatewayNames
|
|
1957
|
+
aiGatewayNames,
|
|
1958
|
+
authNamespaceNames
|
|
1940
1959
|
};
|
|
1941
1960
|
}
|
|
1942
1961
|
/**
|
|
@@ -1961,7 +1980,7 @@ function resolveTypeDefinitionPath(configPath) {
|
|
|
1961
1980
|
async function generateUserTypes(options) {
|
|
1962
1981
|
const { config, configPath } = options;
|
|
1963
1982
|
try {
|
|
1964
|
-
const { attributes, attributeList, machineUserNames, idpNames, connectionNames, aiGatewayNames } = extractAttributesFromConfig(config);
|
|
1983
|
+
const { attributes, attributeList, machineUserNames, idpNames, connectionNames, aiGatewayNames, authNamespaceNames } = extractAttributesFromConfig(config);
|
|
1965
1984
|
if (!attributes && !attributeList) logger.info("No attributes found in configuration", { mode: "plain" });
|
|
1966
1985
|
if (attributes) logger.debug(`Extracted Attributes: ${JSON.stringify(attributes)}`);
|
|
1967
1986
|
if (attributeList) logger.debug(`Extracted AttributeList: ${JSON.stringify(attributeList)}`);
|
|
@@ -1969,9 +1988,10 @@ async function generateUserTypes(options) {
|
|
|
1969
1988
|
if (idpNames?.length) logger.debug(`Extracted IdpNames: ${JSON.stringify(idpNames)}`);
|
|
1970
1989
|
if (connectionNames?.length) logger.debug(`Extracted ConnectionNames: ${JSON.stringify(connectionNames)}`);
|
|
1971
1990
|
if (aiGatewayNames?.length) logger.debug(`Extracted AIGatewayNames: ${JSON.stringify(aiGatewayNames)}`);
|
|
1991
|
+
if (authNamespaceNames?.length) logger.debug(`Extracted AuthNamespaceNames: ${JSON.stringify(authNamespaceNames)}`);
|
|
1972
1992
|
const env = config.env;
|
|
1973
1993
|
if (env) logger.debug(`Extracted Env: ${JSON.stringify(env)}`);
|
|
1974
|
-
const typeDefContent = generateTypeDefinition(attributes, attributeList, env, machineUserNames, idpNames, connectionNames, aiGatewayNames);
|
|
1994
|
+
const typeDefContent = generateTypeDefinition(attributes, attributeList, env, machineUserNames, idpNames, connectionNames, aiGatewayNames, authNamespaceNames);
|
|
1975
1995
|
const outputPath = resolveTypeDefinitionPath(configPath);
|
|
1976
1996
|
fs$2.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
1977
1997
|
fs$2.writeFileSync(outputPath, typeDefContent);
|
|
@@ -2006,7 +2026,7 @@ var PluginManager = class {
|
|
|
2006
2026
|
/**
|
|
2007
2027
|
* Process a single plugin attachment on a raw TailorDBType.
|
|
2008
2028
|
* This method is called during type loading before parsing.
|
|
2009
|
-
* @param context - Context containing the raw
|
|
2029
|
+
* @param context - Context containing the raw table, config, namespace, and plugin ID
|
|
2010
2030
|
* @returns Result with plugin output on success, or error message on failure
|
|
2011
2031
|
*/
|
|
2012
2032
|
async processAttachment(context) {
|
|
@@ -2063,9 +2083,9 @@ var PluginManager = class {
|
|
|
2063
2083
|
};
|
|
2064
2084
|
}
|
|
2065
2085
|
/**
|
|
2066
|
-
* Process namespace plugins that don't require a source
|
|
2086
|
+
* Process namespace plugins that don't require a source table.
|
|
2067
2087
|
* This method is called once per namespace for plugins with onNamespaceLoaded method.
|
|
2068
|
-
* @param namespace - The target namespace for generated
|
|
2088
|
+
* @param namespace - The target namespace for generated tables
|
|
2069
2089
|
* @returns Array of results with plugin outputs and configs
|
|
2070
2090
|
*/
|
|
2071
2091
|
async processNamespacePlugins(namespace) {
|
|
@@ -2131,11 +2151,11 @@ var PluginManager = class {
|
|
|
2131
2151
|
return results;
|
|
2132
2152
|
}
|
|
2133
2153
|
/**
|
|
2134
|
-
* Run every plugin attachment for a single TailorDB
|
|
2135
|
-
* extended
|
|
2154
|
+
* Run every plugin attachment for a single TailorDB table in order, threading the
|
|
2155
|
+
* extended table through the chain. Returns plain data (no logging, no shared state)
|
|
2136
2156
|
* so the caller decides how to apply updates and render progress.
|
|
2137
|
-
* @param params - The raw
|
|
2138
|
-
* @returns Final extended
|
|
2157
|
+
* @param params - The raw table, its attachments, and the target namespace
|
|
2158
|
+
* @returns Final extended table (if any), generated tables, and render events
|
|
2139
2159
|
*/
|
|
2140
2160
|
async processAttachmentsForType(params) {
|
|
2141
2161
|
const { rawType, attachments, namespace } = params;
|
|
@@ -2238,8 +2258,8 @@ var PluginManager = class {
|
|
|
2238
2258
|
}));
|
|
2239
2259
|
}
|
|
2240
2260
|
/**
|
|
2241
|
-
* Get all plugin-generated
|
|
2242
|
-
* @returns Array of plugin-generated
|
|
2261
|
+
* Get all plugin-generated tables
|
|
2262
|
+
* @returns Array of plugin-generated table info
|
|
2243
2263
|
*/
|
|
2244
2264
|
getPluginGeneratedTypes() {
|
|
2245
2265
|
return this.generatedTypes;
|
|
@@ -2282,10 +2302,10 @@ var PluginManager = class {
|
|
|
2282
2302
|
return this.pluginExecutorFiles;
|
|
2283
2303
|
}
|
|
2284
2304
|
/**
|
|
2285
|
-
* Extend a TailorDB
|
|
2305
|
+
* Extend a TailorDB table with new fields.
|
|
2286
2306
|
* This method handles the `db.table()` call and metadata copying internally.
|
|
2287
|
-
* @param params - Parameters for
|
|
2288
|
-
* @returns The extended TailorDB
|
|
2307
|
+
* @param params - Parameters for table extension
|
|
2308
|
+
* @returns The extended TailorDB table
|
|
2289
2309
|
*/
|
|
2290
2310
|
extendType(params) {
|
|
2291
2311
|
const { originalType, extendFields, pluginId } = params;
|
|
@@ -2302,11 +2322,11 @@ var PluginManager = class {
|
|
|
2302
2322
|
}
|
|
2303
2323
|
};
|
|
2304
2324
|
/**
|
|
2305
|
-
* Copy metadata from original
|
|
2325
|
+
* Copy metadata from original table to extended table.
|
|
2306
2326
|
* Preserves files, settings, permissions, indexes, and plugins.
|
|
2307
|
-
* @param original - The original TailorDB
|
|
2308
|
-
* @param extended - The newly created extended
|
|
2309
|
-
* @returns The extended
|
|
2327
|
+
* @param original - The original TailorDB table with metadata
|
|
2328
|
+
* @param extended - The newly created extended table
|
|
2329
|
+
* @returns The extended table with copied metadata
|
|
2310
2330
|
*/
|
|
2311
2331
|
function copyMetadataToExtendedType(original, extended) {
|
|
2312
2332
|
let result = extended;
|
|
@@ -2481,7 +2501,7 @@ function resourceTrn(workspaceId, kind, name) {
|
|
|
2481
2501
|
*
|
|
2482
2502
|
* The platform reads everything after the workspace id as alternating key/value
|
|
2483
2503
|
* pairs and matches the pair list against one resource type, so a nested
|
|
2484
|
-
* resource is the parent's pair followed by its own. A TailorDB
|
|
2504
|
+
* resource is the parent's pair followed by its own. A TailorDB table is
|
|
2485
2505
|
* `tailordb:<namespace>:type:<name>`, distinct from the namespace's own
|
|
2486
2506
|
* `tailordb:<namespace>`.
|
|
2487
2507
|
* @param workspaceId - Workspace ID
|
|
@@ -2493,10 +2513,10 @@ function nestedResourceTrn(workspaceId, parent, child) {
|
|
|
2493
2513
|
return `${trnPrefix(workspaceId)}:${parent[0]}:${parent[1]}:${child[0]}:${child[1]}`;
|
|
2494
2514
|
}
|
|
2495
2515
|
/**
|
|
2496
|
-
* Build the TRN for one TailorDB
|
|
2516
|
+
* Build the TRN for one TailorDB table.
|
|
2497
2517
|
* @param workspaceId - Workspace ID
|
|
2498
|
-
* @param namespace - TailorDB namespace holding the
|
|
2499
|
-
* @param typeName -
|
|
2518
|
+
* @param namespace - TailorDB namespace holding the table
|
|
2519
|
+
* @param typeName - Table name
|
|
2500
2520
|
* @returns Fully-qualified TRN string
|
|
2501
2521
|
*/
|
|
2502
2522
|
function tailorDBTypeTrn(workspaceId, namespace, typeName) {
|
|
@@ -2776,15 +2796,17 @@ async function fetchExistingResourcesWithLabels(params) {
|
|
|
2776
2796
|
function trackDesiredResourceOwnership(params) {
|
|
2777
2797
|
const { labels, ownerLabel, appName, appId, resourceType, resourceName, conflicts, unmanaged } = params;
|
|
2778
2798
|
const owned = isOwnedByApp(labels, appName, appId);
|
|
2779
|
-
if (!owned)
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2799
|
+
if (!owned) {
|
|
2800
|
+
if (!ownerLabel) unmanaged.push({
|
|
2801
|
+
resourceType,
|
|
2802
|
+
resourceName
|
|
2803
|
+
});
|
|
2804
|
+
else conflicts.push({
|
|
2805
|
+
resourceType,
|
|
2806
|
+
resourceName,
|
|
2807
|
+
currentOwner: ownerLabel
|
|
2808
|
+
});
|
|
2809
|
+
}
|
|
2788
2810
|
return owned;
|
|
2789
2811
|
}
|
|
2790
2812
|
/**
|
|
@@ -3315,7 +3337,8 @@ async function planApplication(context, httpAdapterBuildResult) {
|
|
|
3315
3337
|
if (application.id) {
|
|
3316
3338
|
const otherApps = existingApplications.filter((app) => app.name !== application.name);
|
|
3317
3339
|
const renamedAway = await Promise.all(otherApps.map(async (app) => {
|
|
3318
|
-
|
|
3340
|
+
const labels = await fetchAppLabels(client, workspaceId, app.name);
|
|
3341
|
+
return isOwnedByApp(labels, application.name, application.id) ? app.name : null;
|
|
3319
3342
|
}));
|
|
3320
3343
|
for (const name of renamedAway) if (name) changeSet.deletes.push({
|
|
3321
3344
|
name,
|
|
@@ -3517,7 +3540,8 @@ function loadSecretsState(scope) {
|
|
|
3517
3540
|
function saveSecretsState(scope, state) {
|
|
3518
3541
|
if (!scope.applicationId) return;
|
|
3519
3542
|
const filePath = getSecretsStatePath(scope);
|
|
3520
|
-
|
|
3543
|
+
const dir = path.dirname(filePath);
|
|
3544
|
+
mkdirSync(dir, { recursive: true });
|
|
3521
3545
|
const tempPath = `${filePath}.tmp-${randomUUID()}`;
|
|
3522
3546
|
writeFileSync(tempPath, JSON.stringify({
|
|
3523
3547
|
version: 2,
|
|
@@ -3544,9 +3568,9 @@ function serializeUpdateTime(updateTime) {
|
|
|
3544
3568
|
return updateTime === void 0 ? void 0 : `${updateTime.seconds}.${updateTime.nanos}`;
|
|
3545
3569
|
}
|
|
3546
3570
|
const LOCK_POLL_INTERVAL_MS = 100;
|
|
3547
|
-
const LOCK_ACQUIRE_TIMEOUT_MS =
|
|
3548
|
-
const LOCK_HEARTBEAT_INTERVAL_MS =
|
|
3549
|
-
const LOCK_LEASE_MS =
|
|
3571
|
+
const LOCK_ACQUIRE_TIMEOUT_MS = 3e5;
|
|
3572
|
+
const LOCK_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
3573
|
+
const LOCK_LEASE_MS = 6e4;
|
|
3550
3574
|
const lockQueues = /* @__PURE__ */ new Map();
|
|
3551
3575
|
/**
|
|
3552
3576
|
* Run a remote-update/state-save sequence exclusively for one target's secrets state.
|
|
@@ -3862,7 +3886,7 @@ async function applyAuthConnections(client, result, phase) {
|
|
|
3862
3886
|
|
|
3863
3887
|
//#endregion
|
|
3864
3888
|
//#region src/cli/commands/deploy/function-registry.ts
|
|
3865
|
-
const CHUNK_SIZE$1 =
|
|
3889
|
+
const CHUNK_SIZE$1 = 65536;
|
|
3866
3890
|
/**
|
|
3867
3891
|
* Compute SHA-256 content hash for a script string.
|
|
3868
3892
|
* @param content - Script content to hash
|
|
@@ -4761,9 +4785,7 @@ async function planServices$3(client, workspaceId, appName, appId, idps, idpUser
|
|
|
4761
4785
|
case void 0:
|
|
4762
4786
|
authorization = void 0;
|
|
4763
4787
|
break;
|
|
4764
|
-
default:
|
|
4765
|
-
authorization = idp.authorization.cel;
|
|
4766
|
-
break;
|
|
4788
|
+
default: authorization = idp.authorization.cel;
|
|
4767
4789
|
}
|
|
4768
4790
|
const lang = convertLang(idp.lang);
|
|
4769
4791
|
const userAuthPolicy = idp.userAuthPolicy;
|
|
@@ -4987,23 +5009,25 @@ function protoIdPCondition(condition) {
|
|
|
4987
5009
|
};
|
|
4988
5010
|
}
|
|
4989
5011
|
function protoIdPOperand(operand) {
|
|
4990
|
-
if (typeof operand === "object" && !Array.isArray(operand))
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5012
|
+
if (typeof operand === "object" && !Array.isArray(operand)) {
|
|
5013
|
+
if ("user" in operand) return { kind: {
|
|
5014
|
+
case: "userField",
|
|
5015
|
+
value: operand.user
|
|
5016
|
+
} };
|
|
5017
|
+
else if ("idpUser" in operand) return { kind: {
|
|
5018
|
+
case: "idpUserField",
|
|
5019
|
+
value: operand.idpUser
|
|
5020
|
+
} };
|
|
5021
|
+
else if ("newIdpUser" in operand) return { kind: {
|
|
5022
|
+
case: "newIdpUserField",
|
|
5023
|
+
value: operand.newIdpUser
|
|
5024
|
+
} };
|
|
5025
|
+
else if ("oldIdpUser" in operand) return { kind: {
|
|
5026
|
+
case: "oldIdpUserField",
|
|
5027
|
+
value: operand.oldIdpUser
|
|
5028
|
+
} };
|
|
5029
|
+
else throw new Error(`Unknown operand: ${JSON.stringify(operand)}`);
|
|
5030
|
+
}
|
|
5007
5031
|
return { kind: {
|
|
5008
5032
|
case: "value",
|
|
5009
5033
|
value: fromJson(ValueSchema, operand)
|
|
@@ -6077,12 +6101,13 @@ async function planAuthHooks(client, workspaceId, auths, deletedServices, forceA
|
|
|
6077
6101
|
}
|
|
6078
6102
|
}
|
|
6079
6103
|
};
|
|
6080
|
-
if (existingHook)
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6104
|
+
if (existingHook) {
|
|
6105
|
+
if (!forceApplyAll && areAuthHooksEqual(existingHook, hookRequest.hook)) changeSet.unchanged.push({ name: `${config.name}/before-login` });
|
|
6106
|
+
else changeSet.updates.push({
|
|
6107
|
+
name: `${config.name}/before-login`,
|
|
6108
|
+
request: hookRequest
|
|
6109
|
+
});
|
|
6110
|
+
} else changeSet.creates.push({
|
|
6086
6111
|
name: `${config.name}/before-login`,
|
|
6087
6112
|
request: hookRequest
|
|
6088
6113
|
});
|
|
@@ -6337,9 +6362,9 @@ function resolveSameRunNamespace(sameRunNamespaces, resourceName, resourceLabel)
|
|
|
6337
6362
|
return namespace;
|
|
6338
6363
|
}
|
|
6339
6364
|
/**
|
|
6340
|
-
* Find the local TailorDB namespace that declares the given
|
|
6365
|
+
* Find the local TailorDB namespace that declares the given table.
|
|
6341
6366
|
* @param application - Loaded application
|
|
6342
|
-
* @param typeName - TailorDB
|
|
6367
|
+
* @param typeName - TailorDB table name to look up
|
|
6343
6368
|
* @returns The declaring namespace, or undefined when no local service has it
|
|
6344
6369
|
*/
|
|
6345
6370
|
function findTailorDBNamespace(application, typeName) {
|
|
@@ -6366,7 +6391,7 @@ function resolveNamespace(params) {
|
|
|
6366
6391
|
}
|
|
6367
6392
|
function resolveTailorDBNamespace(application, typeName, sameRunNamespaces) {
|
|
6368
6393
|
return resolveNamespace({
|
|
6369
|
-
resourceLabel: "TailorDB
|
|
6394
|
+
resourceLabel: "TailorDB table",
|
|
6370
6395
|
resourceName: typeName,
|
|
6371
6396
|
localNamespaces: application.tailorDBServices.map((service) => service.namespace),
|
|
6372
6397
|
findLocalNamespace: () => findTailorDBNamespace(application, typeName),
|
|
@@ -6410,11 +6435,6 @@ function resolveIdpNamespace(application, executorName, idpName, sameRunIdpNames
|
|
|
6410
6435
|
}
|
|
6411
6436
|
return assertDefined([...localIdpNames][0], "idp service missing");
|
|
6412
6437
|
}
|
|
6413
|
-
function resolveAuthNamespace(application) {
|
|
6414
|
-
const authNamespace = getApplicationAuthNamespace(application);
|
|
6415
|
-
if (!authNamespace) throw new Error("No Auth service configured");
|
|
6416
|
-
return authNamespace;
|
|
6417
|
-
}
|
|
6418
6438
|
function protoExecutor(context, executor) {
|
|
6419
6439
|
const { application } = context;
|
|
6420
6440
|
const appName = application.name;
|
|
@@ -6490,7 +6510,7 @@ function protoExecutor(context, executor) {
|
|
|
6490
6510
|
case: "auth",
|
|
6491
6511
|
value: {
|
|
6492
6512
|
eventTypes: trigger.events,
|
|
6493
|
-
namespaceName:
|
|
6513
|
+
namespaceName: requireApplicationAuthNamespace(application)
|
|
6494
6514
|
}
|
|
6495
6515
|
});
|
|
6496
6516
|
break;
|
|
@@ -6782,8 +6802,9 @@ async function planResolvers(client, workspaceId, pipelines, executors, initialE
|
|
|
6782
6802
|
* @returns The resolver's metadata write
|
|
6783
6803
|
*/
|
|
6784
6804
|
const resolverMetaRequest = async (namespace, resolver) => {
|
|
6805
|
+
const trn = resolverTrn(workspaceId, namespace, resolver.name);
|
|
6785
6806
|
return addDependencyRecords(await buildMetaRequest({
|
|
6786
|
-
trn
|
|
6807
|
+
trn,
|
|
6787
6808
|
appName: appName ?? "",
|
|
6788
6809
|
appId
|
|
6789
6810
|
}), {
|
|
@@ -7202,18 +7223,22 @@ async function applySecretManager(client, result, phase = "create-update", appli
|
|
|
7202
7223
|
if (phase === "create-update") {
|
|
7203
7224
|
await Promise.all(vaultChangeSet.creates.map(async (create) => {
|
|
7204
7225
|
await client.createSecretManagerVault(vaultCreateRequest(create));
|
|
7205
|
-
if (application)
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7226
|
+
if (application) {
|
|
7227
|
+
const metaRequest = await buildMetaRequest({
|
|
7228
|
+
trn: resourceTrn(create.workspaceId, "vault", create.name),
|
|
7229
|
+
appName: application.name,
|
|
7230
|
+
appId: application.id
|
|
7231
|
+
});
|
|
7232
|
+
await writeMetadataLabels(client, metaRequest);
|
|
7233
|
+
}
|
|
7210
7234
|
}));
|
|
7211
7235
|
if (application) await Promise.all(vaultChangeSet.updates.map(async (update) => {
|
|
7212
|
-
|
|
7236
|
+
const metaRequest = await buildMetaRequest({
|
|
7213
7237
|
trn: resourceTrn(update.workspaceId, "vault", update.name),
|
|
7214
7238
|
appName: application.name,
|
|
7215
7239
|
appId: application.id
|
|
7216
|
-
})
|
|
7240
|
+
});
|
|
7241
|
+
await writeMetadataLabels(client, metaRequest);
|
|
7217
7242
|
}));
|
|
7218
7243
|
const secretHashUpdates = [...secretChangeSet.creates, ...secretChangeSet.updates];
|
|
7219
7244
|
if (secretHashUpdates.length > 0) await withSecretsStateLock(stateScope, async () => {
|
|
@@ -7419,20 +7444,22 @@ function buildValidateStatements(fields, accessExpr, keyPrefix) {
|
|
|
7419
7444
|
const checks = validators.map((v) => `{ const __r = (${v.script?.expr}); if (typeof __r === "string") { __errs[${key(fieldPath)}] = __r; } }`).join("\n");
|
|
7420
7445
|
statements.push(`{ const _value = ${access};\n${checks}\n}`);
|
|
7421
7446
|
}
|
|
7422
|
-
if (isNestedType(config) && config.fields)
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
const
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7447
|
+
if (isNestedType(config) && config.fields) {
|
|
7448
|
+
if (config.array) {
|
|
7449
|
+
const innerParts = [];
|
|
7450
|
+
for (const [innerName, innerConfig] of Object.entries(config.fields)) {
|
|
7451
|
+
const innerValidators = (innerConfig.validate ?? []).filter((v) => v.script?.expr);
|
|
7452
|
+
if (innerValidators.length > 0) {
|
|
7453
|
+
const errorKeyExpr = `${JSON.stringify(fieldPath + "[")} + __idx + ${JSON.stringify("]." + innerName)}`;
|
|
7454
|
+
const checks = innerValidators.map((v) => `{ const __r = (${v.script?.expr}); if (typeof __r === "string") { __errs[${errorKeyExpr}] = __r; } }`).join("\n");
|
|
7455
|
+
innerParts.push(`{ const _value = __el[${key(innerName)}];\n${checks}\n}`);
|
|
7456
|
+
}
|
|
7430
7457
|
}
|
|
7458
|
+
if (innerParts.length > 0) statements.push(`(${access} || []).forEach((__el, __idx) => {\n${innerParts.join("\n")}\n});`);
|
|
7459
|
+
} else {
|
|
7460
|
+
const nested = buildValidateStatements(config.fields, access, fieldPath);
|
|
7461
|
+
if (nested.length > 0) statements.push(`if (${access} != null) {\n${nested.join("\n")}\n}`);
|
|
7431
7462
|
}
|
|
7432
|
-
if (innerParts.length > 0) statements.push(`(${access} || []).forEach((__el, __idx) => {\n${innerParts.join("\n")}\n});`);
|
|
7433
|
-
} else {
|
|
7434
|
-
const nested = buildValidateStatements(config.fields, access, fieldPath);
|
|
7435
|
-
if (nested.length > 0) statements.push(`if (${access} != null) {\n${nested.join("\n")}\n}`);
|
|
7436
7463
|
}
|
|
7437
7464
|
}
|
|
7438
7465
|
return statements;
|
|
@@ -7451,13 +7478,13 @@ function wrapValidate(statements, typeValidateExpr) {
|
|
|
7451
7478
|
}
|
|
7452
7479
|
/**
|
|
7453
7480
|
* Aggregate every field's create/update hook, default, and validate into
|
|
7454
|
-
*
|
|
7481
|
+
* table-level scripts. Hooks compute a single shared timestamp (`now`) per
|
|
7455
7482
|
* operation, so all fields touched in one create/update observe the same
|
|
7456
7483
|
* instant. Defaults are applied after hooks on create only. Validators
|
|
7457
7484
|
* run with the same rules on create and update.
|
|
7458
7485
|
* @param fields - Per-field script configuration
|
|
7459
|
-
* @param options - Optional
|
|
7460
|
-
* @returns Aggregated
|
|
7486
|
+
* @param options - Optional table-level hook/validate expressions
|
|
7487
|
+
* @returns Aggregated table-level scripts
|
|
7461
7488
|
*/
|
|
7462
7489
|
function buildTypeScripts(fields, options) {
|
|
7463
7490
|
const result = {};
|
|
@@ -7792,13 +7819,13 @@ function isSnapshotFieldRefOperand(operand) {
|
|
|
7792
7819
|
//#endregion
|
|
7793
7820
|
//#region src/cli/commands/tailordb/migrate/rename-detection.ts
|
|
7794
7821
|
/**
|
|
7795
|
-
* Field and
|
|
7822
|
+
* Field and table rename detection for TailorDB migrations
|
|
7796
7823
|
*
|
|
7797
7824
|
* A rename has no dedicated platform API, so the diff decomposes it into
|
|
7798
|
-
* `field_removed` + `field_added` (`table_removed` + `table_added` for
|
|
7825
|
+
* `field_removed` + `field_added` (`table_removed` + `table_added` for tables).
|
|
7799
7826
|
* This module detects removed/added pairs that are compatible enough to be a
|
|
7800
7827
|
* rename so that `migration generate` can ask the user (or accept
|
|
7801
|
-
* `--rename
|
|
7828
|
+
* `--rename Table.oldField:newField` / `--rename OldTable:NewTable`) and record a single
|
|
7802
7829
|
* `field_renamed` / `table_renamed` change instead.
|
|
7803
7830
|
*/
|
|
7804
7831
|
/** Modifiers a rename may change, since the Pre-phase relaxes them. */
|
|
@@ -7909,7 +7936,7 @@ function assertValidFieldRenames(previous, current, fieldRenames) {
|
|
|
7909
7936
|
}
|
|
7910
7937
|
const prevType = previous.tables[tableName];
|
|
7911
7938
|
const currType = current.tables[tableName];
|
|
7912
|
-
if (!prevType || !currType) throw new Error(`Cannot rename ${label}:
|
|
7939
|
+
if (!prevType || !currType) throw new Error(`Cannot rename ${label}: table "${tableName}" must exist in both the previous and the current schema.`);
|
|
7913
7940
|
const prevField = prevType.fields[previousFieldName];
|
|
7914
7941
|
if (!prevField) throw new Error(`Cannot rename ${label}: field "${previousFieldName}" does not exist in the previous schema.`);
|
|
7915
7942
|
if (currType.fields[previousFieldName]) throw new Error(`Cannot rename ${label}: field "${previousFieldName}" still exists in the current schema.`);
|
|
@@ -7921,13 +7948,13 @@ function assertValidFieldRenames(previous, current, fieldRenames) {
|
|
|
7921
7948
|
}
|
|
7922
7949
|
const RENAME_OPTION_PATTERN = /^([^.:\s]+)\.([^.:\s]+):([^.:\s]+)$/;
|
|
7923
7950
|
/**
|
|
7924
|
-
* Parse a `--rename` option value of the form `
|
|
7951
|
+
* Parse a `--rename` option value of the form `Table.oldField:newField`.
|
|
7925
7952
|
* @param {string} value - Raw option value
|
|
7926
7953
|
* @returns {FieldRenameSpec} Parsed rename spec
|
|
7927
7954
|
*/
|
|
7928
7955
|
function parseRenameOption(value) {
|
|
7929
7956
|
const [, tableName, previousFieldName, fieldName] = value.match(RENAME_OPTION_PATTERN) ?? [];
|
|
7930
|
-
if (!tableName || !previousFieldName || !fieldName) throw new Error(`Invalid --rename value "${value}". Expected format: "
|
|
7957
|
+
if (!tableName || !previousFieldName || !fieldName) throw new Error(`Invalid --rename value "${value}". Expected format: "Table.oldField:newField".`);
|
|
7931
7958
|
if (previousFieldName === fieldName) throw new Error(`Invalid --rename value "${value}": old and new field names are identical.`);
|
|
7932
7959
|
return {
|
|
7933
7960
|
tableName,
|
|
@@ -7937,13 +7964,13 @@ function parseRenameOption(value) {
|
|
|
7937
7964
|
}
|
|
7938
7965
|
const DROP_OPTION_PATTERN = /^([^.:\s]+)\.([^.:\s]+)$/;
|
|
7939
7966
|
/**
|
|
7940
|
-
* Parse a `--drop` option value of the form `
|
|
7967
|
+
* Parse a `--drop` option value of the form `Table.field`.
|
|
7941
7968
|
* @param {string} value - Raw option value
|
|
7942
7969
|
* @returns {FieldDropSpec} Parsed drop spec
|
|
7943
7970
|
*/
|
|
7944
7971
|
function parseDropOption(value) {
|
|
7945
7972
|
const [, tableName, fieldName] = value.match(DROP_OPTION_PATTERN) ?? [];
|
|
7946
|
-
if (!tableName || !fieldName) throw new Error(`Invalid --drop value "${value}". Expected format: "
|
|
7973
|
+
if (!tableName || !fieldName) throw new Error(`Invalid --drop value "${value}". Expected format: "Table.field".`);
|
|
7947
7974
|
return {
|
|
7948
7975
|
tableName,
|
|
7949
7976
|
fieldName
|
|
@@ -7963,13 +7990,13 @@ function dropSpecApplies(spec, previousSnapshot, currentSnapshot) {
|
|
|
7963
7990
|
return Boolean(prevFields?.[spec.fieldName] && !currFields?.[spec.fieldName]);
|
|
7964
7991
|
}
|
|
7965
7992
|
/**
|
|
7966
|
-
* Parse an `--expand-contract` option value of the form `
|
|
7993
|
+
* Parse an `--expand-contract` option value of the form `Table.field`.
|
|
7967
7994
|
* @param {string} value - Raw option value
|
|
7968
7995
|
* @returns {FieldExpandContractSpec} Parsed spec
|
|
7969
7996
|
*/
|
|
7970
7997
|
function parseExpandContractOption(value) {
|
|
7971
7998
|
const [, tableName, fieldName] = value.match(DROP_OPTION_PATTERN) ?? [];
|
|
7972
|
-
if (!tableName || !fieldName) throw new Error(`Invalid --expand-contract value "${value}". Expected format: "
|
|
7999
|
+
if (!tableName || !fieldName) throw new Error(`Invalid --expand-contract value "${value}". Expected format: "Table.field".`);
|
|
7973
8000
|
return {
|
|
7974
8001
|
tableName,
|
|
7975
8002
|
fieldName
|
|
@@ -8088,16 +8115,16 @@ function assertValidTypeRenames(previous, current, typeRenames) {
|
|
|
8088
8115
|
const { previousTableName, tableName } = rename;
|
|
8089
8116
|
const label = `${previousTableName}:${tableName}`;
|
|
8090
8117
|
for (const key of [previousTableName, tableName]) {
|
|
8091
|
-
if (seen.has(key)) throw new Error(`
|
|
8118
|
+
if (seen.has(key)) throw new Error(`Table "${key}" appears in more than one rename.`);
|
|
8092
8119
|
seen.add(key);
|
|
8093
8120
|
}
|
|
8094
8121
|
const prevType = previous.tables[previousTableName];
|
|
8095
|
-
if (!prevType) throw new Error(`Cannot rename ${label}:
|
|
8096
|
-
if (current.tables[previousTableName]) throw new Error(`Cannot rename ${label}:
|
|
8122
|
+
if (!prevType) throw new Error(`Cannot rename ${label}: table "${previousTableName}" does not exist in the previous schema.`);
|
|
8123
|
+
if (current.tables[previousTableName]) throw new Error(`Cannot rename ${label}: table "${previousTableName}" still exists in the current schema.`);
|
|
8097
8124
|
const currType = current.tables[tableName];
|
|
8098
|
-
if (!currType) throw new Error(`Cannot rename ${label}:
|
|
8099
|
-
if (previous.tables[tableName]) throw new Error(`Cannot rename ${label}:
|
|
8100
|
-
if (!isTypeRenameCompatible(prevType, currType)) throw new Error(`Cannot rename ${label}: the
|
|
8125
|
+
if (!currType) throw new Error(`Cannot rename ${label}: table "${tableName}" does not exist in the current schema.`);
|
|
8126
|
+
if (previous.tables[tableName]) throw new Error(`Cannot rename ${label}: table "${tableName}" already exists in the previous schema.`);
|
|
8127
|
+
if (!isTypeRenameCompatible(prevType, currType)) throw new Error(`Cannot rename ${label}: the tables are not rename-compatible (every field must keep its name, type, array-ness, required/unique constraints, foreign key target, and scale, enum values must not be removed, indexes must match, self-referential foreign keys must be optional, and tables with serial or file fields cannot be renamed).`);
|
|
8101
8128
|
}
|
|
8102
8129
|
}
|
|
8103
8130
|
/**
|
|
@@ -8117,14 +8144,14 @@ function isBreakingForeignKeyRetarget(before, after, typeRenameTargets) {
|
|
|
8117
8144
|
}
|
|
8118
8145
|
const TYPE_RENAME_OPTION_PATTERN = /^([^.:\s]+):([^.:\s]+)$/;
|
|
8119
8146
|
/**
|
|
8120
|
-
* Parse a `--rename` option value of the form `
|
|
8147
|
+
* Parse a `--rename` option value of the form `OldTable:NewTable`.
|
|
8121
8148
|
* @param {string} value - Raw option value
|
|
8122
8149
|
* @returns {TypeRenameSpec} Parsed rename spec
|
|
8123
8150
|
*/
|
|
8124
8151
|
function parseTypeRenameOption(value) {
|
|
8125
8152
|
const [, previousTableName, tableName] = value.match(TYPE_RENAME_OPTION_PATTERN) ?? [];
|
|
8126
|
-
if (!previousTableName || !tableName) throw new Error(`Invalid --rename value "${value}". Expected format: "
|
|
8127
|
-
if (previousTableName === tableName) throw new Error(`Invalid --rename value "${value}": old and new
|
|
8153
|
+
if (!previousTableName || !tableName) throw new Error(`Invalid --rename value "${value}". Expected format: "Table.oldField:newField" or "OldTable:NewTable".`);
|
|
8154
|
+
if (previousTableName === tableName) throw new Error(`Invalid --rename value "${value}": old and new table names are identical.`);
|
|
8128
8155
|
return {
|
|
8129
8156
|
previousTableName,
|
|
8130
8157
|
tableName
|
|
@@ -8132,13 +8159,13 @@ function parseTypeRenameOption(value) {
|
|
|
8132
8159
|
}
|
|
8133
8160
|
const TYPE_DROP_OPTION_PATTERN = /^([^.:\s]+)$/;
|
|
8134
8161
|
/**
|
|
8135
|
-
* Parse a `--drop` option value of the form `
|
|
8162
|
+
* Parse a `--drop` option value of the form `Table`.
|
|
8136
8163
|
* @param {string} value - Raw option value
|
|
8137
8164
|
* @returns {TypeDropSpec} Parsed drop spec
|
|
8138
8165
|
*/
|
|
8139
8166
|
function parseTypeDropOption(value) {
|
|
8140
8167
|
const [, tableName] = value.match(TYPE_DROP_OPTION_PATTERN) ?? [];
|
|
8141
|
-
if (!tableName) throw new Error(`Invalid --drop value "${value}". Expected format: "
|
|
8168
|
+
if (!tableName) throw new Error(`Invalid --drop value "${value}". Expected format: "Table.field" or "Table".`);
|
|
8142
8169
|
return { tableName };
|
|
8143
8170
|
}
|
|
8144
8171
|
/**
|
|
@@ -8802,15 +8829,15 @@ function normalizeSnapshotField(field) {
|
|
|
8802
8829
|
};
|
|
8803
8830
|
}
|
|
8804
8831
|
/**
|
|
8805
|
-
* Normalize a snapshot
|
|
8832
|
+
* Normalize a snapshot table into the canonical comparison shape, returning a
|
|
8806
8833
|
* new object rather than mutating the input. Currently fills:
|
|
8807
8834
|
* - `pluralForm` via inflection when missing (legacy snapshots written
|
|
8808
8835
|
* before `pluralForm` became required may omit it)
|
|
8809
8836
|
* - per-field `scale` defaults via {@link normalizeSnapshotField}
|
|
8810
8837
|
*
|
|
8811
8838
|
* Idempotent — safe to call multiple times on the same input.
|
|
8812
|
-
* @param {TailorDBSnapshotType} type - Snapshot
|
|
8813
|
-
* @returns {TailorDBSnapshotType} A new, normalized snapshot
|
|
8839
|
+
* @param {TailorDBSnapshotType} type - Snapshot table to normalize
|
|
8840
|
+
* @returns {TailorDBSnapshotType} A new, normalized snapshot table object
|
|
8814
8841
|
*/
|
|
8815
8842
|
function normalizeSnapshotType(type) {
|
|
8816
8843
|
const pluralForm = type.pluralForm || inflection.pluralize(type.name);
|
|
@@ -8922,9 +8949,9 @@ function createSnapshotFieldConfigFromOperatorConfig(fieldConfig) {
|
|
|
8922
8949
|
return normalizeSnapshotField(config);
|
|
8923
8950
|
}
|
|
8924
8951
|
/**
|
|
8925
|
-
* Create a snapshot
|
|
8926
|
-
* @param {TailorDBType} type - Parsed TailorDB
|
|
8927
|
-
* @returns {TailorDBSnapshotType} Snapshot
|
|
8952
|
+
* Create a snapshot table from a parsed table
|
|
8953
|
+
* @param {TailorDBType} type - Parsed TailorDB table definition
|
|
8954
|
+
* @returns {TailorDBSnapshotType} Snapshot table configuration
|
|
8928
8955
|
*/
|
|
8929
8956
|
function createSnapshotType(type) {
|
|
8930
8957
|
const fields = createSnapshotRecord();
|
|
@@ -9008,8 +9035,8 @@ function convertActionPermission(permission) {
|
|
|
9008
9035
|
};
|
|
9009
9036
|
}
|
|
9010
9037
|
/**
|
|
9011
|
-
* Create a schema snapshot from local
|
|
9012
|
-
* @param {Record<string, TailorDBType>} types - Local
|
|
9038
|
+
* Create a schema snapshot from local table definitions
|
|
9039
|
+
* @param {Record<string, TailorDBType>} types - Local table definitions
|
|
9013
9040
|
* @param {string} namespace - Namespace for the snapshot
|
|
9014
9041
|
* @returns {NormalizedSchemaSnapshot} Normalized schema snapshot
|
|
9015
9042
|
*/
|
|
@@ -9067,7 +9094,7 @@ function loadDiff(filePath) {
|
|
|
9067
9094
|
};
|
|
9068
9095
|
}
|
|
9069
9096
|
const FIELD_REMOVED_WARNING_REASON = "Field removed (existing data will no longer be accessible through the schema)";
|
|
9070
|
-
const TABLE_REMOVED_WARNING_REASON = "
|
|
9097
|
+
const TABLE_REMOVED_WARNING_REASON = "Table removed (all records in this table will be deleted during post-migration cleanup)";
|
|
9071
9098
|
/**
|
|
9072
9099
|
* Reconstruct data-loss warnings from removal changes for diff.json files
|
|
9073
9100
|
* written before the warning tier existed
|
|
@@ -9449,11 +9476,11 @@ function areFieldsDifferent(oldField, newField) {
|
|
|
9449
9476
|
}
|
|
9450
9477
|
/**
|
|
9451
9478
|
* Collect breaking changes for a field change
|
|
9452
|
-
* @param {string} tableName - Name of the
|
|
9479
|
+
* @param {string} tableName - Name of the table containing the field
|
|
9453
9480
|
* @param {string} fieldName - Name of the field being changed
|
|
9454
9481
|
* @param {SnapshotFieldConfig | undefined} oldField - Old field configuration
|
|
9455
9482
|
* @param {SnapshotFieldConfig | undefined} newField - New field configuration
|
|
9456
|
-
* @param {ReadonlyMap<string, string>} [typeRenameTargets] - Confirmed
|
|
9483
|
+
* @param {ReadonlyMap<string, string>} [typeRenameTargets] - Confirmed table renames (old name → new name)
|
|
9457
9484
|
* @returns {BreakingChangeInfo[]} Breaking change information
|
|
9458
9485
|
*/
|
|
9459
9486
|
function getBreakingFieldChanges(tableName, fieldName, oldField, newField, typeRenameTargets) {
|
|
@@ -9593,11 +9620,11 @@ function compareTypeFields(ctx, tableName, prevType, currType, fieldRenames = []
|
|
|
9593
9620
|
}
|
|
9594
9621
|
}
|
|
9595
9622
|
/**
|
|
9596
|
-
* Determine if a
|
|
9623
|
+
* Determine if a table-level index change is breaking. Mirrors the field-level
|
|
9597
9624
|
* unique reasoning: enforcing a unique constraint over existing rows can fail
|
|
9598
9625
|
* on duplicates, so both adding a unique index and re-pointing an existing
|
|
9599
9626
|
* unique index at a different field set require a data migration.
|
|
9600
|
-
* @param {string} tableName - Name of the
|
|
9627
|
+
* @param {string} tableName - Name of the table containing the index
|
|
9601
9628
|
* @param {string} indexName - Name of the index being changed
|
|
9602
9629
|
* @param {SnapshotIndexConfig | undefined} oldIndex - Old index configuration
|
|
9603
9630
|
* @param {SnapshotIndexConfig | undefined} newIndex - New index configuration
|
|
@@ -9616,9 +9643,9 @@ function isBreakingIndexChange(tableName, indexName, oldIndex, newIndex) {
|
|
|
9616
9643
|
return null;
|
|
9617
9644
|
}
|
|
9618
9645
|
/**
|
|
9619
|
-
* Compare
|
|
9646
|
+
* Compare table-level indexes
|
|
9620
9647
|
* @param {DiffContext} ctx - Diff context
|
|
9621
|
-
* @param {string} tableName -
|
|
9648
|
+
* @param {string} tableName - Table name
|
|
9622
9649
|
* @param {Record<string, SnapshotIndexConfig> | undefined} oldIndexes - Previous indexes
|
|
9623
9650
|
* @param {Record<string, SnapshotIndexConfig> | undefined} newIndexes - Current indexes
|
|
9624
9651
|
* @returns {void}
|
|
@@ -9664,9 +9691,9 @@ function compareIndexes(ctx, tableName, oldIndexes, newIndexes) {
|
|
|
9664
9691
|
}
|
|
9665
9692
|
}
|
|
9666
9693
|
/**
|
|
9667
|
-
* Compare
|
|
9694
|
+
* Compare table-level file fields
|
|
9668
9695
|
* @param {DiffContext} ctx - Diff context
|
|
9669
|
-
* @param {string} tableName -
|
|
9696
|
+
* @param {string} tableName - Table name
|
|
9670
9697
|
* @param {Record<string, string> | undefined} oldFiles - Previous file fields
|
|
9671
9698
|
* @param {Record<string, string> | undefined} newFiles - Current file fields
|
|
9672
9699
|
* @returns {void}
|
|
@@ -9699,9 +9726,9 @@ function compareFiles(ctx, tableName, oldFiles, newFiles) {
|
|
|
9699
9726
|
}
|
|
9700
9727
|
}
|
|
9701
9728
|
/**
|
|
9702
|
-
* Compare
|
|
9729
|
+
* Compare table-level relationships
|
|
9703
9730
|
* @param {DiffContext} ctx - Diff context
|
|
9704
|
-
* @param {string} tableName -
|
|
9731
|
+
* @param {string} tableName - Table name
|
|
9705
9732
|
* @param {"forward" | "backward"} relationshipType - Relationship direction to compare
|
|
9706
9733
|
* @param {Record<string, SnapshotRelationship> | undefined} oldRelationships - Previous relationships
|
|
9707
9734
|
* @param {Record<string, SnapshotRelationship> | undefined} newRelationships - Current relationships
|
|
@@ -9744,9 +9771,9 @@ function compareRelationships(ctx, tableName, relationshipType, oldRelationships
|
|
|
9744
9771
|
}
|
|
9745
9772
|
}
|
|
9746
9773
|
/**
|
|
9747
|
-
* Compare
|
|
9774
|
+
* Compare table-level permissions
|
|
9748
9775
|
* @param {DiffContext} ctx - Diff context
|
|
9749
|
-
* @param {string} tableName -
|
|
9776
|
+
* @param {string} tableName - Table name
|
|
9750
9777
|
* @param {SnapshotRecordPermission | undefined} oldRecordPerm - Previous record permission
|
|
9751
9778
|
* @param {SnapshotRecordPermission | undefined} newRecordPerm - Current record permission
|
|
9752
9779
|
* @param {SnapshotGqlPermission | undefined} oldGqlPerm - Previous GQL permission
|
|
@@ -9993,8 +10020,8 @@ function compareSnapshots(previous, current, options) {
|
|
|
9993
10020
|
const previousTypeNames = new Set(Object.keys(previous.tables));
|
|
9994
10021
|
const currentTypeNames = new Set(Object.keys(current.tables));
|
|
9995
10022
|
for (const rename of typeRenames) {
|
|
9996
|
-
const prevType = assertDefined(previous.tables[rename.previousTableName], `renamed
|
|
9997
|
-
const currType = assertDefined(current.tables[rename.tableName], `renamed
|
|
10023
|
+
const prevType = assertDefined(previous.tables[rename.previousTableName], `renamed table "${rename.previousTableName}" missing from previous snapshot`);
|
|
10024
|
+
const currType = assertDefined(current.tables[rename.tableName], `renamed table "${rename.tableName}" missing from current snapshot`);
|
|
9998
10025
|
ctx.changes.push({
|
|
9999
10026
|
kind: "table_renamed",
|
|
10000
10027
|
tableName: rename.tableName,
|
|
@@ -10004,7 +10031,7 @@ function compareSnapshots(previous, current, options) {
|
|
|
10004
10031
|
});
|
|
10005
10032
|
ctx.breakingChanges.push({
|
|
10006
10033
|
tableName: rename.tableName,
|
|
10007
|
-
reason: `
|
|
10034
|
+
reason: `Table renamed from ${rename.previousTableName} to ${rename.tableName} (existing records must be copied by the migration script)`
|
|
10008
10035
|
});
|
|
10009
10036
|
ctx.breakingChanges.push({
|
|
10010
10037
|
tableName: rename.tableName,
|
|
@@ -10035,8 +10062,8 @@ function compareSnapshots(previous, current, options) {
|
|
|
10035
10062
|
}
|
|
10036
10063
|
for (const tableName of currentTypeNames) {
|
|
10037
10064
|
if (!previousTypeNames.has(tableName)) continue;
|
|
10038
|
-
const prevType = assertDefined(previous.tables[tableName], `
|
|
10039
|
-
const currType = assertDefined(current.tables[tableName], `
|
|
10065
|
+
const prevType = assertDefined(previous.tables[tableName], `table "${tableName}" missing from previous snapshot`);
|
|
10066
|
+
const currType = assertDefined(current.tables[tableName], `table "${tableName}" missing from current snapshot`);
|
|
10040
10067
|
compareTypeSettings(ctx, tableName, prevType, currType);
|
|
10041
10068
|
compareTypeScripts(ctx, tableName, prevType, currType);
|
|
10042
10069
|
compareTypeFields(ctx, tableName, prevType, currType, renamesByType.get(tableName));
|
|
@@ -10059,13 +10086,13 @@ function compareSnapshots(previous, current, options) {
|
|
|
10059
10086
|
};
|
|
10060
10087
|
}
|
|
10061
10088
|
/**
|
|
10062
|
-
* Compare a snapshot against canonical TailorDBSnapshotType-shaped local
|
|
10089
|
+
* Compare a snapshot against canonical TailorDBSnapshotType-shaped local tables.
|
|
10063
10090
|
* Callers are expected to pre-convert TailorDBService.types to TailorDBSnapshotType via
|
|
10064
10091
|
* `createSnapshotType`. As a safety net, both sides are re-run through idempotent
|
|
10065
10092
|
* normalization here, so a caller that forgets will still get correct
|
|
10066
10093
|
* comparisons (no silent false drift).
|
|
10067
10094
|
* @param {SchemaSnapshot} snapshot - Schema snapshot to compare against
|
|
10068
|
-
* @param {Record<string, TailorDBSnapshotType>} localTypes - Local snapshot-shaped
|
|
10095
|
+
* @param {Record<string, TailorDBSnapshotType>} localTypes - Local snapshot-shaped tables
|
|
10069
10096
|
* @param {string} namespace - Namespace for comparison
|
|
10070
10097
|
* @returns {MigrationDiff} Migration diff
|
|
10071
10098
|
*/
|
|
@@ -10186,7 +10213,7 @@ function convertRemoteFieldToSnapshot(remoteField) {
|
|
|
10186
10213
|
}
|
|
10187
10214
|
/**
|
|
10188
10215
|
* Convert remote ParsedTailorDBType to SnapshotFieldConfig for comparison
|
|
10189
|
-
* @param {ProtoTailorDBType} remoteType - Remote TailorDB
|
|
10216
|
+
* @param {ProtoTailorDBType} remoteType - Remote TailorDB table from API
|
|
10190
10217
|
* @returns {Record<string, SnapshotFieldConfig>} Converted field configs
|
|
10191
10218
|
*/
|
|
10192
10219
|
function convertRemoteFieldsToSnapshot(remoteType) {
|
|
@@ -10369,8 +10396,8 @@ function convertRemoteTypeToSnapshot(remoteType, expectedType) {
|
|
|
10369
10396
|
return snapshotType;
|
|
10370
10397
|
}
|
|
10371
10398
|
/**
|
|
10372
|
-
* Convert remote TailorDB
|
|
10373
|
-
* @param {ProtoTailorDBType[]} remoteTypes - Remote TailorDB
|
|
10399
|
+
* Convert remote TailorDB tables into the normalized snapshot shape used by drift checks.
|
|
10400
|
+
* @param {ProtoTailorDBType[]} remoteTypes - Remote TailorDB tables from the API
|
|
10374
10401
|
* @param {string} namespace - Namespace for the reconstructed snapshot
|
|
10375
10402
|
* @param {readonly RemoteGqlPermission[]} remoteGqlPermissions - Remote GQL permissions for the namespace
|
|
10376
10403
|
* @param {SchemaSnapshot} expectedSnapshot - Optional snapshot used to disambiguate remote relationship direction
|
|
@@ -10494,7 +10521,7 @@ function addFieldDifferences(differences, prefix, remoteField, snapshotField) {
|
|
|
10494
10521
|
}
|
|
10495
10522
|
/**
|
|
10496
10523
|
* Compare a single field between remote and snapshot
|
|
10497
|
-
* @param {string} tableName - Name of the
|
|
10524
|
+
* @param {string} tableName - Name of the table
|
|
10498
10525
|
* @param {string} fieldName - Name of the field
|
|
10499
10526
|
* @param {SnapshotFieldConfig} remoteField - Remote field config
|
|
10500
10527
|
* @param {SnapshotFieldConfig} snapshotField - Snapshot field config
|
|
@@ -10516,8 +10543,8 @@ function compareFields(tableName, fieldName, remoteField, snapshotField) {
|
|
|
10516
10543
|
*/
|
|
10517
10544
|
const SYSTEM_FIELDS = /* @__PURE__ */ new Set(["id"]);
|
|
10518
10545
|
/**
|
|
10519
|
-
* Compare remote TailorDB
|
|
10520
|
-
* @param {ProtoTailorDBType[]} remoteTypes - Remote
|
|
10546
|
+
* Compare remote TailorDB tables with a local snapshot
|
|
10547
|
+
* @param {ProtoTailorDBType[]} remoteTypes - Remote tables from listParsedTailorDBTypes API
|
|
10521
10548
|
* @param {SchemaSnapshot} snapshot - Local schema snapshot
|
|
10522
10549
|
* @param {readonly RemoteGqlPermission[]} remoteGqlPermissions - Remote GQL permissions for the namespace
|
|
10523
10550
|
* @returns {SchemaDrift[]} List of drifts detected
|
|
@@ -10562,12 +10589,12 @@ function compareScriptHashes(remoteTypes, snapshot) {
|
|
|
10562
10589
|
if (localHash !== remoteHash) drifts.push({
|
|
10563
10590
|
tableName,
|
|
10564
10591
|
kind: "script_mismatch",
|
|
10565
|
-
details: remoteHash ? `
|
|
10592
|
+
details: remoteHash ? `Table '${tableName}' scripts differ between remote and snapshot` : `Table '${tableName}' has no script hash on remote`
|
|
10566
10593
|
});
|
|
10567
10594
|
} else if (remoteHasScripts(remoteType)) drifts.push({
|
|
10568
10595
|
tableName,
|
|
10569
10596
|
kind: "script_mismatch",
|
|
10570
|
-
details: `
|
|
10597
|
+
details: `Table '${tableName}' has scripts on remote but not in snapshot`
|
|
10571
10598
|
});
|
|
10572
10599
|
}
|
|
10573
10600
|
return drifts;
|
|
@@ -10616,23 +10643,23 @@ function schemaDriftFromDiffChange(change) {
|
|
|
10616
10643
|
case "table_added": return {
|
|
10617
10644
|
tableName: change.tableName,
|
|
10618
10645
|
kind: "type_missing_remote",
|
|
10619
|
-
details: `
|
|
10646
|
+
details: `Table '${change.tableName}' exists in snapshot but not in remote`
|
|
10620
10647
|
};
|
|
10621
10648
|
case "table_removed": return {
|
|
10622
10649
|
tableName: change.tableName,
|
|
10623
10650
|
kind: "type_missing_local",
|
|
10624
|
-
details: `
|
|
10651
|
+
details: `Table '${change.tableName}' exists in remote but not in snapshot`
|
|
10625
10652
|
};
|
|
10626
10653
|
case "table_renamed": return {
|
|
10627
10654
|
tableName: change.tableName,
|
|
10628
10655
|
kind: "type_settings_mismatch",
|
|
10629
|
-
details: `
|
|
10656
|
+
details: `Table '${change.previousTableName}' was renamed to '${change.tableName}'`
|
|
10630
10657
|
};
|
|
10631
10658
|
case "table_settings_modified":
|
|
10632
10659
|
case "table_modified": return {
|
|
10633
10660
|
tableName: change.tableName,
|
|
10634
10661
|
kind: "type_settings_mismatch",
|
|
10635
|
-
details: change.reason ?? "
|
|
10662
|
+
details: change.reason ?? "Table settings differ between remote and snapshot"
|
|
10636
10663
|
};
|
|
10637
10664
|
case "field_added": return {
|
|
10638
10665
|
tableName: change.tableName,
|
|
@@ -10719,7 +10746,7 @@ function schemaDriftFromDiffChange(change) {
|
|
|
10719
10746
|
case "table_scripts_modified": return {
|
|
10720
10747
|
tableName: change.tableName,
|
|
10721
10748
|
kind: "script_mismatch",
|
|
10722
|
-
details: change.reason ?? "
|
|
10749
|
+
details: change.reason ?? "Table-level scripts differ between remote and snapshot"
|
|
10723
10750
|
};
|
|
10724
10751
|
default: throw new Error("Unsupported diff change");
|
|
10725
10752
|
}
|
|
@@ -10742,7 +10769,7 @@ function formatSchemaDrifts(drifts) {
|
|
|
10742
10769
|
driftsByType.set(drift.tableName, existing);
|
|
10743
10770
|
}
|
|
10744
10771
|
for (const [tableName, typeDrifts] of driftsByType) {
|
|
10745
|
-
lines.push(`
|
|
10772
|
+
lines.push(` Table '${tableName}':`);
|
|
10746
10773
|
for (const drift of typeDrifts) if (drift.fieldName) lines.push(` - Field '${drift.fieldName}': ${drift.details}`);
|
|
10747
10774
|
else if (drift.indexName) lines.push(` - Index '${drift.indexName}': ${drift.details}`);
|
|
10748
10775
|
else if (drift.fileName) lines.push(` - File '${drift.fileName}': ${drift.details}`);
|
|
@@ -10848,10 +10875,10 @@ function captureMigrationFileState(namespacesWithMigrations) {
|
|
|
10848
10875
|
* without relying on local TypeScript definitions.
|
|
10849
10876
|
*/
|
|
10850
10877
|
/**
|
|
10851
|
-
* Generate a TailorDB
|
|
10852
|
-
* @param {TailorDBSnapshotType} snapshotType - Snapshot
|
|
10878
|
+
* Generate a TailorDB table manifest from a snapshot table
|
|
10879
|
+
* @param {TailorDBSnapshotType} snapshotType - Snapshot table to generate manifest from
|
|
10853
10880
|
* @param {GenerateManifestOptions} options - Generation options
|
|
10854
|
-
* @returns {MessageInitShape<typeof TailorDBTypeSchema>}
|
|
10881
|
+
* @returns {MessageInitShape<typeof TailorDBTypeSchema>} Table manifest
|
|
10855
10882
|
*/
|
|
10856
10883
|
function generateTailorDBTypeManifestFromSnapshot(snapshotType, options = {}) {
|
|
10857
10884
|
const pluralForm = inflection.camelize(snapshotType.pluralForm, true);
|
|
@@ -11120,10 +11147,10 @@ function convertOperandToProto(operand) {
|
|
|
11120
11147
|
} };
|
|
11121
11148
|
}
|
|
11122
11149
|
/**
|
|
11123
|
-
* Generate all TailorDB
|
|
11150
|
+
* Generate all TailorDB table manifests from a schema snapshot
|
|
11124
11151
|
* @param {SchemaSnapshot} snapshot - Schema snapshot
|
|
11125
11152
|
* @param {GenerateAllManifestsOptions} options - Generation options
|
|
11126
|
-
* @returns {Map<string, MessageInitShape<typeof TailorDBTypeSchema>>} Map of
|
|
11153
|
+
* @returns {Map<string, MessageInitShape<typeof TailorDBTypeSchema>>} Map of table name to manifest
|
|
11127
11154
|
*/
|
|
11128
11155
|
function generateAllTypeManifestsFromSnapshot(snapshot, options = {}) {
|
|
11129
11156
|
const manifests = /* @__PURE__ */ new Map();
|
|
@@ -11138,9 +11165,9 @@ function generateAllTypeManifestsFromSnapshot(snapshot, options = {}) {
|
|
|
11138
11165
|
return manifests;
|
|
11139
11166
|
}
|
|
11140
11167
|
/**
|
|
11141
|
-
* Compare snapshot
|
|
11168
|
+
* Compare snapshot tables with existing remote table names
|
|
11142
11169
|
* @param {SchemaSnapshot} snapshot - Schema snapshot
|
|
11143
|
-
* @param {ReadonlySet<string>} existingTypeNames - Set of existing
|
|
11170
|
+
* @param {ReadonlySet<string>} existingTypeNames - Set of existing table names in remote
|
|
11144
11171
|
* @returns {SnapshotTypeComparison} Comparison result
|
|
11145
11172
|
*/
|
|
11146
11173
|
function compareSnapshotWithRemote(snapshot, existingTypeNames) {
|
|
@@ -11273,15 +11300,15 @@ function protoGqlOperand(operand) {
|
|
|
11273
11300
|
* - `field_type_modified`: keep the complete previous field config until
|
|
11274
11301
|
* Post-phase so migrate.ts runs against the previous type contract.
|
|
11275
11302
|
*
|
|
11276
|
-
* and the
|
|
11303
|
+
* and the table-level index adjustments:
|
|
11277
11304
|
*
|
|
11278
11305
|
* - `index_added` with `unique: true`: withhold the index until Post-phase.
|
|
11279
11306
|
* - `index_modified` that gains a unique constraint or re-points a unique
|
|
11280
11307
|
* index at different fields: keep the previous definition until Post-phase.
|
|
11281
11308
|
*
|
|
11282
|
-
*
|
|
11283
|
-
* handled by the deploy flow rather than via this module: the old
|
|
11284
|
-
* retained until Post-phase, and a renamed
|
|
11309
|
+
* Table-level deletions (`table_removed`) and renames (`table_renamed`) are
|
|
11310
|
+
* handled by the deploy flow rather than via this module: the old table is
|
|
11311
|
+
* retained until Post-phase, and a renamed table's new table is created with
|
|
11285
11312
|
* its full constraints in the Pre-phase (the copy script writes complete
|
|
11286
11313
|
* rows, so nothing needs relaxing).
|
|
11287
11314
|
*
|
|
@@ -11308,15 +11335,15 @@ function isPreMigrationFieldChange(change) {
|
|
|
11308
11335
|
return PRE_MIGRATION_FIELD_KINDS.has(change.kind);
|
|
11309
11336
|
}
|
|
11310
11337
|
/**
|
|
11311
|
-
* Create the
|
|
11338
|
+
* Create the table snapshot used to build a Pre-phase manifest.
|
|
11312
11339
|
*
|
|
11313
11340
|
* This adjustment happens before manifest generation because field hooks and
|
|
11314
|
-
* validators are aggregated into
|
|
11341
|
+
* validators are aggregated into table-level scripts by the manifest builder.
|
|
11315
11342
|
* Replacing only the generated field proto would leave those scripts on the
|
|
11316
11343
|
* target field contract while migrate.ts still runs against the previous one.
|
|
11317
11344
|
* @param snapshotType - Final snapshot state for this migration
|
|
11318
|
-
* @param typeChanges - Field changes for this
|
|
11319
|
-
* @param typeScriptsChange -
|
|
11345
|
+
* @param typeChanges - Field changes for this table, keyed by field name
|
|
11346
|
+
* @param typeScriptsChange - Table-level scripts changed by the same migration
|
|
11320
11347
|
* @returns A snapshot with Pre-phase field contracts
|
|
11321
11348
|
*/
|
|
11322
11349
|
function createPreMigrationSnapshotType(snapshotType, typeChanges, typeScriptsChange) {
|
|
@@ -11366,7 +11393,7 @@ function buildPreMigrationChangesMap(pendingMigrations) {
|
|
|
11366
11393
|
* - Modified fields keep the looser side of unique/required/enum.
|
|
11367
11394
|
*
|
|
11368
11395
|
* @param {Record<string, MessageInitShape<typeof TailorDBType_FieldConfigSchema>>} fields - Field map to adjust (mutated in place)
|
|
11369
|
-
* @param {Map<string, FieldDiffChange>} typeChanges - Changes for this
|
|
11396
|
+
* @param {Map<string, FieldDiffChange>} typeChanges - Changes for this table, keyed by fieldName
|
|
11370
11397
|
*/
|
|
11371
11398
|
function applyPreMigrationFieldAdjustments(fields, typeChanges) {
|
|
11372
11399
|
for (const [fieldName, change] of typeChanges) {
|
|
@@ -11411,7 +11438,7 @@ function applyPreMigrationFieldAdjustments(fields, typeChanges) {
|
|
|
11411
11438
|
}
|
|
11412
11439
|
}
|
|
11413
11440
|
/**
|
|
11414
|
-
* Build a map of
|
|
11441
|
+
* Build a map of table-level index changes that require pre-migration schema
|
|
11415
11442
|
* adjustment (the breaking ones — see {@link isBreakingIndexChange}).
|
|
11416
11443
|
* @param {PendingMigration[]} pendingMigrations - Pending migrations to scan
|
|
11417
11444
|
* @returns {PreMigrationIndexChangesMap} Map of changes keyed by tableName/indexName
|
|
@@ -11429,7 +11456,7 @@ function buildPreMigrationIndexChangesMap(pendingMigrations) {
|
|
|
11429
11456
|
return map;
|
|
11430
11457
|
}
|
|
11431
11458
|
/**
|
|
11432
|
-
* Apply pre-migration schema adjustments to a
|
|
11459
|
+
* Apply pre-migration schema adjustments to a table's index map in place.
|
|
11433
11460
|
*
|
|
11434
11461
|
* The indexes map is the proto-shape `TailorDBType.schema.indexes` that will
|
|
11435
11462
|
* be sent in the Pre-phase. We mutate it so that:
|
|
@@ -11438,7 +11465,7 @@ function buildPreMigrationIndexChangesMap(pendingMigrations) {
|
|
|
11438
11465
|
* - Modified indexes keep their previous definition until Post-phase.
|
|
11439
11466
|
*
|
|
11440
11467
|
* @param {Record<string, MessageInitShape<typeof TailorDBType_IndexSchema>>} indexes - Index map to adjust (mutated in place)
|
|
11441
|
-
* @param {Map<string, IndexDiffChange>} typeIndexChanges - Changes for this
|
|
11468
|
+
* @param {Map<string, IndexDiffChange>} typeIndexChanges - Changes for this table, keyed by indexName
|
|
11442
11469
|
*/
|
|
11443
11470
|
function applyPreMigrationIndexAdjustments(indexes, typeIndexChanges) {
|
|
11444
11471
|
for (const [indexName, change] of typeIndexChanges) {
|
|
@@ -11500,7 +11527,7 @@ async function fetchRemoteMigrationNumber(client, trn) {
|
|
|
11500
11527
|
* Schema validation checks shared between `deploy` and
|
|
11501
11528
|
* `tailordb migration validate`.
|
|
11502
11529
|
*
|
|
11503
|
-
* These checks are read-only: they compare local
|
|
11530
|
+
* These checks are read-only: they compare local table definitions, the
|
|
11504
11531
|
* migration snapshot history, and the remote schema without mutating any
|
|
11505
11532
|
* state.
|
|
11506
11533
|
*/
|
|
@@ -11519,11 +11546,11 @@ function toTailorDBDeployInput(service) {
|
|
|
11519
11546
|
};
|
|
11520
11547
|
}
|
|
11521
11548
|
/**
|
|
11522
|
-
* Fetch all TailorDB
|
|
11549
|
+
* Fetch all TailorDB tables from remote for a namespace
|
|
11523
11550
|
* @param {OperatorClient} client - Operator client instance
|
|
11524
11551
|
* @param {string} workspaceId - Workspace ID
|
|
11525
11552
|
* @param {string} namespace - TailorDB namespace
|
|
11526
|
-
* @returns {Promise<ProtoTailorDBType[]>} Remote TailorDB
|
|
11553
|
+
* @returns {Promise<ProtoTailorDBType[]>} Remote TailorDB tables
|
|
11527
11554
|
*/
|
|
11528
11555
|
async function fetchRemoteTypes(client, workspaceId, namespace) {
|
|
11529
11556
|
return fetchAllTolerant(async (pageToken, maxPageSize) => {
|
|
@@ -11667,7 +11694,8 @@ async function verifyRemoteSchema(client, workspaceId, namespacesWithMigrations,
|
|
|
11667
11694
|
});
|
|
11668
11695
|
continue;
|
|
11669
11696
|
}
|
|
11670
|
-
const
|
|
11697
|
+
const expectedMigrationNumber = checkpointRepair?.to ?? remoteMigrationNumber;
|
|
11698
|
+
const expectedSnapshot = reconstructSnapshotFromMigrations(migrationsDir, expectedMigrationNumber);
|
|
11671
11699
|
if (!expectedSnapshot) {
|
|
11672
11700
|
results.push({
|
|
11673
11701
|
namespace,
|
|
@@ -11679,7 +11707,8 @@ async function verifyRemoteSchema(client, workspaceId, namespacesWithMigrations,
|
|
|
11679
11707
|
continue;
|
|
11680
11708
|
}
|
|
11681
11709
|
const [remoteTypes, remoteGqlPermissions] = await Promise.all([fetchRemoteTypes(client, workspaceId, namespace), fetchRemoteGqlPermissions(client, workspaceId, namespace)]);
|
|
11682
|
-
const
|
|
11710
|
+
const expectedDeploySnapshot = deployComparableSnapshot(expectedSnapshot, remoteTypes, namespaceGqlOperations(config, tailorDBInputs, namespace));
|
|
11711
|
+
const drifts = compareRemoteWithSnapshot(remoteTypes, expectedDeploySnapshot, remoteGqlPermissions);
|
|
11683
11712
|
results.push({
|
|
11684
11713
|
namespace,
|
|
11685
11714
|
remoteMigrationNumber,
|
|
@@ -11701,7 +11730,7 @@ function logRemoteDriftGuidance() {
|
|
|
11701
11730
|
logger.newline();
|
|
11702
11731
|
logger.info("To resolve:");
|
|
11703
11732
|
logger.info(" - Run 'tailor tailordb migration status' to compare local vs remote.", { mode: "plain" });
|
|
11704
|
-
logger.info(" - If remote is correct, update local
|
|
11733
|
+
logger.info(" - If remote is correct, update local tables and run 'migration generate'.", { mode: "plain" });
|
|
11705
11734
|
logger.info(" - If local migration history is correct, run 'migration sync <N>' to overwrite remote.", { mode: "plain" });
|
|
11706
11735
|
logger.info(" - If only bookkeeping is stale, run 'migration set <N>'.", { mode: "plain" });
|
|
11707
11736
|
}
|
|
@@ -11724,7 +11753,7 @@ function formatRemoteVerificationResults(results) {
|
|
|
11724
11753
|
}
|
|
11725
11754
|
/**
|
|
11726
11755
|
* Check if there are schema differences between migration snapshots and local definitions
|
|
11727
|
-
* @param {ReadonlyMap<string, Record<string, TailorDBSnapshotType>>} typesByNamespace - Snapshot-shaped local
|
|
11756
|
+
* @param {ReadonlyMap<string, Record<string, TailorDBSnapshotType>>} typesByNamespace - Snapshot-shaped local tables by namespace
|
|
11728
11757
|
* @param {NamespaceWithMigrations[]} namespacesWithMigrations - Namespaces with migrations config
|
|
11729
11758
|
* @returns {Promise<MigrationCheckResult[]>} Results for each namespace
|
|
11730
11759
|
*/
|
|
@@ -12214,11 +12243,13 @@ async function detectPendingMigrations(client, workspaceId, namespacesWithMigrat
|
|
|
12214
12243
|
*/
|
|
12215
12244
|
async function executeSingleMigration(options, migration) {
|
|
12216
12245
|
const { client, workspaceId, invoker, env, configDir } = options;
|
|
12246
|
+
const migrationName = `migration-${migration.namespace}-${formatMigrationNumber(migration.number)}.js`;
|
|
12247
|
+
const bundleResult = await bundleMigrationScript(migration.scriptPath, migration.namespace, migration.number, env, configDir);
|
|
12217
12248
|
const result = await executeScript({
|
|
12218
12249
|
client,
|
|
12219
12250
|
workspaceId,
|
|
12220
|
-
name:
|
|
12221
|
-
code:
|
|
12251
|
+
name: migrationName,
|
|
12252
|
+
code: bundleResult.bundledCode,
|
|
12222
12253
|
invoker
|
|
12223
12254
|
});
|
|
12224
12255
|
return {
|
|
@@ -12239,8 +12270,9 @@ async function executeSingleMigration(options, migration) {
|
|
|
12239
12270
|
* @returns {Promise<void>}
|
|
12240
12271
|
*/
|
|
12241
12272
|
async function updateMigrationLabel(client, workspaceId, namespace, migrationNumber, historyId) {
|
|
12273
|
+
const trn = resourceTrn(workspaceId, "tailordb", namespace);
|
|
12242
12274
|
await writeMetadataLabels(client, {
|
|
12243
|
-
trn
|
|
12275
|
+
trn,
|
|
12244
12276
|
labels: {
|
|
12245
12277
|
[MIGRATION_LABEL_KEY]: sanitizeMigrationLabel(migrationNumber),
|
|
12246
12278
|
...historyId ? { [MIGRATION_HISTORY_LABEL_KEY]: historyId } : {}
|
|
@@ -12329,14 +12361,15 @@ function migrationFileStatesEqual(planned, current) {
|
|
|
12329
12361
|
* Validate migration files and detect pending migrations
|
|
12330
12362
|
* @param {OperatorClient} client - Operator client instance
|
|
12331
12363
|
* @param {string} workspaceId - Workspace ID
|
|
12332
|
-
* @param {ReadonlyMap<string, Record<string, TailorDBSnapshotType>>} typesByNamespace -
|
|
12364
|
+
* @param {ReadonlyMap<string, Record<string, TailorDBSnapshotType>>} typesByNamespace - Tables by namespace
|
|
12333
12365
|
* @param {LoadedConfig} config - Loaded application config (includes path)
|
|
12334
12366
|
* @param {boolean} noSchemaCheck - Whether to skip schema diff check
|
|
12335
12367
|
* @param {ReadonlyArray<TailorDBDeployInput>} tailorDBInputs - Deploy inputs for namespace defaults
|
|
12336
12368
|
* @returns {Promise<ValidateAndDetectResult>} Pending migrations and namespaces that have migration directories configured
|
|
12337
12369
|
*/
|
|
12338
12370
|
async function validateAndDetectMigrations(client, workspaceId, typesByNamespace, config, noSchemaCheck, tailorDBInputs) {
|
|
12339
|
-
const
|
|
12371
|
+
const configDir = path.dirname(config.path);
|
|
12372
|
+
const namespacesWithMigrations = getNamespacesWithMigrations(config, configDir);
|
|
12340
12373
|
let pendingMigrations = [];
|
|
12341
12374
|
let checkpointRepairs = [];
|
|
12342
12375
|
const migrationHistoryIds = Object.create(null);
|
|
@@ -12498,10 +12531,43 @@ async function applyTailorDB(client, result, phase = "create-update") {
|
|
|
12498
12531
|
await executeServicesCreation(client, changeSet);
|
|
12499
12532
|
const migratingNamespaces = new Set(pendingMigrations.map((m) => m.namespace));
|
|
12500
12533
|
const isOutsideMigrations = (namespaceName) => namespaceName !== void 0 && !migratingNamespaces.has(namespaceName);
|
|
12534
|
+
const firstPendingByNamespace = /* @__PURE__ */ new Map();
|
|
12535
|
+
const pendingDeletedTypes = /* @__PURE__ */ new Map();
|
|
12536
|
+
for (const migration of pendingMigrations) {
|
|
12537
|
+
const first = firstPendingByNamespace.get(migration.namespace);
|
|
12538
|
+
if (!first || migration.number < first.number) firstPendingByNamespace.set(migration.namespace, migration);
|
|
12539
|
+
const deleted = pendingDeletedTypes.get(migration.namespace) ?? /* @__PURE__ */ new Set();
|
|
12540
|
+
for (const typeName of getDeletedTypeNames(migration)) deleted.add(typeName);
|
|
12541
|
+
pendingDeletedTypes.set(migration.namespace, deleted);
|
|
12542
|
+
}
|
|
12543
|
+
const preMigrationTables = /* @__PURE__ */ new Map();
|
|
12544
|
+
for (const [namespace, first] of firstPendingByNamespace) {
|
|
12545
|
+
const snapshot = reconstructSnapshotFromMigrations(first.migrationsDir, first.number - 1);
|
|
12546
|
+
if (!snapshot) throw new Error(`Cannot reconstruct the schema state before migration ${formatMigrationNumber(first.number)} for namespace "${namespace}"`);
|
|
12547
|
+
preMigrationTables.set(namespace, snapshot.tables);
|
|
12548
|
+
}
|
|
12501
12549
|
try {
|
|
12502
12550
|
for (const create of changeSet.type.creates) {
|
|
12503
|
-
|
|
12504
|
-
|
|
12551
|
+
const namespaceName = create.request.namespaceName;
|
|
12552
|
+
if (isOutsideMigrations(namespaceName)) {
|
|
12553
|
+
await client.createTailorDBType(create.request);
|
|
12554
|
+
continue;
|
|
12555
|
+
}
|
|
12556
|
+
const typeName = create.request.tailordbType?.name;
|
|
12557
|
+
if (!namespaceName || !typeName) continue;
|
|
12558
|
+
const priorType = preMigrationTables.get(namespaceName)?.[typeName];
|
|
12559
|
+
if (!priorType) continue;
|
|
12560
|
+
if (pendingDeletedTypes.get(namespaceName)?.has(typeName)) continue;
|
|
12561
|
+
const input = migrationContext.tailorDBInputs.find((i) => i.namespace === namespaceName);
|
|
12562
|
+
processedTypes.created.add(typeName);
|
|
12563
|
+
await client.createTailorDBType({
|
|
12564
|
+
workspaceId: create.request.workspaceId,
|
|
12565
|
+
namespaceName,
|
|
12566
|
+
tailordbType: generateTailorDBTypeManifestFromSnapshot(priorType, {
|
|
12567
|
+
subscribed: migrationContext.executorUsedTypes.has(typeName),
|
|
12568
|
+
namespaceGqlOperations: input?.config.gqlOperations
|
|
12569
|
+
})
|
|
12570
|
+
});
|
|
12505
12571
|
}
|
|
12506
12572
|
for (const update of changeSet.type.updates) {
|
|
12507
12573
|
if (!isOutsideMigrations(update.request.namespaceName)) continue;
|
|
@@ -12518,17 +12584,18 @@ async function applyTailorDB(client, result, phase = "create-update") {
|
|
|
12518
12584
|
logger.newline();
|
|
12519
12585
|
}
|
|
12520
12586
|
for (const migration of pendingMigrations) {
|
|
12587
|
+
const attemptedTypes = /* @__PURE__ */ new Set();
|
|
12521
12588
|
try {
|
|
12522
|
-
await executeSingleMigrationPrePhase(client, changeSet, migration, migrationContext.tailorDBInputs, migrationContext.executorUsedTypes);
|
|
12589
|
+
await executeSingleMigrationPrePhase(client, changeSet, migration, migrationContext.tailorDBInputs, migrationContext.executorUsedTypes, attemptedTypes);
|
|
12523
12590
|
if (migration.hasScript && migrationCtx) await executeMigrations(migrationCtx, [migration]);
|
|
12524
12591
|
} catch (error) {
|
|
12525
|
-
await rollbackSingleMigrationAfterFailure(client,
|
|
12592
|
+
await rollbackSingleMigrationAfterFailure(client, migration, migrationContext.workspaceId, migrationContext.tailorDBInputs, migrationContext.executorUsedTypes, attemptedTypes);
|
|
12526
12593
|
throw error;
|
|
12527
12594
|
}
|
|
12528
12595
|
try {
|
|
12529
|
-
await executeSingleMigrationPostPhase(client, changeSet, migration, migrationContext.tailorDBInputs, migrationContext.executorUsedTypes);
|
|
12596
|
+
await executeSingleMigrationPostPhase(client, changeSet, migration, migrationContext.tailorDBInputs, migrationContext.executorUsedTypes, attemptedTypes);
|
|
12530
12597
|
} catch (error) {
|
|
12531
|
-
await rollbackSingleMigrationAfterFailure(client,
|
|
12598
|
+
await rollbackSingleMigrationAfterFailure(client, migration, migrationContext.workspaceId, migrationContext.tailorDBInputs, migrationContext.executorUsedTypes, attemptedTypes);
|
|
12532
12599
|
throw error;
|
|
12533
12600
|
}
|
|
12534
12601
|
try {
|
|
@@ -12598,9 +12665,9 @@ async function applyTailorDB(client, result, phase = "create-update") {
|
|
|
12598
12665
|
} else await Promise.all(changeSet.service.deletes.map((del) => client.deleteTailorDBService(del.request)));
|
|
12599
12666
|
}
|
|
12600
12667
|
/**
|
|
12601
|
-
* Get the set of
|
|
12668
|
+
* Get the set of table names affected by a migration
|
|
12602
12669
|
* @param {PendingMigration} migration - Pending migration
|
|
12603
|
-
* @returns {Set<string>} Set of affected
|
|
12670
|
+
* @returns {Set<string>} Set of affected table names
|
|
12604
12671
|
*/
|
|
12605
12672
|
function getAffectedTypeNames(migration) {
|
|
12606
12673
|
const typeNames = /* @__PURE__ */ new Set();
|
|
@@ -12608,11 +12675,11 @@ function getAffectedTypeNames(migration) {
|
|
|
12608
12675
|
return typeNames;
|
|
12609
12676
|
}
|
|
12610
12677
|
/**
|
|
12611
|
-
* Get the set of
|
|
12612
|
-
* old name is included: the old
|
|
12613
|
-
* (which copies its rows into the new
|
|
12678
|
+
* Get the set of table names to be deleted by a migration. A renamed table's
|
|
12679
|
+
* old name is included: the old table survives the Pre-phase and the script
|
|
12680
|
+
* (which copies its rows into the new table), then is dropped here.
|
|
12614
12681
|
* @param {PendingMigration} migration - Pending migration
|
|
12615
|
-
* @returns {Set<string>} Set of
|
|
12682
|
+
* @returns {Set<string>} Set of table names to delete
|
|
12616
12683
|
*/
|
|
12617
12684
|
function getDeletedTypeNames(migration) {
|
|
12618
12685
|
const typeNames = /* @__PURE__ */ new Set();
|
|
@@ -12633,7 +12700,7 @@ async function executeServicesCreation(client, changeSet) {
|
|
|
12633
12700
|
}), ...changeSet.service.updates.map((update) => writeMetadataLabels(client, update.metaRequest))]);
|
|
12634
12701
|
}
|
|
12635
12702
|
/**
|
|
12636
|
-
* Track which
|
|
12703
|
+
* Track which tables have been created/updated across migrations
|
|
12637
12704
|
*/
|
|
12638
12705
|
const processedTypes = {
|
|
12639
12706
|
created: /* @__PURE__ */ new Set(),
|
|
@@ -12675,7 +12742,8 @@ function buildSnapshotTypeManifest(migration, tableName, tailorDBInputs, executo
|
|
|
12675
12742
|
if (!snapshotType) return void 0;
|
|
12676
12743
|
const input = tailorDBInputs.find((i) => i.namespace === migration.namespace);
|
|
12677
12744
|
const typeScriptsChange = migration.diff.changes.find((change) => change.kind === "table_scripts_modified" && change.tableName === tableName);
|
|
12678
|
-
|
|
12745
|
+
const manifestSnapshotType = typeChanges ? createPreMigrationSnapshotType(snapshotType, typeChanges, typeScriptsChange) : snapshotType;
|
|
12746
|
+
return generateTailorDBTypeManifestFromSnapshot(manifestSnapshotType, {
|
|
12679
12747
|
subscribed: executorUsedTypes.has(snapshotType.name),
|
|
12680
12748
|
namespaceGqlOperations: input?.config.gqlOperations
|
|
12681
12749
|
});
|
|
@@ -12697,10 +12765,11 @@ async function awaitAllSettledOrThrow(promises) {
|
|
|
12697
12765
|
* @param {TailorDBChangeSet} changeSet - TailorDB change set
|
|
12698
12766
|
* @param {PendingMigration} migration - Single pending migration
|
|
12699
12767
|
* @param tailorDBInputs - Deploy inputs, used to resolve namespace gqlOperations for the snapshot
|
|
12700
|
-
* @param executorUsedTypes -
|
|
12768
|
+
* @param executorUsedTypes - Tables used by executors (drives publishRecordEvents default)
|
|
12769
|
+
* @param attemptedTypes - Tables whose schema this migration attempted to create or update
|
|
12701
12770
|
* @returns {Promise<void>} Promise that resolves when pre-migration phase completes
|
|
12702
12771
|
*/
|
|
12703
|
-
async function executeSingleMigrationPrePhase(client, changeSet, migration, tailorDBInputs, executorUsedTypes) {
|
|
12772
|
+
async function executeSingleMigrationPrePhase(client, changeSet, migration, tailorDBInputs, executorUsedTypes, attemptedTypes) {
|
|
12704
12773
|
const preMigrationChanges = buildPreMigrationChangesMap([migration]);
|
|
12705
12774
|
const preMigrationIndexChanges = buildPreMigrationIndexChangesMap([migration]);
|
|
12706
12775
|
const affectedTypes = getAffectedTypeNames(migration);
|
|
@@ -12717,6 +12786,7 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
|
|
|
12717
12786
|
const indexChanges = preMigrationIndexChanges.get(tableName);
|
|
12718
12787
|
if (indexChanges && indexChanges.size > 0 && clonedRequest.tailordbType.schema?.indexes) applyPreMigrationIndexAdjustments(clonedRequest.tailordbType.schema.indexes, indexChanges);
|
|
12719
12788
|
processedTypes.created.add(tableName);
|
|
12789
|
+
attemptedTypes.add(tableName);
|
|
12720
12790
|
await client.createTailorDBType(clonedRequest);
|
|
12721
12791
|
}
|
|
12722
12792
|
for (const create of changeSet.type.creates) {
|
|
@@ -12730,6 +12800,7 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
|
|
|
12730
12800
|
const indexChanges = preMigrationIndexChanges.get(tableName);
|
|
12731
12801
|
if (indexChanges && indexChanges.size > 0 && clonedTypeRequest.schema?.indexes) applyPreMigrationIndexAdjustments(clonedTypeRequest.schema.indexes, indexChanges);
|
|
12732
12802
|
processedTypes.updated.add(tableName);
|
|
12803
|
+
attemptedTypes.add(tableName);
|
|
12733
12804
|
await client.updateTailorDBType({
|
|
12734
12805
|
workspaceId: create.request.workspaceId,
|
|
12735
12806
|
namespaceName: create.request.namespaceName,
|
|
@@ -12748,6 +12819,7 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
|
|
|
12748
12819
|
const indexChanges = preMigrationIndexChanges.get(tableName);
|
|
12749
12820
|
if (indexChanges && indexChanges.size > 0 && clonedRequest.tailordbType.schema?.indexes) applyPreMigrationIndexAdjustments(clonedRequest.tailordbType.schema.indexes, indexChanges);
|
|
12750
12821
|
processedTypes.updated.add(tableName);
|
|
12822
|
+
attemptedTypes.add(tableName);
|
|
12751
12823
|
await client.updateTailorDBType(clonedRequest);
|
|
12752
12824
|
}
|
|
12753
12825
|
if (!processedTypes.gqlPermissionsProcessed.has(migration.namespace)) {
|
|
@@ -12760,7 +12832,10 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
|
|
|
12760
12832
|
});
|
|
12761
12833
|
if (missingTypeCreates.length > 0) for (const create of missingTypeCreates) {
|
|
12762
12834
|
const tableName = create.request.tailordbType?.name;
|
|
12763
|
-
if (tableName)
|
|
12835
|
+
if (tableName) {
|
|
12836
|
+
processedTypes.created.add(tableName);
|
|
12837
|
+
attemptedTypes.add(tableName);
|
|
12838
|
+
}
|
|
12764
12839
|
await client.createTailorDBType(create.request);
|
|
12765
12840
|
}
|
|
12766
12841
|
processedTypes.gqlPermissionsProcessed.add(migration.namespace);
|
|
@@ -12768,7 +12843,7 @@ async function executeSingleMigrationPrePhase(client, changeSet, migration, tail
|
|
|
12768
12843
|
}
|
|
12769
12844
|
}
|
|
12770
12845
|
/**
|
|
12771
|
-
* Track which
|
|
12846
|
+
* Track which tables/permissions have been deleted across migrations
|
|
12772
12847
|
*/
|
|
12773
12848
|
const deletedResources = {
|
|
12774
12849
|
types: /* @__PURE__ */ new Set(),
|
|
@@ -12778,23 +12853,24 @@ const deletedResources = {
|
|
|
12778
12853
|
this.gqlPermissions.clear();
|
|
12779
12854
|
}
|
|
12780
12855
|
};
|
|
12781
|
-
async function rollbackSingleMigrationAfterFailure(client,
|
|
12856
|
+
async function rollbackSingleMigrationAfterFailure(client, migration, workspaceId, tailorDBInputs, executorUsedTypes, attemptedTypes) {
|
|
12782
12857
|
try {
|
|
12783
|
-
await rollbackSingleMigrationPrePhase(client,
|
|
12858
|
+
await rollbackSingleMigrationPrePhase(client, migration, workspaceId, tailorDBInputs, executorUsedTypes, attemptedTypes);
|
|
12784
12859
|
} catch (rollbackError) {
|
|
12785
12860
|
logger.warn(`Failed to roll back migration ${migration.namespace}/${formatMigrationNumber(migration.number)}: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
|
|
12786
12861
|
}
|
|
12787
12862
|
}
|
|
12788
12863
|
/**
|
|
12789
|
-
* Execute post-migration phase for a single migration: Apply final
|
|
12864
|
+
* Execute post-migration phase for a single migration: Apply final tables (with required: true)
|
|
12790
12865
|
* @param {OperatorClient} client - Operator client instance
|
|
12791
12866
|
* @param {TailorDBChangeSet} changeSet - TailorDB change set
|
|
12792
12867
|
* @param {PendingMigration} migration - Single pending migration
|
|
12793
12868
|
* @param tailorDBInputs - Deploy inputs, used to resolve namespace gqlOperations for the snapshot
|
|
12794
|
-
* @param executorUsedTypes -
|
|
12869
|
+
* @param executorUsedTypes - Tables used by executors (drives publishRecordEvents default)
|
|
12870
|
+
* @param attemptedTypes - Tables whose schema this migration attempted to create or update
|
|
12795
12871
|
* @returns {Promise<void>} Promise that resolves when post-migration phase completes
|
|
12796
12872
|
*/
|
|
12797
|
-
async function executeSingleMigrationPostPhase(client, changeSet, migration, tailorDBInputs, executorUsedTypes) {
|
|
12873
|
+
async function executeSingleMigrationPostPhase(client, changeSet, migration, tailorDBInputs, executorUsedTypes, attemptedTypes) {
|
|
12798
12874
|
const preMigrationChanges = buildPreMigrationChangesMap([migration]);
|
|
12799
12875
|
const preMigrationIndexChanges = buildPreMigrationIndexChangesMap([migration]);
|
|
12800
12876
|
const adjustedTypes = /* @__PURE__ */ new Set([...preMigrationChanges.keys(), ...preMigrationIndexChanges.keys()]);
|
|
@@ -12805,6 +12881,7 @@ async function executeSingleMigrationPostPhase(client, changeSet, migration, tai
|
|
|
12805
12881
|
if (!tableName || !affectedTypes.has(tableName) || !adjustedTypes.has(tableName)) continue;
|
|
12806
12882
|
const snapshotType = buildSnapshotTypeManifest(migration, tableName, tailorDBInputs, executorUsedTypes);
|
|
12807
12883
|
if (!snapshotType) continue;
|
|
12884
|
+
attemptedTypes.add(tableName);
|
|
12808
12885
|
await client.updateTailorDBType({
|
|
12809
12886
|
workspaceId: create.request.workspaceId,
|
|
12810
12887
|
namespaceName: create.request.namespaceName,
|
|
@@ -12816,6 +12893,7 @@ async function executeSingleMigrationPostPhase(client, changeSet, migration, tai
|
|
|
12816
12893
|
if (!tableName || !affectedTypes.has(tableName) || !adjustedTypes.has(tableName)) continue;
|
|
12817
12894
|
const snapshotType = buildSnapshotTypeManifest(migration, tableName, tailorDBInputs, executorUsedTypes);
|
|
12818
12895
|
if (!snapshotType) continue;
|
|
12896
|
+
attemptedTypes.add(tableName);
|
|
12819
12897
|
await client.updateTailorDBType({
|
|
12820
12898
|
workspaceId: update.request.workspaceId,
|
|
12821
12899
|
namespaceName: update.request.namespaceName,
|
|
@@ -12853,27 +12931,16 @@ async function executeSingleMigrationPostPhaseDeletions(client, changeSet, migra
|
|
|
12853
12931
|
/**
|
|
12854
12932
|
* Revert a single migration's Pre-phase DDL to the prior checkpoint's schema.
|
|
12855
12933
|
* @param client - Operator client instance
|
|
12856
|
-
* @param changeSet - TailorDB change set
|
|
12857
12934
|
* @param migration - The migration whose Pre-phase DDL must be reverted
|
|
12858
12935
|
* @param workspaceId - Workspace ID
|
|
12859
12936
|
* @param tailorDBInputs - Deploy inputs, used to resolve namespace gqlOperations for the snapshot
|
|
12860
|
-
* @param executorUsedTypes -
|
|
12937
|
+
* @param executorUsedTypes - Tables used by executors (drives publishRecordEvents default)
|
|
12938
|
+
* @param attemptedTypes - Tables whose schema this migration attempted to create or update
|
|
12861
12939
|
* @returns {Promise<void>} Promise that resolves when rollback attempts complete
|
|
12862
12940
|
*/
|
|
12863
|
-
async function rollbackSingleMigrationPrePhase(client,
|
|
12941
|
+
async function rollbackSingleMigrationPrePhase(client, migration, workspaceId, tailorDBInputs, executorUsedTypes, attemptedTypes) {
|
|
12864
12942
|
if (migration.number <= 0) return;
|
|
12865
|
-
|
|
12866
|
-
for (const create of changeSet.type.creates) {
|
|
12867
|
-
const name = create.request.tailordbType?.name;
|
|
12868
|
-
if (create.request.namespaceName === migration.namespace && name) namespaceTypes.add(name);
|
|
12869
|
-
}
|
|
12870
|
-
for (const update of changeSet.type.updates) {
|
|
12871
|
-
const name = update.request.tailordbType?.name;
|
|
12872
|
-
if (update.request.namespaceName === migration.namespace && name) namespaceTypes.add(name);
|
|
12873
|
-
}
|
|
12874
|
-
const applied = /* @__PURE__ */ new Set([...processedTypes.created, ...processedTypes.updated]);
|
|
12875
|
-
const rollbackTypes = new Set([...namespaceTypes].filter((name) => applied.has(name)));
|
|
12876
|
-
if (rollbackTypes.size === 0) return;
|
|
12943
|
+
if (attemptedTypes.size === 0) return;
|
|
12877
12944
|
const priorSnapshot = reconstructSnapshotFromMigrations(migration.migrationsDir, migration.number - 1);
|
|
12878
12945
|
if (!priorSnapshot) {
|
|
12879
12946
|
logger.warn(`Cannot roll back migration ${migration.namespace}/${formatMigrationNumber(migration.number)}: prior snapshot (migration ${formatMigrationNumber(migration.number - 1)}) could not be reconstructed. Leaving schema as-is; manual repair may be required.`);
|
|
@@ -12881,14 +12948,14 @@ async function rollbackSingleMigrationPrePhase(client, changeSet, migration, wor
|
|
|
12881
12948
|
}
|
|
12882
12949
|
const input = tailorDBInputs.find((i) => i.namespace === migration.namespace);
|
|
12883
12950
|
logger.warn(`Migration ${migration.namespace}/${formatMigrationNumber(migration.number)} failed; rolling back its pre-migration schema changes.`);
|
|
12884
|
-
const restoredTypes = [...
|
|
12951
|
+
const restoredTypes = [...attemptedTypes].flatMap((tableName) => {
|
|
12885
12952
|
const priorType = priorSnapshot.tables[tableName];
|
|
12886
12953
|
return priorType ? [{
|
|
12887
12954
|
tableName,
|
|
12888
12955
|
priorType
|
|
12889
12956
|
}] : [];
|
|
12890
12957
|
});
|
|
12891
|
-
const newTypes = [...
|
|
12958
|
+
const newTypes = [...attemptedTypes].filter((tableName) => !priorSnapshot.tables[tableName]);
|
|
12892
12959
|
for (const { tableName, priorType } of restoredTypes) try {
|
|
12893
12960
|
const manifest = generateTailorDBTypeManifestFromSnapshot(priorType, {
|
|
12894
12961
|
subscribed: executorUsedTypes.has(priorType.name),
|
|
@@ -12900,7 +12967,7 @@ async function rollbackSingleMigrationPrePhase(client, changeSet, migration, wor
|
|
|
12900
12967
|
tailordbType: manifest
|
|
12901
12968
|
});
|
|
12902
12969
|
} catch (rollbackError) {
|
|
12903
|
-
logger.warn(`Failed to roll back
|
|
12970
|
+
logger.warn(`Failed to roll back table '${tableName}' in namespace '${migration.namespace}': ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
|
|
12904
12971
|
}
|
|
12905
12972
|
for (const tableName of newTypes) try {
|
|
12906
12973
|
await client.deleteTailorDBGQLPermission({
|
|
@@ -12914,7 +12981,7 @@ async function rollbackSingleMigrationPrePhase(client, changeSet, migration, wor
|
|
|
12914
12981
|
tailordbTypeName: tableName
|
|
12915
12982
|
});
|
|
12916
12983
|
} catch (rollbackError) {
|
|
12917
|
-
logger.warn(`Failed to roll back
|
|
12984
|
+
logger.warn(`Failed to roll back table '${tableName}' in namespace '${migration.namespace}': ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
|
|
12918
12985
|
}
|
|
12919
12986
|
}
|
|
12920
12987
|
/**
|
|
@@ -12946,7 +13013,7 @@ async function planTailorDB(context) {
|
|
|
12946
13013
|
const namespaceByType = /* @__PURE__ */ new Map();
|
|
12947
13014
|
for (const tailordb of tailordbs) for (const tableName of Object.keys(tailordb.types)) {
|
|
12948
13015
|
const existingNamespace = namespaceByType.get(tableName);
|
|
12949
|
-
if (existingNamespace) throw new Error(`Migration test snapshot has duplicate TailorDB
|
|
13016
|
+
if (existingNamespace) throw new Error(`Migration test snapshot has duplicate TailorDB table name "${tableName}" in namespaces "${existingNamespace}" and "${tailordb.namespace}".`);
|
|
12950
13017
|
namespaceByType.set(tableName, tailordb.namespace);
|
|
12951
13018
|
}
|
|
12952
13019
|
}
|
|
@@ -13004,7 +13071,7 @@ function collectTailorDBDisplayEntries(action, typeItems, gqlPermissionItems) {
|
|
|
13004
13071
|
action,
|
|
13005
13072
|
symbol: ACTION_SYMBOLS[action],
|
|
13006
13073
|
name: item.name,
|
|
13007
|
-
labels: gqlPermissionKeys.has(itemKey(item)) ? ["
|
|
13074
|
+
labels: gqlPermissionKeys.has(itemKey(item)) ? ["table", "gqlPermission"] : ["table"],
|
|
13008
13075
|
namespace: item.request?.namespaceName
|
|
13009
13076
|
}));
|
|
13010
13077
|
const gqlPermissionOnlyEntries = gqlPermissionItems.filter((item) => !typeKeys.has(itemKey(item))).map((item) => ({
|
|
@@ -13017,8 +13084,8 @@ function collectTailorDBDisplayEntries(action, typeItems, gqlPermissionItems) {
|
|
|
13017
13084
|
return [...typeEntries, ...gqlPermissionOnlyEntries];
|
|
13018
13085
|
}
|
|
13019
13086
|
/**
|
|
13020
|
-
* Format TailorDB
|
|
13021
|
-
* @param typeChangeSet - TailorDB
|
|
13087
|
+
* Format TailorDB table and gqlPermission changes as grouped dry-run entries.
|
|
13088
|
+
* @param typeChangeSet - TailorDB table changes
|
|
13022
13089
|
* @param gqlPermissionChangeSet - TailorDB gqlPermission changes
|
|
13023
13090
|
* @returns Display entries for TailorDB resource output
|
|
13024
13091
|
*/
|
|
@@ -13120,19 +13187,20 @@ async function planServices(client, workspaceId, appName, appId, tailordbs) {
|
|
|
13120
13187
|
};
|
|
13121
13188
|
}
|
|
13122
13189
|
async function planTypes(client, workspaceId, tailordbs, executorUsedTypes, deletedServices, filteredTypesByNamespace, forceApplyAll = false, records = {}) {
|
|
13123
|
-
const changeSet = createChangeSet("TailorDB
|
|
13190
|
+
const changeSet = createChangeSet("TailorDB tables");
|
|
13124
13191
|
const { appName, appId, dependentApps, runAppIds } = records;
|
|
13125
13192
|
/**
|
|
13126
|
-
* Build one
|
|
13127
|
-
* to it. The
|
|
13128
|
-
* @param namespace - Namespace holding the
|
|
13129
|
-
* @param tableName -
|
|
13130
|
-
* @param explicitPublishEvents - `publishEvents` declared on the
|
|
13131
|
-
* @returns The
|
|
13193
|
+
* Build one table's metadata write, carrying the dependency records that belong
|
|
13194
|
+
* to it. The table is what publishes record events, so the record lives there.
|
|
13195
|
+
* @param namespace - Namespace holding the table
|
|
13196
|
+
* @param tableName - Table name
|
|
13197
|
+
* @param explicitPublishEvents - `publishEvents` declared on the table, if any
|
|
13198
|
+
* @returns The table's metadata write
|
|
13132
13199
|
*/
|
|
13133
13200
|
const typeMetaRequest = async (namespace, tableName, explicitPublishEvents) => {
|
|
13201
|
+
const trn = tailorDBTypeTrn(workspaceId, namespace, tableName);
|
|
13134
13202
|
return addDependencyRecords(await buildMetaRequest({
|
|
13135
|
-
trn
|
|
13203
|
+
trn,
|
|
13136
13204
|
appName: appName ?? "",
|
|
13137
13205
|
appId
|
|
13138
13206
|
}), {
|
|
@@ -13251,7 +13319,8 @@ const tailordbCompareKnownDefaults = {
|
|
|
13251
13319
|
])
|
|
13252
13320
|
};
|
|
13253
13321
|
function normalizeComparableTailorDBType(type) {
|
|
13254
|
-
const
|
|
13322
|
+
const canonical = toComparableProtoJson(TailorDBTypeSchema, type);
|
|
13323
|
+
const normalized = normalizeProtoConfig(canonical);
|
|
13255
13324
|
return normalizeTailorDBCompareValue({
|
|
13256
13325
|
name: normalized?.name ?? "",
|
|
13257
13326
|
schema: {
|
|
@@ -13972,8 +14041,9 @@ async function planWorkflowJobFunctionExecutionPolicy(client, workspaceId, appNa
|
|
|
13972
14041
|
for (const policy of declaredList) {
|
|
13973
14042
|
if (seenNames.has(policy.name)) throw new Error(`Duplicate workflow execution policy name "${policy.name}". Each policy must have a unique name within the workspace.`);
|
|
13974
14043
|
seenNames.add(policy.name);
|
|
14044
|
+
const currentTrn = resourceTrn(workspaceId, "workflow_job_function_execution_policy", policy.name);
|
|
13975
14045
|
const metaRequest = await buildMetaRequest({
|
|
13976
|
-
trn:
|
|
14046
|
+
trn: currentTrn,
|
|
13977
14047
|
appName,
|
|
13978
14048
|
appId
|
|
13979
14049
|
});
|
|
@@ -14234,7 +14304,8 @@ async function ensureConfigId(configPath) {
|
|
|
14234
14304
|
* @returns The existing id (or null when absent), or null for wrapper configs
|
|
14235
14305
|
*/
|
|
14236
14306
|
async function readConfigId(configPath) {
|
|
14237
|
-
const
|
|
14307
|
+
const source = await fs$2.promises.readFile(configPath, "utf-8");
|
|
14308
|
+
const { program } = parseSync(configPath, source);
|
|
14238
14309
|
const calls = [];
|
|
14239
14310
|
findDefineConfigCalls(program, calls);
|
|
14240
14311
|
if (calls.length === 0) return null;
|
|
@@ -14569,7 +14640,8 @@ function recomputedResources(workspaceId, application, jobsByWorkflow, subscribe
|
|
|
14569
14640
|
async function fetchMissingDependentApps(params) {
|
|
14570
14641
|
const { client, workspaceId, application, runAppIds, subscribedKeys, jobsByWorkflow } = params;
|
|
14571
14642
|
return (await Promise.all(recomputedResources(workspaceId, application, jobsByWorkflow, subscribedKeys).filter(({ key }) => !subscribedKeys.has(key)).map(async ({ trn, scope, label }) => {
|
|
14572
|
-
|
|
14643
|
+
const metadata = await getOrNull(() => client.getMetadata({ trn }));
|
|
14644
|
+
return recordedDependencies(metadata?.metadata?.labels, scope).filter((dependency) => !runAppIds.has(dependency.appId)).map((dependency) => ({
|
|
14573
14645
|
resource: label,
|
|
14574
14646
|
appId: dependency.appId,
|
|
14575
14647
|
reason: dependency.reason
|
|
@@ -14666,8 +14738,8 @@ async function validatePlan(input) {
|
|
|
14666
14738
|
});
|
|
14667
14739
|
}
|
|
14668
14740
|
creates(CreateTailorDBServiceRequestSchema, "TailorDB service", tailorDB.changeSet.service.creates);
|
|
14669
|
-
creates(CreateTailorDBTypeRequestSchema, "TailorDB
|
|
14670
|
-
updates(UpdateTailorDBTypeRequestSchema, "TailorDB
|
|
14741
|
+
creates(CreateTailorDBTypeRequestSchema, "TailorDB table", tailorDB.changeSet.type.creates);
|
|
14742
|
+
updates(UpdateTailorDBTypeRequestSchema, "TailorDB table", tailorDB.changeSet.type.updates);
|
|
14671
14743
|
creates(CreateStaticWebsiteRequestSchema, "StaticWebsite", staticWebsite.changeSet.creates);
|
|
14672
14744
|
updates(UpdateStaticWebsiteRequestSchema, "StaticWebsite", staticWebsite.changeSet.updates);
|
|
14673
14745
|
creates(AddCustomDomainRequestSchema, "StaticWebsite custom domain", staticWebsite.customDomainChangeSet.creates);
|
|
@@ -15002,7 +15074,9 @@ function profilePlatformSettings(platformConfig) {
|
|
|
15002
15074
|
*/
|
|
15003
15075
|
async function createWorkspace$1(options) {
|
|
15004
15076
|
const validated = validateCreateWorkspaceOptions(options);
|
|
15005
|
-
const
|
|
15077
|
+
const accessToken = await loadAccessToken({ profile: validated.profile });
|
|
15078
|
+
const platformConfig = await loadPlatformClientConfig({ profile: validated.profile });
|
|
15079
|
+
const client = await initOperatorClient(accessToken, platformConfig);
|
|
15006
15080
|
await validateRegion(validated.region, client);
|
|
15007
15081
|
return createValidatedWorkspaceWithClient(client, validated);
|
|
15008
15082
|
}
|
|
@@ -15013,13 +15087,14 @@ async function createWorkspace$1(options) {
|
|
|
15013
15087
|
* @returns Created workspace info
|
|
15014
15088
|
*/
|
|
15015
15089
|
async function createValidatedWorkspaceWithClient(client, options) {
|
|
15016
|
-
|
|
15090
|
+
const resp = await client.createWorkspace({
|
|
15017
15091
|
workspaceName: options.name,
|
|
15018
15092
|
workspaceRegion: options.region,
|
|
15019
15093
|
deleteProtection: options.deleteProtection ?? false,
|
|
15020
15094
|
organizationId: options.organizationId,
|
|
15021
15095
|
folderId: options.folderId
|
|
15022
|
-
})
|
|
15096
|
+
});
|
|
15097
|
+
return workspaceInfoWithFolderName(client, assertDefined(resp.workspace, "createWorkspace response missing workspace"));
|
|
15023
15098
|
}
|
|
15024
15099
|
/**
|
|
15025
15100
|
* Validate workspace creation options without making API calls.
|
|
@@ -15146,7 +15221,9 @@ const createCommand$1 = defineAppCommand({
|
|
|
15146
15221
|
*/
|
|
15147
15222
|
async function listWorkspaces(options) {
|
|
15148
15223
|
const profile = profileNameSchema.optional().parse(options?.profile);
|
|
15149
|
-
|
|
15224
|
+
const accessToken = await loadAccessToken({ profile });
|
|
15225
|
+
const platformConfig = await loadPlatformClientConfig({ profile });
|
|
15226
|
+
return listWorkspacesWithClient(await initOperatorClient(accessToken, platformConfig), options);
|
|
15150
15227
|
}
|
|
15151
15228
|
/**
|
|
15152
15229
|
* List workspaces using an existing Operator client.
|
|
@@ -15156,14 +15233,15 @@ async function listWorkspaces(options) {
|
|
|
15156
15233
|
*/
|
|
15157
15234
|
async function listWorkspacesWithClient(client, options) {
|
|
15158
15235
|
const pageDirection = toPageDirection(options?.order);
|
|
15159
|
-
|
|
15236
|
+
const workspaces = await fetchPaged(async (pageToken, pageSize) => {
|
|
15160
15237
|
const { workspaces, nextPageToken } = await client.listWorkspaces({
|
|
15161
15238
|
pageToken,
|
|
15162
15239
|
pageSize,
|
|
15163
15240
|
pageDirection
|
|
15164
15241
|
});
|
|
15165
15242
|
return [workspaces, nextPageToken];
|
|
15166
|
-
}, { limit: options?.limit })
|
|
15243
|
+
}, { limit: options?.limit });
|
|
15244
|
+
return workspaceInfosWithFolderNames(client, workspaces);
|
|
15167
15245
|
}
|
|
15168
15246
|
const listCommand$9 = defineAppCommand({
|
|
15169
15247
|
name: "list",
|
|
@@ -15756,9 +15834,9 @@ function ownedSubscriptions(subscriptions, owner) {
|
|
|
15756
15834
|
return subscriptions.filter((subscription) => subscription.owner.config.path === owner.config.path);
|
|
15757
15835
|
}
|
|
15758
15836
|
/**
|
|
15759
|
-
* Collect the TailorDB
|
|
15837
|
+
* Collect the TailorDB tables subscribed to among the given subscriptions.
|
|
15760
15838
|
* @param subscriptions - Subscriptions owned by the target being planned
|
|
15761
|
-
* @returns Subscribed
|
|
15839
|
+
* @returns Subscribed table names
|
|
15762
15840
|
*/
|
|
15763
15841
|
function subscribedTailorDBTypes(subscriptions) {
|
|
15764
15842
|
return new Set(subscriptions.flatMap((subscription) => subscription.trigger.kind === "tailordb" ? [subscription.trigger.typeName] : []));
|
|
@@ -16604,7 +16682,8 @@ async function planDeploymentTarget(params) {
|
|
|
16604
16682
|
plannedExternalTailorDBServices: collectPlannedExternalTailorDBServices(target, targets)
|
|
16605
16683
|
}));
|
|
16606
16684
|
const workflowService = application.workflowService;
|
|
16607
|
-
const
|
|
16685
|
+
const bundledWorkflowJobs = filterBundledWorkflowJobs(workflowService?.jobs ?? [], workflowBuildResult?.usedJobNames ?? []);
|
|
16686
|
+
const functionEntries = collectFunctionEntries(application, bundledWorkflowJobs, bundledScripts);
|
|
16608
16687
|
const forceApplyAll = await withSpan("plan.detectSdkVersionChange", () => shouldForceApplyAll(client, workspaceId, application, functionEntries));
|
|
16609
16688
|
return withSpan("plan", async () => {
|
|
16610
16689
|
const applications = targets.map((target) => target.application);
|
|
@@ -16701,7 +16780,7 @@ function collectResourceOwners(results) {
|
|
|
16701
16780
|
function collectImportantResourceDeletions(results) {
|
|
16702
16781
|
const importantDeletions = [];
|
|
16703
16782
|
for (const del of results.tailorDB.changeSet.type.deletes) importantDeletions.push({
|
|
16704
|
-
resourceType: "TailorDB
|
|
16783
|
+
resourceType: "TailorDB table",
|
|
16705
16784
|
resourceName: del.name
|
|
16706
16785
|
});
|
|
16707
16786
|
for (const del of results.staticWebsite.changeSet.deletes) importantDeletions.push({
|
|
@@ -17037,7 +17116,8 @@ async function confirmDeploymentPlans(params) {
|
|
|
17037
17116
|
const results = deploymentPlanResults(deployment);
|
|
17038
17117
|
const conflicts = collectOwnerConflicts(results);
|
|
17039
17118
|
await confirmOwnerConflict(conflicts, deployment.application.name, yes, deployment.application.id);
|
|
17040
|
-
|
|
17119
|
+
const unmanaged = collectUnmanagedResources(results);
|
|
17120
|
+
await confirmUnmanagedResources(unmanaged, deployment.application.name, yes);
|
|
17041
17121
|
importantDeletions.push(...collectImportantResourceDeletions(results));
|
|
17042
17122
|
const emptyApps = computeRenamedAppDeletions({
|
|
17043
17123
|
conflicts,
|
|
@@ -17225,11 +17305,13 @@ async function deployInternal(options, cliContext, internalContext) {
|
|
|
17225
17305
|
return;
|
|
17226
17306
|
}
|
|
17227
17307
|
await applyDeploymentPlans(client, workspaceId, deployments);
|
|
17228
|
-
if (!internalContext?.suppressResultOutput)
|
|
17229
|
-
|
|
17230
|
-
|
|
17231
|
-
|
|
17232
|
-
|
|
17308
|
+
if (!internalContext?.suppressResultOutput) {
|
|
17309
|
+
if (logger.jsonMode) logger.out({
|
|
17310
|
+
summary: planSummary,
|
|
17311
|
+
status: "applied"
|
|
17312
|
+
});
|
|
17313
|
+
else logger.success("Successfully applied changes.");
|
|
17314
|
+
}
|
|
17233
17315
|
});
|
|
17234
17316
|
}
|
|
17235
17317
|
/**
|
|
@@ -17643,13 +17725,15 @@ async function resolveExecutor(client, workspaceId, name) {
|
|
|
17643
17725
|
*/
|
|
17644
17726
|
async function getExecutor(options) {
|
|
17645
17727
|
const name = options.executor.name;
|
|
17646
|
-
const
|
|
17728
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
17729
|
+
const client = await initOperatorClient(accessToken);
|
|
17647
17730
|
const workspaceId = await loadWorkspaceId({
|
|
17648
17731
|
workspaceId: options.workspaceId,
|
|
17649
17732
|
profile: options.profile
|
|
17650
17733
|
});
|
|
17651
17734
|
try {
|
|
17652
|
-
|
|
17735
|
+
const executor = await resolveExecutor(client, workspaceId, name);
|
|
17736
|
+
return toExecutorInfo(executor);
|
|
17653
17737
|
} catch (error) {
|
|
17654
17738
|
if (error instanceof ConnectError && error.code === Code.NotFound) throw new Error(`Executor '${name}' not found.`, { cause: error });
|
|
17655
17739
|
throw error;
|
|
@@ -18106,8 +18190,9 @@ async function waitForWorkflowExecution(options) {
|
|
|
18106
18190
|
* @returns Workflow wait result
|
|
18107
18191
|
*/
|
|
18108
18192
|
async function waitForWorkflowExecutionById(options) {
|
|
18193
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
18109
18194
|
return await waitForWorkflowExecution({
|
|
18110
|
-
client: await initOperatorClient(
|
|
18195
|
+
client: await initOperatorClient(accessToken),
|
|
18111
18196
|
workspaceId: await loadWorkspaceId({
|
|
18112
18197
|
workspaceId: options.workspaceId,
|
|
18113
18198
|
profile: options.profile
|
|
@@ -18160,7 +18245,8 @@ function parseStatus(status) {
|
|
|
18160
18245
|
*/
|
|
18161
18246
|
async function listWorkflowExecutions(options) {
|
|
18162
18247
|
const workflowName = options?.workflow?.name;
|
|
18163
|
-
const
|
|
18248
|
+
const accessToken = await loadAccessToken({ profile: options?.profile });
|
|
18249
|
+
const client = await initOperatorClient(accessToken);
|
|
18164
18250
|
const workspaceId = await loadWorkspaceId({
|
|
18165
18251
|
workspaceId: options?.workspaceId,
|
|
18166
18252
|
profile: options?.profile
|
|
@@ -18197,7 +18283,8 @@ async function listWorkflowExecutions(options) {
|
|
|
18197
18283
|
* @returns Workflow execution with optional logs
|
|
18198
18284
|
*/
|
|
18199
18285
|
async function getWorkflowExecution(options) {
|
|
18200
|
-
const
|
|
18286
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
18287
|
+
const client = await initOperatorClient(accessToken);
|
|
18201
18288
|
const workspaceId = await loadWorkspaceId({
|
|
18202
18289
|
workspaceId: options.workspaceId,
|
|
18203
18290
|
profile: options.profile
|
|
@@ -18414,13 +18501,15 @@ async function resolveWorkflow(client, workspaceId, name) {
|
|
|
18414
18501
|
*/
|
|
18415
18502
|
async function getWorkflow(options) {
|
|
18416
18503
|
const name = options.workflow.name;
|
|
18417
|
-
const
|
|
18504
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
18505
|
+
const client = await initOperatorClient(accessToken);
|
|
18418
18506
|
const workspaceId = await loadWorkspaceId({
|
|
18419
18507
|
workspaceId: options.workspaceId,
|
|
18420
18508
|
profile: options.profile
|
|
18421
18509
|
});
|
|
18422
18510
|
try {
|
|
18423
|
-
|
|
18511
|
+
const workflow = await resolveWorkflow(client, workspaceId, name);
|
|
18512
|
+
return toWorkflowInfo(workflow);
|
|
18424
18513
|
} catch (error) {
|
|
18425
18514
|
if (error instanceof ConnectError && error.code === Code.NotFound) throw new Error(`Workflow '${name}' not found.`, { cause: error });
|
|
18426
18515
|
throw error;
|
|
@@ -18499,7 +18588,8 @@ async function startWorkflowByName(options) {
|
|
|
18499
18588
|
profile: options.profile
|
|
18500
18589
|
});
|
|
18501
18590
|
if (!machineUser) throw new Error("Machine user is required. Specify --machine-user, set TAILOR_PLATFORM_MACHINE_USER_NAME, or set a profile default with 'tailor profile update <profile> --machine-user <name>'.");
|
|
18502
|
-
const
|
|
18591
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
18592
|
+
const client = await initOperatorClient(accessToken);
|
|
18503
18593
|
const workspaceId = await loadWorkspaceId({
|
|
18504
18594
|
workspaceId: options.workspaceId,
|
|
18505
18595
|
profile: options.profile
|
|
@@ -18527,7 +18617,8 @@ async function startWorkflowByName(options) {
|
|
|
18527
18617
|
* @returns Start result with wait helper
|
|
18528
18618
|
*/
|
|
18529
18619
|
async function startWorkflow(options) {
|
|
18530
|
-
const
|
|
18620
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
18621
|
+
const client = await initOperatorClient(accessToken);
|
|
18531
18622
|
const workspaceId = await loadWorkspaceId({
|
|
18532
18623
|
workspaceId: options.workspaceId,
|
|
18533
18624
|
profile: options.profile
|
|
@@ -18638,7 +18729,8 @@ function createUnknownExecutorJob(executorName, jobId) {
|
|
|
18638
18729
|
*/
|
|
18639
18730
|
async function listExecutorJobs(options) {
|
|
18640
18731
|
const executorName = options.executor.name;
|
|
18641
|
-
const
|
|
18732
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
18733
|
+
const client = await initOperatorClient(accessToken);
|
|
18642
18734
|
const workspaceId = await loadWorkspaceId({
|
|
18643
18735
|
workspaceId: options.workspaceId,
|
|
18644
18736
|
profile: options.profile
|
|
@@ -18681,7 +18773,8 @@ async function listExecutorJobs(options) {
|
|
|
18681
18773
|
*/
|
|
18682
18774
|
async function getExecutorJob(options) {
|
|
18683
18775
|
const executorName = options.executor.name;
|
|
18684
|
-
const
|
|
18776
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
18777
|
+
const client = await initOperatorClient(accessToken);
|
|
18685
18778
|
const workspaceId = await loadWorkspaceId({
|
|
18686
18779
|
workspaceId: options.workspaceId,
|
|
18687
18780
|
profile: options.profile
|
|
@@ -18723,7 +18816,8 @@ async function getExecutorJob(options) {
|
|
|
18723
18816
|
*/
|
|
18724
18817
|
async function watchExecutorJob(options) {
|
|
18725
18818
|
const executorName = options.executor.name;
|
|
18726
|
-
const
|
|
18819
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
18820
|
+
const client = await initOperatorClient(accessToken);
|
|
18727
18821
|
const workspaceId = await loadWorkspaceId({
|
|
18728
18822
|
workspaceId: options.workspaceId,
|
|
18729
18823
|
profile: options.profile
|
|
@@ -18922,8 +19016,6 @@ async function watchExecutorJob(options) {
|
|
|
18922
19016
|
functionExecutionId: operationReference
|
|
18923
19017
|
}, false);
|
|
18924
19018
|
}
|
|
18925
|
-
break;
|
|
18926
|
-
default: break;
|
|
18927
19019
|
}
|
|
18928
19020
|
return withWaitMetadata({
|
|
18929
19021
|
job: jobDetail,
|
|
@@ -19121,7 +19213,8 @@ const jobsCommand = defineAppCommand({
|
|
|
19121
19213
|
* @returns List of executors
|
|
19122
19214
|
*/
|
|
19123
19215
|
async function listExecutors(options) {
|
|
19124
|
-
const
|
|
19216
|
+
const accessToken = await loadAccessToken({ profile: options?.profile });
|
|
19217
|
+
const client = await initOperatorClient(accessToken);
|
|
19125
19218
|
const workspaceId = await loadWorkspaceId({
|
|
19126
19219
|
workspaceId: options?.workspaceId,
|
|
19127
19220
|
profile: options?.profile
|
|
@@ -19194,7 +19287,8 @@ const headerArg = z.string().superRefine((val, ctx) => {
|
|
|
19194
19287
|
};
|
|
19195
19288
|
}).refine((h) => h.key.length > 0, { message: "Header name cannot be empty" });
|
|
19196
19289
|
async function triggerExecutorByName(options) {
|
|
19197
|
-
const
|
|
19290
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
19291
|
+
const client = await initOperatorClient(accessToken);
|
|
19198
19292
|
const workspaceId = await loadWorkspaceId({
|
|
19199
19293
|
workspaceId: options.workspaceId,
|
|
19200
19294
|
profile: options.profile
|
|
@@ -19299,7 +19393,8 @@ The \`--logs\` option displays logs from the downstream execution when available
|
|
|
19299
19393
|
run: async (args) => {
|
|
19300
19394
|
const jsonOutput = logger.jsonMode || args.json;
|
|
19301
19395
|
await assertWritable({ profile: args.profile });
|
|
19302
|
-
const
|
|
19396
|
+
const accessToken = await loadAccessToken({ profile: args.profile });
|
|
19397
|
+
const client = await initOperatorClient(accessToken);
|
|
19303
19398
|
const workspaceId = await loadWorkspaceId({
|
|
19304
19399
|
workspaceId: args["workspace-id"],
|
|
19305
19400
|
profile: args.profile
|
|
@@ -19391,7 +19486,8 @@ The \`--logs\` option displays logs from the downstream execution when available
|
|
|
19391
19486
|
* @returns List of webhook executors with URLs
|
|
19392
19487
|
*/
|
|
19393
19488
|
async function listWebhookExecutors(options) {
|
|
19394
|
-
const
|
|
19489
|
+
const accessToken = await loadAccessToken({ profile: options?.profile });
|
|
19490
|
+
const client = await initOperatorClient(accessToken);
|
|
19395
19491
|
const workspaceId = await loadWorkspaceId({
|
|
19396
19492
|
workspaceId: options?.workspaceId,
|
|
19397
19493
|
profile: options?.profile
|
|
@@ -19467,8 +19563,9 @@ const getFunctionRegistryOptionsSchema = z.object({
|
|
|
19467
19563
|
async function loadOptions$12(options) {
|
|
19468
19564
|
const result = getFunctionRegistryOptionsSchema.safeParse(options);
|
|
19469
19565
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
19566
|
+
const accessToken = await loadAccessToken({ profile: result.data.profile });
|
|
19470
19567
|
return {
|
|
19471
|
-
client: await initOperatorClient(
|
|
19568
|
+
client: await initOperatorClient(accessToken),
|
|
19472
19569
|
workspaceId: await loadWorkspaceId({
|
|
19473
19570
|
workspaceId: result.data.workspaceId,
|
|
19474
19571
|
profile: result.data.profile
|
|
@@ -19532,8 +19629,9 @@ const listFunctionRegistriesOptionsSchema = z.object({
|
|
|
19532
19629
|
async function loadOptions$11(options) {
|
|
19533
19630
|
const result = listFunctionRegistriesOptionsSchema.safeParse(options);
|
|
19534
19631
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
19632
|
+
const accessToken = await loadAccessToken({ profile: result.data.profile });
|
|
19535
19633
|
return {
|
|
19536
|
-
client: await initOperatorClient(
|
|
19634
|
+
client: await initOperatorClient(accessToken),
|
|
19537
19635
|
workspaceId: await loadWorkspaceId({
|
|
19538
19636
|
workspaceId: result.data.workspaceId,
|
|
19539
19637
|
profile: result.data.profile
|
|
@@ -19690,17 +19788,15 @@ function createGenerationManager(params) {
|
|
|
19690
19788
|
pluginConfig: plugin.pluginConfig
|
|
19691
19789
|
});
|
|
19692
19790
|
break;
|
|
19693
|
-
case "onExecutorReady":
|
|
19694
|
-
|
|
19695
|
-
|
|
19696
|
-
|
|
19697
|
-
|
|
19698
|
-
|
|
19699
|
-
|
|
19700
|
-
|
|
19701
|
-
|
|
19702
|
-
});
|
|
19703
|
-
break;
|
|
19791
|
+
case "onExecutorReady": result = await assertDefined(plugin.onExecutorReady, "plugin.onExecutorReady hook missing")({
|
|
19792
|
+
tailordb,
|
|
19793
|
+
resolvers: buildResolverData(),
|
|
19794
|
+
executors: { ...services.executor },
|
|
19795
|
+
auth,
|
|
19796
|
+
baseDir: pluginBaseDir,
|
|
19797
|
+
configPath: config.path,
|
|
19798
|
+
pluginConfig: plugin.pluginConfig
|
|
19799
|
+
});
|
|
19704
19800
|
}
|
|
19705
19801
|
await writeGeneratedFiles(plugin.id, result);
|
|
19706
19802
|
}
|
|
@@ -19783,7 +19879,7 @@ function createGenerationManager(params) {
|
|
|
19783
19879
|
pluginAttachments: db.pluginAttachments
|
|
19784
19880
|
};
|
|
19785
19881
|
} catch (error) {
|
|
19786
|
-
logger.error(`Error loading
|
|
19882
|
+
logger.error(`Error loading tables for TailorDB service ${styles.bold(namespace)}`);
|
|
19787
19883
|
logger.error(String(error));
|
|
19788
19884
|
throw error;
|
|
19789
19885
|
}
|
|
@@ -19792,7 +19888,7 @@ function createGenerationManager(params) {
|
|
|
19792
19888
|
try {
|
|
19793
19889
|
assertUniqueLocalTailorDBTypeNames({ tailorDBServices: app.tailorDBServices });
|
|
19794
19890
|
} catch (error) {
|
|
19795
|
-
logger.error("Error validating TailorDB
|
|
19891
|
+
logger.error("Error validating TailorDB table names");
|
|
19796
19892
|
logger.error(String(error));
|
|
19797
19893
|
throw error;
|
|
19798
19894
|
}
|
|
@@ -19914,7 +20010,8 @@ function machineUserInfo(user) {
|
|
|
19914
20010
|
* @returns List of machine users
|
|
19915
20011
|
*/
|
|
19916
20012
|
async function listMachineUsers(options) {
|
|
19917
|
-
const
|
|
20013
|
+
const accessToken = await loadAccessToken({ profile: options?.profile });
|
|
20014
|
+
const client = await initOperatorClient(accessToken);
|
|
19918
20015
|
const workspaceId = await loadWorkspaceId({
|
|
19919
20016
|
workspaceId: options?.workspaceId,
|
|
19920
20017
|
profile: options?.profile
|
|
@@ -19968,7 +20065,8 @@ async function getMachineUserTokenInternal(options) {
|
|
|
19968
20065
|
profile: options.profile
|
|
19969
20066
|
});
|
|
19970
20067
|
if (!name) throw new Error("Machine user is required. Provide the NAME positional argument, set TAILOR_PLATFORM_MACHINE_USER_NAME, or set a profile default with 'tailor profile update <profile> --machine-user <name>'.");
|
|
19971
|
-
const
|
|
20068
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
20069
|
+
const client = await initOperatorClient(accessToken);
|
|
19972
20070
|
const workspaceId = await loadWorkspaceId({
|
|
19973
20071
|
workspaceId: options.workspaceId,
|
|
19974
20072
|
profile: options.profile
|
|
@@ -20078,7 +20176,8 @@ function toOAuth2ClientCredentials(client) {
|
|
|
20078
20176
|
* @returns OAuth2 client credentials
|
|
20079
20177
|
*/
|
|
20080
20178
|
async function getOAuth2Client(options) {
|
|
20081
|
-
const
|
|
20179
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
20180
|
+
const client = await initOperatorClient(accessToken);
|
|
20082
20181
|
const workspaceId = await loadWorkspaceId({
|
|
20083
20182
|
workspaceId: options.workspaceId,
|
|
20084
20183
|
profile: options.profile
|
|
@@ -20130,7 +20229,8 @@ const getCommand$3 = defineAppCommand({
|
|
|
20130
20229
|
* @returns List of OAuth2 clients
|
|
20131
20230
|
*/
|
|
20132
20231
|
async function listOAuth2Clients(options) {
|
|
20133
|
-
const
|
|
20232
|
+
const accessToken = await loadAccessToken({ profile: options?.profile });
|
|
20233
|
+
const client = await initOperatorClient(accessToken);
|
|
20134
20234
|
const workspaceId = await loadWorkspaceId({
|
|
20135
20235
|
workspaceId: options?.workspaceId,
|
|
20136
20236
|
profile: options?.profile
|
|
@@ -20215,7 +20315,8 @@ const createFolderOptionsSchema = z.object({
|
|
|
20215
20315
|
async function createFolder(options) {
|
|
20216
20316
|
const result = createFolderOptionsSchema.safeParse(options);
|
|
20217
20317
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
20218
|
-
const
|
|
20318
|
+
const accessToken = await loadAccessToken();
|
|
20319
|
+
const response = await (await initOperatorClient(accessToken)).createOrganizationFolder({
|
|
20219
20320
|
organizationId: result.data.organizationId,
|
|
20220
20321
|
parentFolderId: result.data.parentFolderId ?? "",
|
|
20221
20322
|
folderName: result.data.name
|
|
@@ -20260,7 +20361,8 @@ const deleteFolderOptionsSchema = z.object({
|
|
|
20260
20361
|
async function deleteFolder(options) {
|
|
20261
20362
|
const result = deleteFolderOptionsSchema.safeParse(options);
|
|
20262
20363
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
20263
|
-
|
|
20364
|
+
const accessToken = await loadAccessToken();
|
|
20365
|
+
await (await initOperatorClient(accessToken)).deleteOrganizationFolder({
|
|
20264
20366
|
organizationId: result.data.organizationId,
|
|
20265
20367
|
folderId: result.data.folderId
|
|
20266
20368
|
});
|
|
@@ -20275,7 +20377,8 @@ const deleteCommand$1 = defineAppCommand({
|
|
|
20275
20377
|
}),
|
|
20276
20378
|
run: async (args) => {
|
|
20277
20379
|
await assertWritable();
|
|
20278
|
-
const
|
|
20380
|
+
const accessToken = await loadAccessToken();
|
|
20381
|
+
const client = await initOperatorClient(accessToken);
|
|
20279
20382
|
let folderName;
|
|
20280
20383
|
try {
|
|
20281
20384
|
folderName = (await client.getOrganizationFolder({
|
|
@@ -20313,7 +20416,8 @@ const getFolderOptionsSchema = z.object({
|
|
|
20313
20416
|
async function getFolder(options) {
|
|
20314
20417
|
const result = getFolderOptionsSchema.safeParse(options);
|
|
20315
20418
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
20316
|
-
const
|
|
20419
|
+
const accessToken = await loadAccessToken();
|
|
20420
|
+
const response = await (await initOperatorClient(accessToken)).getOrganizationFolder({
|
|
20317
20421
|
organizationId: result.data.organizationId,
|
|
20318
20422
|
folderId: result.data.folderId
|
|
20319
20423
|
});
|
|
@@ -20358,7 +20462,8 @@ async function listFolders(options) {
|
|
|
20358
20462
|
const result = listFoldersOptionsSchema.safeParse(options);
|
|
20359
20463
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
20360
20464
|
const { organizationId, parentFolderId, order, limit } = result.data;
|
|
20361
|
-
const
|
|
20465
|
+
const accessToken = await loadAccessToken();
|
|
20466
|
+
const client = await initOperatorClient(accessToken);
|
|
20362
20467
|
const pageDirection = toPageDirection(order);
|
|
20363
20468
|
return (await fetchPaged(async (pageToken, pageSize) => {
|
|
20364
20469
|
const response = await client.listOrganizationFolders({
|
|
@@ -20405,7 +20510,8 @@ const updateFolderOptionsSchema = z.object({
|
|
|
20405
20510
|
async function updateFolder(options) {
|
|
20406
20511
|
const result = updateFolderOptionsSchema.safeParse(options);
|
|
20407
20512
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
20408
|
-
const
|
|
20513
|
+
const accessToken = await loadAccessToken();
|
|
20514
|
+
const response = await (await initOperatorClient(accessToken)).updateOrganizationFolder({
|
|
20409
20515
|
organizationId: result.data.organizationId,
|
|
20410
20516
|
folderId: result.data.folderId,
|
|
20411
20517
|
folderName: result.data.name
|
|
@@ -20447,7 +20553,8 @@ const getOrganizationOptionsSchema = z.object({ organizationId: z.uuid({ message
|
|
|
20447
20553
|
async function getOrganization(options) {
|
|
20448
20554
|
const result = getOrganizationOptionsSchema.safeParse(options);
|
|
20449
20555
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
20450
|
-
const
|
|
20556
|
+
const accessToken = await loadAccessToken();
|
|
20557
|
+
const response = await (await initOperatorClient(accessToken)).getOrganization({ organizationId: result.data.organizationId });
|
|
20451
20558
|
if (!response.organization) throw new Error(`Organization "${result.data.organizationId}" not found.`);
|
|
20452
20559
|
return organizationInfo(response.organization);
|
|
20453
20560
|
}
|
|
@@ -20475,7 +20582,8 @@ const getCommand$1 = defineAppCommand({
|
|
|
20475
20582
|
*/
|
|
20476
20583
|
async function listOrganizations(options) {
|
|
20477
20584
|
const limit = options?.limit;
|
|
20478
|
-
const
|
|
20585
|
+
const accessToken = await loadAccessToken();
|
|
20586
|
+
const { userOrganizations } = await (await initOperatorClient(accessToken)).listUserOrganizations({});
|
|
20479
20587
|
const results = userOrganizations.map(userOrganizationInfo);
|
|
20480
20588
|
if (limit !== void 0) return results.slice(0, limit);
|
|
20481
20589
|
return results;
|
|
@@ -20561,7 +20669,8 @@ async function buildOrgTree(client, org, depth) {
|
|
|
20561
20669
|
* @returns Organization tree as structured data
|
|
20562
20670
|
*/
|
|
20563
20671
|
async function organizationTree(options) {
|
|
20564
|
-
const
|
|
20672
|
+
const accessToken = await loadAccessToken();
|
|
20673
|
+
const client = await initOperatorClient(accessToken);
|
|
20565
20674
|
let orgs;
|
|
20566
20675
|
if (options?.organizationId) {
|
|
20567
20676
|
orgs = (await listOrganizations()).filter((o) => o.organizationId === options.organizationId);
|
|
@@ -20594,7 +20703,8 @@ const treeCommand = defineAppCommand({
|
|
|
20594
20703
|
})
|
|
20595
20704
|
}),
|
|
20596
20705
|
run: async (args) => {
|
|
20597
|
-
const
|
|
20706
|
+
const accessToken = await loadAccessToken();
|
|
20707
|
+
const client = await initOperatorClient(accessToken);
|
|
20598
20708
|
let orgs;
|
|
20599
20709
|
if (args["organization-id"]) {
|
|
20600
20710
|
orgs = (await listOrganizations()).filter((o) => o.organizationId === args["organization-id"]);
|
|
@@ -20633,7 +20743,8 @@ const updateOrganizationOptionsSchema = z.object({
|
|
|
20633
20743
|
async function updateOrganization(options) {
|
|
20634
20744
|
const result = updateOrganizationOptionsSchema.safeParse(options);
|
|
20635
20745
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
20636
|
-
const
|
|
20746
|
+
const accessToken = await loadAccessToken();
|
|
20747
|
+
const response = await (await initOperatorClient(accessToken)).updateOrganization({
|
|
20637
20748
|
organizationId: result.data.organizationId,
|
|
20638
20749
|
organizationName: result.data.name
|
|
20639
20750
|
});
|
|
@@ -20664,7 +20775,8 @@ const updateCommand$1 = defineAppCommand({
|
|
|
20664
20775
|
//#endregion
|
|
20665
20776
|
//#region src/cli/commands/remove.ts
|
|
20666
20777
|
async function loadOptions$10(options) {
|
|
20667
|
-
const
|
|
20778
|
+
const accessToken = await loadAccessToken({ profile: options?.profile });
|
|
20779
|
+
const client = await initOperatorClient(accessToken);
|
|
20668
20780
|
const workspaceId = await loadWorkspaceId({
|
|
20669
20781
|
workspaceId: options?.workspaceId,
|
|
20670
20782
|
profile: options?.profile
|
|
@@ -20877,7 +20989,8 @@ async function fetchAIGateways(client, workspaceId, names) {
|
|
|
20877
20989
|
* @returns Deployed application, workspace, and AI Gateway information
|
|
20878
20990
|
*/
|
|
20879
20991
|
async function show(options) {
|
|
20880
|
-
const
|
|
20992
|
+
const accessToken = await loadAccessToken({ profile: options?.profile });
|
|
20993
|
+
const client = await initOperatorClient(accessToken);
|
|
20881
20994
|
const workspaceId = await loadWorkspaceId({
|
|
20882
20995
|
workspaceId: options?.workspaceId,
|
|
20883
20996
|
profile: options?.profile
|
|
@@ -20962,7 +21075,7 @@ async function withTimeout(p, ms, message) {
|
|
|
20962
21075
|
|
|
20963
21076
|
//#endregion
|
|
20964
21077
|
//#region src/cli/commands/staticwebsite/deploy.ts
|
|
20965
|
-
const CHUNK_SIZE =
|
|
21078
|
+
const CHUNK_SIZE = 65536;
|
|
20966
21079
|
const IGNORED_FILES = /* @__PURE__ */ new Set([
|
|
20967
21080
|
".DS_Store",
|
|
20968
21081
|
"thumbs.db",
|
|
@@ -21069,7 +21182,7 @@ async function uploadSingleFile(client, workspaceId, deploymentId, rootDir, file
|
|
|
21069
21182
|
throw error;
|
|
21070
21183
|
}
|
|
21071
21184
|
}
|
|
21072
|
-
await withTimeout(uploadWithLogging(),
|
|
21185
|
+
await withTimeout(uploadWithLogging(), 12e4, `Upload timed out for "${filePath}"`);
|
|
21073
21186
|
}
|
|
21074
21187
|
/**
|
|
21075
21188
|
* Log skipped files after a deployment, including reasons for skipping.
|
|
@@ -21098,7 +21211,8 @@ const deployCommand = defineAppCommand({
|
|
|
21098
21211
|
run: async (args) => {
|
|
21099
21212
|
await assertWritable({ profile: args.profile });
|
|
21100
21213
|
logger.info(`Deploying static website "${args.name}" from directory: ${args.dir}`);
|
|
21101
|
-
const
|
|
21214
|
+
const accessToken = await loadAccessToken({ profile: args.profile });
|
|
21215
|
+
const client = await initOperatorClient(accessToken);
|
|
21102
21216
|
const name = args.name;
|
|
21103
21217
|
const dir = path.resolve(process.cwd(), args.dir);
|
|
21104
21218
|
const workspaceId = await loadWorkspaceId({
|
|
@@ -21106,7 +21220,7 @@ const deployCommand = defineAppCommand({
|
|
|
21106
21220
|
profile: args.profile
|
|
21107
21221
|
});
|
|
21108
21222
|
if (!fs$1.existsSync(dir) || !fs$1.statSync(dir).isDirectory()) throw new Error(`Directory not found or not a directory: ${dir}`);
|
|
21109
|
-
const { url, skippedFiles } = await withTimeout(deployStaticWebsite(client, workspaceId, name, dir, !args.json),
|
|
21223
|
+
const { url, skippedFiles } = await withTimeout(deployStaticWebsite(client, workspaceId, name, dir, !args.json), 6e5, "Deployment timed out after 10 minutes.");
|
|
21110
21224
|
if (args.json) logger.out({
|
|
21111
21225
|
name,
|
|
21112
21226
|
workspaceId,
|
|
@@ -21198,9 +21312,9 @@ const MAX_FIELD_NAME_LENGTH = 63;
|
|
|
21198
21312
|
const TEMP_FIELD_SUFFIX = "Migrate";
|
|
21199
21313
|
/**
|
|
21200
21314
|
* Key identifying a field across snapshots and user-supplied options.
|
|
21201
|
-
* @param tableName - Name of the
|
|
21315
|
+
* @param tableName - Name of the table holding the field
|
|
21202
21316
|
* @param fieldName - Name of the field
|
|
21203
|
-
* @returns Key in `
|
|
21317
|
+
* @returns Key in `Table.field` form
|
|
21204
21318
|
*/
|
|
21205
21319
|
function fieldKey(tableName, fieldName) {
|
|
21206
21320
|
return `${tableName}.${fieldName}`;
|
|
@@ -22330,7 +22444,8 @@ async function script(options) {
|
|
|
22330
22444
|
const migrationNumber = parseMigrationNumberArg(options.number);
|
|
22331
22445
|
if (migrationNumber === 0) throw new Error(`Migration ${options.number} is the initial schema snapshot and cannot have a migration script.`);
|
|
22332
22446
|
const { config } = await loadConfig(options.configPath);
|
|
22333
|
-
const
|
|
22447
|
+
const configDir = path.dirname(config.path);
|
|
22448
|
+
const namespacesWithMigrations = getNamespacesWithMigrations(config, configDir);
|
|
22334
22449
|
if (namespacesWithMigrations.length === 0) throw new Error("No TailorDB services with migrations configuration found");
|
|
22335
22450
|
const targetNamespace = resolveTargetNamespace(namespacesWithMigrations, options.namespace);
|
|
22336
22451
|
const { migrationsDir } = assertDefined(namespacesWithMigrations.find((ns) => ns.namespace === targetNamespace), "namespace with migrations not found");
|
|
@@ -22502,7 +22617,8 @@ async function handleInitOption(namespaces, skipConfirmation) {
|
|
|
22502
22617
|
async function generate(options) {
|
|
22503
22618
|
logBetaWarning("tailordb migration");
|
|
22504
22619
|
const { config, plugins } = await loadConfig(options.configPath);
|
|
22505
|
-
const
|
|
22620
|
+
const configDir = path.dirname(config.path);
|
|
22621
|
+
const namespacesWithMigrations = getNamespacesWithMigrations(config, configDir);
|
|
22506
22622
|
if (namespacesWithMigrations.length === 0) {
|
|
22507
22623
|
logger.warn("No TailorDB namespaces with migrations config found.");
|
|
22508
22624
|
logger.info("Add \"migration: { directory: \\\"./migrations\\\" }\" to your db config to enable migrations.");
|
|
@@ -22542,7 +22658,7 @@ async function generate(options) {
|
|
|
22542
22658
|
if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
|
|
22543
22659
|
let pluginManager;
|
|
22544
22660
|
if (plugins.length > 0) pluginManager = new PluginManager(plugins);
|
|
22545
|
-
const { defineApplication } = await import("./application-
|
|
22661
|
+
const { defineApplication } = await import("./application-D4zOiLLa.mjs");
|
|
22546
22662
|
const application = defineApplication({
|
|
22547
22663
|
config,
|
|
22548
22664
|
pluginManager
|
|
@@ -22567,9 +22683,9 @@ async function generate(options) {
|
|
|
22567
22683
|
});
|
|
22568
22684
|
}
|
|
22569
22685
|
const renameSpecsByNamespace = matchFlagsToNamespaces(renameFlags, generations, renameSpecApplies, "--rename does not match a removed + added field pair");
|
|
22570
|
-
const typeRenameSpecsByNamespace = matchFlagsToNamespaces(typeRenameFlags, generations, typeRenameSpecApplies, "--rename does not match a removed + added
|
|
22686
|
+
const typeRenameSpecsByNamespace = matchFlagsToNamespaces(typeRenameFlags, generations, typeRenameSpecApplies, "--rename does not match a removed + added table pair");
|
|
22571
22687
|
const dropSpecsByNamespace = matchFlagsToNamespaces(dropFlags, generations, dropSpecApplies, "--drop does not match a removed field");
|
|
22572
|
-
const typeDropSpecsByNamespace = matchFlagsToNamespaces(typeDropFlags, generations, typeDropSpecApplies, "--drop does not match a removed
|
|
22688
|
+
const typeDropSpecsByNamespace = matchFlagsToNamespaces(typeDropFlags, generations, typeDropSpecApplies, "--drop does not match a removed table");
|
|
22573
22689
|
const expandContractKeysByNamespace = /* @__PURE__ */ new Map();
|
|
22574
22690
|
const matchedExpandContractFlags = /* @__PURE__ */ new Set();
|
|
22575
22691
|
const ineligibleExpandContracts = [];
|
|
@@ -22626,7 +22742,7 @@ async function generate(options) {
|
|
|
22626
22742
|
}
|
|
22627
22743
|
if (unresolvedCandidates.length > 0) {
|
|
22628
22744
|
const details = unresolvedCandidates.map(({ namespace, label, targets }) => ` - ${label} → ${targets.join(", ")}? (namespace: ${namespace})`).join("\n");
|
|
22629
|
-
throw new Error(`Possible rename(s) detected:\n${details}\nRe-run with --rename "
|
|
22745
|
+
throw new Error(`Possible rename(s) detected:\n${details}\nRe-run with --rename "Table.oldField:newField" (field) or --rename "OldTable:NewTable" (table) to record a rename and scaffold a data copy script, or --drop "Table.field" / --drop "Table" to confirm the removal.`);
|
|
22630
22746
|
}
|
|
22631
22747
|
for (const { migrationsDir, currentSnapshot, previousSnapshot, diff, expandPlans } of generations) if (!previousSnapshot) await generateInitialSnapshot(currentSnapshot, migrationsDir);
|
|
22632
22748
|
else await generateDiffFromSnapshot(previousSnapshot, assertDefined(diff, "Migration diff was not resolved during preflight"), migrationsDir, options, currentSnapshot, expandPlans ?? []);
|
|
@@ -22674,7 +22790,7 @@ async function generateInitialSnapshot(snapshot, migrationsDir) {
|
|
|
22674
22790
|
const result = await generateSchemaFile(snapshot, migrationsDir, 0);
|
|
22675
22791
|
logger.success(`Generated initial schema snapshot`);
|
|
22676
22792
|
logger.info(` File: ${result.filePath}`);
|
|
22677
|
-
logger.info(`
|
|
22793
|
+
logger.info(` Tables: ${Object.keys(snapshot.tables).length}`);
|
|
22678
22794
|
logger.log("\nThis is the baseline schema. Future changes will be tracked as diffs.");
|
|
22679
22795
|
}
|
|
22680
22796
|
/**
|
|
@@ -22746,7 +22862,7 @@ async function promptTypeRenameCandidate(candidate, addedTypeNames) {
|
|
|
22746
22862
|
default: true
|
|
22747
22863
|
}) ? firstTypeName : void 0;
|
|
22748
22864
|
return await prompt.select({
|
|
22749
|
-
message: `${oldTypeName} was removed. Was it renamed to one of these added
|
|
22865
|
+
message: `${oldTypeName} was removed. Was it renamed to one of these added tables?`,
|
|
22750
22866
|
choices: [...addedTypeNames.map((tableName) => ({
|
|
22751
22867
|
name: `Yes, renamed to ${tableName}`,
|
|
22752
22868
|
value: tableName
|
|
@@ -22905,7 +23021,8 @@ async function generateDiffFromSnapshot(previousSnapshot, diff, migrationsDir, o
|
|
|
22905
23021
|
});
|
|
22906
23022
|
return;
|
|
22907
23023
|
}
|
|
22908
|
-
const
|
|
23024
|
+
const migrationNumber = getNextMigrationNumber(migrationsDir);
|
|
23025
|
+
const result = await generateDiffFiles(diff, migrationsDir, migrationNumber, previousSnapshot, options.name);
|
|
22909
23026
|
logger.success(`Generated migration ${styles.bold(formatMigrationNumber(result.migrationNumber))}`);
|
|
22910
23027
|
logger.info(` Diff file: ${result.diffFilePath}`);
|
|
22911
23028
|
if (result.migrateFilePath) {
|
|
@@ -22991,13 +23108,14 @@ async function acknowledgeWarnings(options) {
|
|
|
22991
23108
|
message: "Record a reason acknowledging that this migration intentionally has no script?",
|
|
22992
23109
|
default: true
|
|
22993
23110
|
})) {
|
|
23111
|
+
const reason = await prompt.text({
|
|
23112
|
+
message: "Reason:",
|
|
23113
|
+
validate: (value) => value.trim() !== "" || "Reason must not be empty."
|
|
23114
|
+
});
|
|
22994
23115
|
const scriptSkipped = markMigrationScriptSkipped({
|
|
22995
23116
|
migrationsDir,
|
|
22996
23117
|
migrationNumber,
|
|
22997
|
-
reason
|
|
22998
|
-
message: "Reason:",
|
|
22999
|
-
validate: (value) => value.trim() !== "" || "Reason must not be empty."
|
|
23000
|
-
})
|
|
23118
|
+
reason
|
|
23001
23119
|
});
|
|
23002
23120
|
logger.success(`Recorded that migration ${styles.bold(label)} intentionally has no migration script`);
|
|
23003
23121
|
logger.info(` Reason: ${scriptSkipped.reason}`);
|
|
@@ -23022,7 +23140,7 @@ async function acknowledgeWarnings(options) {
|
|
|
23022
23140
|
*/
|
|
23023
23141
|
const generateCommand = defineAppCommand({
|
|
23024
23142
|
name: "generate",
|
|
23025
|
-
description: "Generate migration files by detecting schema differences between current local
|
|
23143
|
+
description: "Generate migration files by detecting schema differences between current local tables and the previous migration snapshot.",
|
|
23026
23144
|
args: z.strictObject({
|
|
23027
23145
|
...confirmationArgs,
|
|
23028
23146
|
...configArg,
|
|
@@ -23031,9 +23149,9 @@ const generateCommand = defineAppCommand({
|
|
|
23031
23149
|
description: "Optional description for the migration"
|
|
23032
23150
|
}),
|
|
23033
23151
|
init: arg(z.boolean().default(false), { description: "Delete existing migrations and start fresh" }),
|
|
23034
|
-
rename: arg(z.array(z.string()).optional(), { description: "Record a field or
|
|
23035
|
-
drop: arg(z.array(z.string()).optional(), { description: "Confirm that a removed field or
|
|
23036
|
-
"expand-contract": arg(z.array(z.string()).optional(), { description: "Convert a field type through a temporary field (format: \"
|
|
23152
|
+
rename: arg(z.array(z.string()).optional(), { description: "Record a field or table rename instead of remove + add (format: \"Table.oldField:newField\" or \"OldTable:NewTable\"; repeatable). Renames require a migration script that copies the data." }),
|
|
23153
|
+
drop: arg(z.array(z.string()).optional(), { description: "Confirm that a removed field or table is a genuine removal, not a rename (format: \"Table.field\" or \"Table\"; repeatable). Required in non-interactive runs for a removal with rename candidates." }),
|
|
23154
|
+
"expand-contract": arg(z.array(z.string()).optional(), { description: "Convert a field type through a temporary field (format: \"Table.field\"; repeatable). Generates two migrations." })
|
|
23037
23155
|
}),
|
|
23038
23156
|
run: async (args) => {
|
|
23039
23157
|
await generate({
|
|
@@ -23247,7 +23365,7 @@ async function bundleSeedScript(namespace, typeNames, baseDir = process.cwd()) {
|
|
|
23247
23365
|
* into multiple chunks at type boundaries (or record boundaries for large types).
|
|
23248
23366
|
*/
|
|
23249
23367
|
/** Default maximum message size: 3.5MB (conservative limit for gRPC) */
|
|
23250
|
-
const DEFAULT_MAX_MESSAGE_SIZE =
|
|
23368
|
+
const DEFAULT_MAX_MESSAGE_SIZE = 3670016;
|
|
23251
23369
|
/** Reserved bytes for message metadata overhead */
|
|
23252
23370
|
const METADATA_OVERHEAD = 1024;
|
|
23253
23371
|
/**
|
|
@@ -23327,7 +23445,7 @@ function chunkSeedData(options) {
|
|
|
23327
23445
|
order: [type]
|
|
23328
23446
|
})) > argBudget) {
|
|
23329
23447
|
const singleRecordSize = byteSize(JSON.stringify(record));
|
|
23330
|
-
throw new Error(`A single record in
|
|
23448
|
+
throw new Error(`A single record in table "${type}" (${singleRecordSize} bytes) exceeds the message size budget (${argBudget} bytes). Consider increasing maxMessageSize or reducing the record size.`);
|
|
23331
23449
|
}
|
|
23332
23450
|
const testBatch = [...recordBatch, record];
|
|
23333
23451
|
const testData = {
|
|
@@ -23374,9 +23492,9 @@ function byteSize(str) {
|
|
|
23374
23492
|
//#endregion
|
|
23375
23493
|
//#region src/plugin/builtin/seed/seed-type-processor.ts
|
|
23376
23494
|
/**
|
|
23377
|
-
* Processes TailorDB
|
|
23378
|
-
* @param type - Parsed TailorDB
|
|
23379
|
-
* @param namespace - Namespace of the
|
|
23495
|
+
* Processes TailorDB tables to extract seed type information
|
|
23496
|
+
* @param type - Parsed TailorDB table
|
|
23497
|
+
* @param namespace - Namespace of the table
|
|
23380
23498
|
* @returns Seed type information
|
|
23381
23499
|
*/
|
|
23382
23500
|
function processSeedTypeInfo(type, namespace) {
|
|
@@ -23412,7 +23530,8 @@ function buildSeedNamespaceConfigs(tailordb) {
|
|
|
23412
23530
|
types.push(typeInfo.name);
|
|
23413
23531
|
dependencies[typeInfo.name] = typeInfo.dependencies;
|
|
23414
23532
|
if (typeInfo.selfRefFields.length > 0) selfRefTypes.push(typeInfo.name);
|
|
23415
|
-
const
|
|
23533
|
+
const source = assertDefined(ns.sourceInfo.get(typeName), `source info missing for type: ${typeName}`);
|
|
23534
|
+
const linesDb = processLinesDb(type, source);
|
|
23416
23535
|
requiredFields[typeInfo.name] = Object.entries(type.fields).filter(([fieldName, field]) => field.config.required !== false && !linesDb.optionalFields.includes(fieldName) && !linesDb.omitFields.includes(fieldName)).map(([fieldName]) => fieldName);
|
|
23417
23536
|
}
|
|
23418
23537
|
return {
|
|
@@ -23439,9 +23558,10 @@ async function loadApplicationNamespaces(options = {}) {
|
|
|
23439
23558
|
config,
|
|
23440
23559
|
configPath: config.path
|
|
23441
23560
|
});
|
|
23561
|
+
const pluginManager = plugins.length > 0 ? new PluginManager(plugins) : void 0;
|
|
23442
23562
|
const application = defineApplication({
|
|
23443
23563
|
config,
|
|
23444
|
-
pluginManager
|
|
23564
|
+
pluginManager
|
|
23445
23565
|
});
|
|
23446
23566
|
const namespaceNames = typeof options.namespaces === "function" ? options.namespaces(config, plugins) : options.namespaces;
|
|
23447
23567
|
const namespaceFilter = namespaceNames ? new Set(namespaceNames) : void 0;
|
|
@@ -23523,9 +23643,9 @@ async function loadSeedContext(options = {}) {
|
|
|
23523
23643
|
//#endregion
|
|
23524
23644
|
//#region src/cli/shared/tailordb-namespace.ts
|
|
23525
23645
|
/**
|
|
23526
|
-
* Resolve TailorDB
|
|
23646
|
+
* Resolve TailorDB table names to namespace names.
|
|
23527
23647
|
* @param args - Resolution inputs
|
|
23528
|
-
* @returns
|
|
23648
|
+
* @returns Table to namespace map for found tables
|
|
23529
23649
|
*/
|
|
23530
23650
|
async function resolveTypeNamespaces(args) {
|
|
23531
23651
|
const requestedTypesByLowercase = /* @__PURE__ */ new Map();
|
|
@@ -23571,18 +23691,18 @@ async function truncateSingleType(options, client) {
|
|
|
23571
23691
|
namespaceName: options.namespaceName,
|
|
23572
23692
|
tailordbTypeName: options.typeName
|
|
23573
23693
|
});
|
|
23574
|
-
logger.success(`Truncated
|
|
23694
|
+
logger.success(`Truncated table "${options.typeName}" in namespace "${options.namespaceName}"`);
|
|
23575
23695
|
}
|
|
23576
23696
|
async function truncateNamespace(workspaceId, namespaceName, client) {
|
|
23577
23697
|
await client.truncateTailorDBTypes({
|
|
23578
23698
|
workspaceId,
|
|
23579
23699
|
namespaceName
|
|
23580
23700
|
});
|
|
23581
|
-
logger.success(`Truncated all
|
|
23701
|
+
logger.success(`Truncated all tables in namespace "${namespaceName}"`);
|
|
23582
23702
|
}
|
|
23583
23703
|
/**
|
|
23584
23704
|
* Truncate TailorDB data based on the given options.
|
|
23585
|
-
* @param options - Truncate options (all, namespace, or
|
|
23705
|
+
* @param options - Truncate options (all, namespace, or tables)
|
|
23586
23706
|
* @returns Promise that resolves when truncation completes
|
|
23587
23707
|
*/
|
|
23588
23708
|
async function truncate(options) {
|
|
@@ -23592,21 +23712,22 @@ async function truncate(options) {
|
|
|
23592
23712
|
});
|
|
23593
23713
|
}
|
|
23594
23714
|
async function $truncate(options = {}) {
|
|
23595
|
-
const
|
|
23715
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
23716
|
+
const client = await initOperatorClient(accessToken);
|
|
23596
23717
|
const workspaceId = await loadWorkspaceId({
|
|
23597
23718
|
workspaceId: options.workspaceId,
|
|
23598
23719
|
profile: options.profile
|
|
23599
23720
|
});
|
|
23600
|
-
const
|
|
23721
|
+
const hasTables = options.tables && options.tables.length > 0;
|
|
23601
23722
|
const hasNamespace = !!options.namespace;
|
|
23602
23723
|
const hasAll = !!options.all;
|
|
23603
23724
|
const optionCount = [
|
|
23604
23725
|
hasAll,
|
|
23605
23726
|
hasNamespace,
|
|
23606
|
-
|
|
23727
|
+
hasTables
|
|
23607
23728
|
].filter(Boolean).length;
|
|
23608
|
-
if (optionCount === 0) throw new Error("Please specify one of: --all, --namespace <name>, or
|
|
23609
|
-
if (optionCount > 1) throw new Error("Options --all, --namespace, and
|
|
23729
|
+
if (optionCount === 0) throw new Error("Please specify one of: --all, --namespace <name>, or table names");
|
|
23730
|
+
if (optionCount > 1) throw new Error("Options --all, --namespace, and table names are mutually exclusive. Please specify only one.");
|
|
23610
23731
|
const { config } = await loadConfig(options.configPath);
|
|
23611
23732
|
const namespaces = extractOwnedNamespaces(config);
|
|
23612
23733
|
if (hasAll) {
|
|
@@ -23647,20 +23768,20 @@ async function $truncate(options = {}) {
|
|
|
23647
23768
|
await truncateNamespace(workspaceId, namespace, client);
|
|
23648
23769
|
return;
|
|
23649
23770
|
}
|
|
23650
|
-
if (
|
|
23651
|
-
const typeNames = assertDefined(options.
|
|
23771
|
+
if (hasTables) {
|
|
23772
|
+
const typeNames = assertDefined(options.tables, "tables option missing");
|
|
23652
23773
|
const typeNamespaceMap = await resolveTypeNamespaces({
|
|
23653
23774
|
workspaceId,
|
|
23654
23775
|
namespaces,
|
|
23655
23776
|
typeNames,
|
|
23656
23777
|
client
|
|
23657
23778
|
});
|
|
23658
|
-
const
|
|
23659
|
-
if (
|
|
23779
|
+
const notFoundTables = typeNames.filter((typeName) => !typeNamespaceMap.has(typeName));
|
|
23780
|
+
if (notFoundTables.length > 0) throw new Error(`The following tables were not found in any namespace: ${notFoundTables.join(", ")}`);
|
|
23660
23781
|
if (!options.yes) {
|
|
23661
|
-
const
|
|
23782
|
+
const tableList = typeNames.join(", ");
|
|
23662
23783
|
if (!await prompt.confirm({
|
|
23663
|
-
message: `This will truncate the following
|
|
23784
|
+
message: `This will truncate the following tables: ${tableList}. Continue?`,
|
|
23664
23785
|
default: false
|
|
23665
23786
|
})) {
|
|
23666
23787
|
logger.info("Truncate cancelled.");
|
|
@@ -23684,9 +23805,9 @@ const truncateCommand = defineAppCommand({
|
|
|
23684
23805
|
args: z.strictObject({
|
|
23685
23806
|
...deploymentArgs,
|
|
23686
23807
|
...confirmationArgs,
|
|
23687
|
-
|
|
23808
|
+
tables: arg(z.string().array().optional(), {
|
|
23688
23809
|
positional: true,
|
|
23689
|
-
description: "
|
|
23810
|
+
description: "Table names to truncate"
|
|
23690
23811
|
}),
|
|
23691
23812
|
all: arg(z.boolean().default(false), {
|
|
23692
23813
|
alias: "a",
|
|
@@ -23699,14 +23820,14 @@ const truncateCommand = defineAppCommand({
|
|
|
23699
23820
|
}),
|
|
23700
23821
|
run: async (args) => {
|
|
23701
23822
|
await assertWritable({ profile: args.profile });
|
|
23702
|
-
const
|
|
23823
|
+
const tables = args.tables && args.tables.length > 0 ? args.tables : void 0;
|
|
23703
23824
|
await $truncate({
|
|
23704
23825
|
workspaceId: args["workspace-id"],
|
|
23705
23826
|
profile: args.profile,
|
|
23706
23827
|
configPath: args.config,
|
|
23707
23828
|
all: args.all,
|
|
23708
23829
|
namespace: args.namespace,
|
|
23709
|
-
|
|
23830
|
+
tables,
|
|
23710
23831
|
yes: args.yes
|
|
23711
23832
|
});
|
|
23712
23833
|
}
|
|
@@ -23720,7 +23841,8 @@ const truncateCommand = defineAppCommand({
|
|
|
23720
23841
|
* @returns List of workflows
|
|
23721
23842
|
*/
|
|
23722
23843
|
async function listWorkflows(options) {
|
|
23723
|
-
const
|
|
23844
|
+
const accessToken = await loadAccessToken({ profile: options?.profile });
|
|
23845
|
+
const client = await initOperatorClient(accessToken);
|
|
23724
23846
|
const workspaceId = await loadWorkspaceId({
|
|
23725
23847
|
workspaceId: options?.workspaceId,
|
|
23726
23848
|
profile: options?.profile
|
|
@@ -23767,7 +23889,8 @@ const listCommand$2 = defineAppCommand({
|
|
|
23767
23889
|
* @returns Resume result with wait helper
|
|
23768
23890
|
*/
|
|
23769
23891
|
async function resumeWorkflow(options) {
|
|
23770
|
-
const
|
|
23892
|
+
const accessToken = await loadAccessToken({ profile: options.profile });
|
|
23893
|
+
const client = await initOperatorClient(accessToken);
|
|
23771
23894
|
const workspaceId = await loadWorkspaceId({
|
|
23772
23895
|
workspaceId: options.workspaceId,
|
|
23773
23896
|
profile: options.profile
|
|
@@ -23984,8 +24107,9 @@ const healthOptionsSchema = z.object({
|
|
|
23984
24107
|
async function loadOptions$9(options) {
|
|
23985
24108
|
const result = healthOptionsSchema.safeParse(options);
|
|
23986
24109
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
24110
|
+
const accessToken = await loadAccessToken({ profile: result.data.profile });
|
|
23987
24111
|
return {
|
|
23988
|
-
client: await initOperatorClient(
|
|
24112
|
+
client: await initOperatorClient(accessToken),
|
|
23989
24113
|
workspaceId: await loadWorkspaceId({
|
|
23990
24114
|
workspaceId: result.data.workspaceId,
|
|
23991
24115
|
profile: result.data.profile
|
|
@@ -24000,10 +24124,11 @@ async function loadOptions$9(options) {
|
|
|
24000
24124
|
*/
|
|
24001
24125
|
async function getAppHealth(options) {
|
|
24002
24126
|
const { client, workspaceId, name } = await loadOptions$9(options);
|
|
24003
|
-
|
|
24127
|
+
const response = await client.getApplicationSchemaHealth({
|
|
24004
24128
|
workspaceId,
|
|
24005
24129
|
applicationName: name
|
|
24006
|
-
})
|
|
24130
|
+
});
|
|
24131
|
+
return appHealthInfo(name, response);
|
|
24007
24132
|
}
|
|
24008
24133
|
const healthCommand = defineAppCommand({
|
|
24009
24134
|
name: "health",
|
|
@@ -24041,8 +24166,9 @@ const listAppsOptionsSchema = z.object({
|
|
|
24041
24166
|
async function loadOptions$8(options) {
|
|
24042
24167
|
const result = listAppsOptionsSchema.safeParse(options);
|
|
24043
24168
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
24169
|
+
const accessToken = await loadAccessToken({ profile: result.data.profile });
|
|
24044
24170
|
return {
|
|
24045
|
-
client: await initOperatorClient(
|
|
24171
|
+
client: await initOperatorClient(accessToken),
|
|
24046
24172
|
workspaceId: await loadWorkspaceId({
|
|
24047
24173
|
workspaceId: result.data.workspaceId,
|
|
24048
24174
|
profile: result.data.profile
|
|
@@ -24098,8 +24224,9 @@ const deleteWorkspaceOptionsSchema = z.object({ workspaceId: z.uuid({ message: "
|
|
|
24098
24224
|
async function loadOptions$7(options) {
|
|
24099
24225
|
const result = deleteWorkspaceOptionsSchema.safeParse(options);
|
|
24100
24226
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
24227
|
+
const accessToken = await loadAccessToken();
|
|
24101
24228
|
return {
|
|
24102
|
-
client: await initOperatorClient(
|
|
24229
|
+
client: await initOperatorClient(accessToken),
|
|
24103
24230
|
workspaceId: result.data.workspaceId
|
|
24104
24231
|
};
|
|
24105
24232
|
}
|
|
@@ -24133,9 +24260,10 @@ const deleteCommand = defineAppCommand({
|
|
|
24133
24260
|
}
|
|
24134
24261
|
const workspaceResource = workspace.workspace;
|
|
24135
24262
|
const workspaceName = workspaceResource?.name ?? workspaceId;
|
|
24263
|
+
const folderName = workspaceResource ? await resolveWorkspaceFolderName(client, workspaceResource) : "";
|
|
24136
24264
|
const displayName = workspaceDisplayName({
|
|
24137
24265
|
name: workspaceName,
|
|
24138
|
-
folderName
|
|
24266
|
+
folderName
|
|
24139
24267
|
});
|
|
24140
24268
|
if (!args.yes) {
|
|
24141
24269
|
const confirmation = await prompt.text({ message: `Enter the workspace name to confirm deletion (${displayName}):` });
|
|
@@ -24165,8 +24293,9 @@ const getWorkspaceOptionsSchema = z.object({
|
|
|
24165
24293
|
async function loadOptions$6(options) {
|
|
24166
24294
|
const result = getWorkspaceOptionsSchema.safeParse(options);
|
|
24167
24295
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
24296
|
+
const accessToken = await loadAccessToken({ profile: result.data.profile });
|
|
24168
24297
|
return {
|
|
24169
|
-
client: await initOperatorClient(
|
|
24298
|
+
client: await initOperatorClient(accessToken),
|
|
24170
24299
|
workspaceId: await loadWorkspaceId({
|
|
24171
24300
|
workspaceId: result.data.workspaceId,
|
|
24172
24301
|
profile: result.data.profile
|
|
@@ -24211,8 +24340,9 @@ const restoreWorkspaceOptionsSchema = z.object({ workspaceId: z.uuid({ message:
|
|
|
24211
24340
|
async function loadOptions$5(options) {
|
|
24212
24341
|
const result = restoreWorkspaceOptionsSchema.safeParse(options);
|
|
24213
24342
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
24343
|
+
const accessToken = await loadAccessToken();
|
|
24214
24344
|
return {
|
|
24215
|
-
client: await initOperatorClient(
|
|
24345
|
+
client: await initOperatorClient(accessToken),
|
|
24216
24346
|
workspaceId: result.data.workspaceId
|
|
24217
24347
|
};
|
|
24218
24348
|
}
|
|
@@ -24291,8 +24421,9 @@ const inviteUserOptionsSchema = z.object({
|
|
|
24291
24421
|
async function loadOptions$4(options) {
|
|
24292
24422
|
const result = inviteUserOptionsSchema.safeParse(options);
|
|
24293
24423
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
24424
|
+
const accessToken = await loadAccessToken({ profile: result.data.profile });
|
|
24294
24425
|
return {
|
|
24295
|
-
client: await initOperatorClient(
|
|
24426
|
+
client: await initOperatorClient(accessToken),
|
|
24296
24427
|
workspaceId: await loadWorkspaceId({
|
|
24297
24428
|
workspaceId: result.data.workspaceId,
|
|
24298
24429
|
profile: result.data.profile
|
|
@@ -24348,8 +24479,9 @@ const listUsersOptionsSchema = z.object({
|
|
|
24348
24479
|
async function loadOptions$3(options) {
|
|
24349
24480
|
const result = listUsersOptionsSchema.safeParse(options);
|
|
24350
24481
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
24482
|
+
const accessToken = await loadAccessToken({ profile: result.data.profile });
|
|
24351
24483
|
return {
|
|
24352
|
-
client: await initOperatorClient(
|
|
24484
|
+
client: await initOperatorClient(accessToken),
|
|
24353
24485
|
workspaceId: await loadWorkspaceId({
|
|
24354
24486
|
workspaceId: result.data.workspaceId,
|
|
24355
24487
|
profile: result.data.profile
|
|
@@ -24404,8 +24536,9 @@ const removeUserOptionsSchema = z.object({
|
|
|
24404
24536
|
async function loadOptions$2(options) {
|
|
24405
24537
|
const result = removeUserOptionsSchema.safeParse(options);
|
|
24406
24538
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
24539
|
+
const accessToken = await loadAccessToken({ profile: result.data.profile });
|
|
24407
24540
|
return {
|
|
24408
|
-
client: await initOperatorClient(
|
|
24541
|
+
client: await initOperatorClient(accessToken),
|
|
24409
24542
|
workspaceId: await loadWorkspaceId({
|
|
24410
24543
|
workspaceId: result.data.workspaceId,
|
|
24411
24544
|
profile: result.data.profile
|
|
@@ -24461,8 +24594,9 @@ const updateUserOptionsSchema = z.object({
|
|
|
24461
24594
|
async function loadOptions$1(options) {
|
|
24462
24595
|
const result = updateUserOptionsSchema.safeParse(options);
|
|
24463
24596
|
if (!result.success) throw new Error(assertDefined(result.error.issues[0], "Zod returned no issues").message);
|
|
24597
|
+
const accessToken = await loadAccessToken({ profile: result.data.profile });
|
|
24464
24598
|
return {
|
|
24465
|
-
client: await initOperatorClient(
|
|
24599
|
+
client: await initOperatorClient(accessToken),
|
|
24466
24600
|
workspaceId: await loadWorkspaceId({
|
|
24467
24601
|
workspaceId: result.data.workspaceId,
|
|
24468
24602
|
profile: result.data.profile
|
|
@@ -24641,7 +24775,7 @@ function mapQueryExecutionError(args) {
|
|
|
24641
24775
|
if (args.engine === "sql" && message.includes("sqlaccess error: failed to fetch schema: query returned an unexpected number of rows")) return createCLIError({
|
|
24642
24776
|
code: "invalid_namespace",
|
|
24643
24777
|
message: `Failed to load TailorDB schema for namespace '${args.namespace}'.`,
|
|
24644
|
-
suggestion: "Ensure the query references TailorDB
|
|
24778
|
+
suggestion: "Ensure the query references TailorDB tables from a single namespace and re-apply if needed."
|
|
24645
24779
|
});
|
|
24646
24780
|
if (args.engine === "sql" && message.includes("sqlaccess error: failed to parse:")) {
|
|
24647
24781
|
const parserReason = message.split("sqlaccess error: failed to parse:").at(1)?.split("\n").at(0)?.trim();
|
|
@@ -24769,9 +24903,9 @@ function isSqlInputComplete(input) {
|
|
|
24769
24903
|
//#endregion
|
|
24770
24904
|
//#region src/cli/query/sql-type-extractor.ts
|
|
24771
24905
|
/**
|
|
24772
|
-
* Extract TailorDB
|
|
24906
|
+
* Extract TailorDB table names from SQL query.
|
|
24773
24907
|
* @param query - SQL query
|
|
24774
|
-
* @returns
|
|
24908
|
+
* @returns Table names referenced by query
|
|
24775
24909
|
*/
|
|
24776
24910
|
function extractTypeNamesFromSql(query) {
|
|
24777
24911
|
let statements;
|
|
@@ -24849,16 +24983,17 @@ function extractColumnTemplate(query) {
|
|
|
24849
24983
|
//#endregion
|
|
24850
24984
|
//#region src/cli/query/type-field-order.ts
|
|
24851
24985
|
/**
|
|
24852
|
-
* Load field definition order for all TailorDB
|
|
24986
|
+
* Load field definition order for all TailorDB tables in a namespace.
|
|
24853
24987
|
* @param config - Loaded application configuration
|
|
24854
24988
|
* @param namespace - TailorDB namespace name
|
|
24855
|
-
* @returns Map of
|
|
24989
|
+
* @returns Map of table name to field names in definition order
|
|
24856
24990
|
*/
|
|
24857
24991
|
async function loadTypeFieldOrder(config, namespace) {
|
|
24858
24992
|
const fieldOrder = /* @__PURE__ */ new Map();
|
|
24859
24993
|
const dbConfig = config.db?.[namespace];
|
|
24860
24994
|
if (!dbConfig || !("files" in dbConfig) || dbConfig.files.length === 0) return fieldOrder;
|
|
24861
|
-
const
|
|
24995
|
+
const baseDir = path.dirname(config.path);
|
|
24996
|
+
const typeFiles = loadFilesWithIgnores(dbConfig, baseDir);
|
|
24862
24997
|
await Promise.all(typeFiles.map(async (typeFile) => {
|
|
24863
24998
|
try {
|
|
24864
24999
|
const module = await import(pathToFileURL(typeFile).href);
|
|
@@ -24900,10 +25035,10 @@ async function getNamespaceFromSqlQuery(workspaceId, query, client, namespaces)
|
|
|
24900
25035
|
client
|
|
24901
25036
|
});
|
|
24902
25037
|
const notFoundTypes = typeNames.filter((typeName) => !typeNamespaceMap.has(typeName));
|
|
24903
|
-
if (notFoundTypes.length > 0) throw new Error(`Could not find namespace for
|
|
25038
|
+
if (notFoundTypes.length > 0) throw new Error(`Could not find namespace for tables in query: ${notFoundTypes.join(", ")}.`);
|
|
24904
25039
|
const namespacesFromTypes = new Set(typeNamespaceMap.values());
|
|
24905
25040
|
if (namespacesFromTypes.size === 1) return assertDefined([...namespacesFromTypes][0], "namespace from types missing");
|
|
24906
|
-
throw new Error(`Query references
|
|
25041
|
+
throw new Error(`Query references tables from multiple namespaces: ${[...namespacesFromTypes].join(", ")}.`);
|
|
24907
25042
|
}
|
|
24908
25043
|
async function loadOptions(options) {
|
|
24909
25044
|
const result = queryBaseOptionsSchema.safeParse(options);
|
|
@@ -24914,7 +25049,8 @@ async function loadOptions(options) {
|
|
|
24914
25049
|
profile: result.data.profile
|
|
24915
25050
|
});
|
|
24916
25051
|
if (!machineUser) throw new Error("Machine user is required. Specify --machine-user, set TAILOR_PLATFORM_MACHINE_USER_NAME, or set a profile default with 'tailor profile update <profile> --machine-user <name>'.");
|
|
24917
|
-
const
|
|
25052
|
+
const accessToken = await loadAccessToken({ profile: result.data.profile });
|
|
25053
|
+
const client = await initOperatorClient(accessToken);
|
|
24918
25054
|
const workspaceId = await loadWorkspaceId({
|
|
24919
25055
|
workspaceId: result.data.workspaceId,
|
|
24920
25056
|
profile: result.data.profile
|
|
@@ -25129,7 +25265,7 @@ async function runRepl(options) {
|
|
|
25129
25265
|
const execute = await prepareQueryExecutor(options);
|
|
25130
25266
|
const historyPath = getReplHistoryPath(options.engine, options.profile, options.workspaceId);
|
|
25131
25267
|
const validate = createReplValidator(options.engine);
|
|
25132
|
-
const { highlightSqlLine, highlightGraphqlLine, replTransform } = await import("./repl-editor-
|
|
25268
|
+
const { highlightSqlLine, highlightGraphqlLine, replTransform } = await import("./repl-editor-F9LotMNx.mjs");
|
|
25133
25269
|
const highlight = options.engine === "sql" ? highlightSqlLine : highlightGraphqlLine;
|
|
25134
25270
|
const prompt = createPrompt({
|
|
25135
25271
|
prefix: "",
|
|
@@ -25540,4 +25676,4 @@ async function registerTsHook(tsHookUrl) {
|
|
|
25540
25676
|
|
|
25541
25677
|
//#endregion
|
|
25542
25678
|
export { treeCommand as $, sanitizeMigrationLabel as $n, listWorkspaces as $t, truncate as A, MIGRATION_FILE_NAMES as An, readPlatformConfig as Ar, triggerExecutor as At, MIGRATION_REVIEW_REQUIRED_MARKER as B, getLatestMigrationNumber as Bn, deploymentArgs as Br, getCommand$5 as Bt, healthCommand as C, captureFileState as Cn, loadConfigPath as Cr, listCommand$7 as Ct, resumeWorkflow as D, INITIAL_SCHEMA_NUMBER as Dn, loadStoredUserTokens as Dr, listWebhookExecutors as Dt, resumeCommand as E, DIFF_FILE_NAME as En, loadPlatformClientConfig as Er, getFunctionRegistry as Et, chunkSeedData as F, assertValidMigrationFiles as Fn, writePlatformConfig as Fr, jobsCommand as Ft, showCommand as G, loadDiff as Gn, resolveMachineUserInputSource as Gr, functionExecutionStatusToString as Gt, deployCommand as H, getMigrationFilePath as Hn, multiConfigArg as Hr, executionsCommand as Ht, bundleSeedScript as I, compareLocalTypesWithSnapshot as In, defineAppCommand as Ir, listExecutorJobs as It, remove as J, reconstructSnapshotFromMigrations as Jn, deploy as Jt, extractOwnedNamespaces as K, loadSnapshot as Kn, toPageDirection as Kr, getCommand$6 as Kt, generate as L, compareSnapshots as Ln, commonArgs as Lr, watchExecutorJob as Lt, loadSeedContext as M, SCHEMA_FILE_NAME as Mn, resolveConfigUser as Mr, listExecutors as Mt, loadApplicationNamespaces as N, UnsupportedMigrationFileVersionError as Nn, resolveUserTokenKey as Nr, getExecutorJob as Nt, listCommand$2 as O, MIGRATE_FILE_NAME as On, loadWorkspaceId as Or, webhookCommand as Ot, loadTailorDBNamespaces as P, assertMigrationNumberExists as Pn, saveUserTokens as Pr, getExecutorWaitFailureMessage as Pt, organizationTree as Q, handleOptionalToRequiredError as Qn, listCommand$9 as Qt, generateCommand as R, createSnapshotFromLocalTypes as Rn, configArg as Rr, startCommand as Rt, getAppHealth as S, protoGqlPermission as Sn, loadAccessToken as Sr, generate$1 as St, waitWorkflowExecution as T, DB_TYPES_FILE_NAME as Tn, loadMachineUserName as Tr, getCommand$4 as Tt, deployStaticWebsite as U, getMigrationFiles as Un, pagedLogArgs as Ur, getWorkflowExecution as Ut, generateSchemaFile as V, getMigrationDirPath as Vn, isVerbose as Vr, getWorkflow as Vt, show as W, getNextMigrationNumber as Wn, paginationArgs as Wr, listWorkflowExecutions as Wt, updateCommand$1 as X, MIGRATION_LABEL_KEY as Xn, deployMigrationTestBaseline as Xt, removeCommand$1 as Y, MIGRATION_HISTORY_LABEL_KEY as Yn, deployFromCLI as Yt, updateOrganization as Z, createMigrationHistoryId as Zn, deployMigrationTestTarget as Zt, getWorkspace as _, verifyRemoteSchema as _n, loadConfig as _r, getOAuth2Client as _t, queryCommand as a, ensureConfigId as an, resourceTrn as ar, updateFolder as at, listApps as b, compareSnapshotWithRemote as bn, hasAnyUserTokenEntry as br, listCommand$6 as bt, removeCommand as c, executeScript as cn, sdkVersionLabelKey as cr, getCommand$2 as ct, listUsers as d, bundleMigrationScript as dn, generateUserTypes as dr, deleteFolder as dt, createCommand$1 as en, formatDiffSummary as er, listCommand$3 as et, inviteCommand as f, checkMigrationDiffs as fn, formatMigrationNumber as fr, createCommand as ft, getCommand as g, toTailorDBDeployInput as gn, assertWritable as gr, getCommand$3 as gt, restoreWorkspace as h, logRemoteDriftGuidance as hn, apiCall as hr, listOAuth2Clients as ht, query as i, workspaceNameSchema as in, selectTargetNamespace as ir, updateCommand$2 as it, truncateCommand as j, MIGRATION_NUMBER_PATTERN as jn, removeLegacyUserAlias as jr, listCommand$8 as jt, listWorkflows as k, MIGRATE_TEST_FILE_NAME as kn, platformConfigFromProfile as kr, triggerCommand as kt, removeUser as l, waitForExecution as ln, writeMetadataLabels as lr, getFolder as lt, restoreCommand as m, formatRemoteVerificationResults as mn, prompt as mr, listCommand$5 as mt, errorToJson as n, createWorkspace$1 as nn, hasChanges as nr, getCommand$1 as nt, updateCommand as o, getMigrationMachineUser as on, sdkAppIdLabelKey as or, listCommand$4 as ot, inviteUser as p, fetchRemoteSchemaSnapshot as pn, parseMigrationNumberArg as pr, createFolder as pt, logBetaWarning as q, normalizeSchemaSnapshot as qn, workspaceArgs as qr, getExecutor as qt, serializeError as r, formatKeyValueTable as rn, getNamespacesWithMigrations as rr, getOrganization as rt, updateUser as s, updateMigrationLabel as sn, sdkNameLabelKey as sr, listFolders as st, registerTsHook as t, createValidatedWorkspaceWithClient as tn, formatMigrationDiff as tr, listOrganizations as tt, listCommand as u, formatMigrationScriptCommand as un, PluginManager as ur, deleteCommand$1 as ut, deleteCommand as v, fetchRemoteMigrationNumber as vn, deleteUserTokens as vr, getMachineUserToken as vt, waitCommand as w, captureMigrationFileState as wn, loadConsoleBaseUrl as wr, listFunctionRegistries as wt, listCommand$1 as x, generateAllTypeManifestsFromSnapshot as xn, hasUserTokenEntry as xr, listMachineUsers as xt, deleteWorkspace as y, fetchRemoteMigrationState as yn, fetchLatestToken as yr, tokenCommand as yt, scriptCommand as z, formatSchemaDrifts as zn, confirmationArgs as zr, startWorkflow as zt };
|
|
25543
|
-
//# sourceMappingURL=register-ts-hook-
|
|
25679
|
+
//# sourceMappingURL=register-ts-hook-Vqjza10T.mjs.map
|