@tailor-platform/sdk 1.78.0 → 1.80.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/{application-CUxVA7Fs.mjs → application-C1d52JP9.mjs} +290 -224
  3. package/dist/application-C1d52JP9.mjs.map +1 -0
  4. package/dist/application-Nlh9BHQf.mjs +3 -0
  5. package/dist/cli/commands/tailordb/migrate/bundler.d.mts +3 -2
  6. package/dist/cli/index.mjs +27 -53
  7. package/dist/cli/index.mjs.map +1 -1
  8. package/dist/cli/lib.mjs +3 -6
  9. package/dist/cli/lib.mjs.map +1 -1
  10. package/dist/cli/tsconfig-paths-hook.d.mts +1 -0
  11. package/dist/cli/tsconfig-paths-hook.mjs +153 -0
  12. package/dist/completion/zsh-worker.zsh +1 -1
  13. package/dist/configure/config/types.d.mts +5 -1
  14. package/dist/configure/index.mjs +7 -6
  15. package/dist/configure/index.mjs.map +1 -1
  16. package/dist/configure/services/auth/types.d.mts +18 -23
  17. package/dist/configure/services/tailordb/schema.d.mts +1 -7
  18. package/dist/configure/services/workflow/execution-policy.d.mts +2 -2
  19. package/dist/configure/types/type.d.mts +1 -9
  20. package/dist/{globals-CvizbGLY.mjs → globals-B-n_3uYu.mjs} +11 -5
  21. package/dist/globals-B-n_3uYu.mjs.map +1 -0
  22. package/dist/{runtime-BD2vYJFT.mjs → register-typescript-runtime-Bd4bcLbW.mjs} +399 -124
  23. package/dist/register-typescript-runtime-Bd4bcLbW.mjs.map +1 -0
  24. package/dist/{registry-CYBRvfaU.mjs → registry-CXi7rJq7.mjs} +3 -2
  25. package/dist/registry-CXi7rJq7.mjs.map +1 -0
  26. package/dist/runtime/field-parse.d.mts +11 -0
  27. package/dist/runtime/globals.d.mts +4 -1
  28. package/dist/runtime/index.mjs +1 -1
  29. package/dist/runtime/workflow.d.mts +79 -15
  30. package/dist/runtime/workflow.mjs +2 -2
  31. package/dist/{schema-U6DxoZ8D.mjs → schema-CYrle8JZ.mjs} +42 -24
  32. package/dist/schema-CYrle8JZ.mjs.map +1 -0
  33. package/dist/{service-D12iQGcS.mjs → service-CDPatibu.mjs} +31 -17
  34. package/dist/service-CDPatibu.mjs.map +1 -0
  35. package/dist/service-Cg7Qibit.mjs +3 -0
  36. package/dist/vitest/environment.mjs +1 -1
  37. package/dist/vitest/index.mjs +36 -10
  38. package/dist/vitest/index.mjs.map +1 -1
  39. package/dist/vitest/mocks/workflow.d.mts +29 -15
  40. package/dist/vitest/setup.mjs +1 -1
  41. package/dist/workflow-CkIDJpdg.mjs +69 -0
  42. package/dist/workflow-CkIDJpdg.mjs.map +1 -0
  43. package/docs/cli/application.md +6 -0
  44. package/docs/cli-reference.md +21 -21
  45. package/docs/configuration.md +2 -0
  46. package/docs/runtime.md +2 -2
  47. package/docs/services/auth.md +2 -2
  48. package/docs/services/tailordb.md +2 -0
  49. package/docs/services/workflow.md +2 -2
  50. package/docs/testing.md +2 -2
  51. package/package.json +7 -6
  52. package/dist/application-CUxVA7Fs.mjs.map +0 -1
  53. package/dist/application-Dp_-ioiP.mjs +0 -3
  54. package/dist/configure/types/field-runtime.d.mts +0 -17
  55. package/dist/globals-CvizbGLY.mjs.map +0 -1
  56. package/dist/registry-CYBRvfaU.mjs.map +0 -1
  57. package/dist/runtime-BD2vYJFT.mjs.map +0 -1
  58. package/dist/schema-U6DxoZ8D.mjs.map +0 -1
  59. package/dist/service-CghpdV-9.mjs +0 -3
  60. package/dist/service-D12iQGcS.mjs.map +0 -1
  61. package/dist/workflow-DSwnYPPP.mjs +0 -45
  62. package/dist/workflow-DSwnYPPP.mjs.map +0 -1
@@ -1,9 +1,9 @@
1
- import { t as db } from "./schema-U6DxoZ8D.mjs";
1
+ import { t as db } from "./schema-CYrle8JZ.mjs";
2
2
  import { $ as CreateAuthIDPConfigRequestSchema, A as CreatePipelineResolverRequestSchema, At as TenantProviderConfig_TenantProviderType, B as IdPPermissionOperator, Bt as CreateAIGatewayRequestSchema, C as UpdateStaticWebsiteRequestSchema, Ct as AuthOAuth2Client_ClientType, D as CreateSecretManagerVaultRequestSchema, Dt as AuthSCIMAttribute_Uniqueness, E as CreateSecretManagerSecretRequestSchema, Et as AuthSCIMAttribute_Type, F as PipelineResolver_OperationType, Ft as GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus, G as CreateExecutorExecutorRequestSchema, Gt as ConditionSchema, H as FunctionExecution_Status, I as CreateIdPServiceRequestSchema, It as UpdateApplicationRequestSchema, J as ExecutorJobStatus, Jt as PageDirection, K as UpdateExecutorExecutorRequestSchema, Kt as Condition_Operator, L as UpdateIdPServiceRequestSchema, M as UpdatePipelineResolverRequestSchema, N as UpdatePipelineServiceRequestSchema, O as UpdateSecretManagerSecretRequestSchema, Ot as AuthSCIMConfig_AuthorizationType, Pt as CreateApplicationRequestSchema, Q as CreateAuthHookRequestSchema, Rt as ApplicationSchemaUpdateAttemptStatus, S as CreateStaticWebsiteRequestSchema, St as AuthInvokerSchema, Tt as AuthSCIMAttribute_Mutability, V as IdPPermissionPermit, Vt as UpdateAIGatewayRequestSchema, X as ExecutorTriggerType, Y as ExecutorTargetType, Z as CreateAuthConnectionRequestSchema, _ as TailorDBGQLPermission_Permit, a as CreateWorkflowRequestSchema, at as CreateTenantConfigRequestSchema, b as TailorDBType_PermitAction, bt as AuthHookPoint, ct as UpdateAuthHookRequestSchema, d as CreateTailorDBServiceRequestSchema, dt as UpdateAuthOAuth2ClientRequestSchema, et as CreateAuthMachineUserRequestSchema, f as CreateTailorDBTypeRequestSchema, ft as UpdateAuthSCIMConfigRequestSchema, g as TailorDBGQLPermission_Operator, gt as UpdateUserProfileConfigRequestSchema, h as TailorDBGQLPermission_Action, ht as UpdateTenantConfigRequestSchema, i as CreateWorkflowJobFunctionRequestSchema, it as CreateAuthServiceRequestSchema, j as CreatePipelineServiceRequestSchema, jt as UserProfileProviderConfig_UserProfileProviderType, l as WorkflowExecution_Status, lt as UpdateAuthIDPConfigRequestSchema, mt as UpdateAuthServiceRequestSchema, nt as CreateAuthSCIMConfigRequestSchema, o as UpdateWorkflowJobFunctionExecutionPolicyRequestSchema, ot as CreateUserProfileConfigRequestSchema, p as UpdateTailorDBTypeRequestSchema, pt as UpdateAuthSCIMResourceRequestSchema, qt as FilterSchema, r as CreateWorkflowJobFunctionExecutionPolicyRequestSchema, rt as CreateAuthSCIMResourceRequestSchema, s as UpdateWorkflowRequestSchema, st as UpdateAuthConnectionRequestSchema, t as WorkspacePlatformUserRole, tt as CreateAuthOAuth2ClientRequestSchema, u as WorkflowJobExecution_Status, ut as UpdateAuthMachineUserRequestSchema, v as TailorDBType_Permission_Operator, vt as AuthConnection_Status, wt as AuthOAuth2Client_GrantType, x as AddCustomDomainRequestSchema, xt as AuthIDPConfig_AuthType, y as TailorDBType_Permission_Permit, yt as AuthConnection_Type, z as IdPLang, zt as Subgraph_ServiceType } from "./workspace_resource_pb-Db3fv68L.mjs";
3
3
  import { t as assertDefined } from "./assert-DBxo8jPo.mjs";
4
4
  import { a as parseBoolean, i as symbols, n as logger, r as styles, t as CIPromptError } from "./logger-BwS4ppwO.mjs";
5
- import { A as fetchAllTolerant, B as initOperatorClient, C as createBundleCache, E as hashFile, F as getConsoleBaseUrl, G as byName, H as normalizeBaseUrl, I as getOAuth2ClientId, K as LOG_LEVELS, L as getOrNull, M as fetchPaged, O as defaultPlatformBaseUrl, R as getPlatformBaseUrl, S as hasGenerationHooks, T as hashContent, U as rememberPlatformConfigForToken, V as isDefaultPlatform, W as resolveStaticWebsiteUrls, _ as platformBundleDefinePlugin, d as buildExecutorArgsExpr, f as buildResolverOperationHookExpr, g as stringifyFunction, h as TailorDBTypeSchema, i as resolverBundleKey, j as fetchMachineUserToken, k as fetchAll, l as HTTP_METHODS, m as assertUniqueTailorDBTypeNamesWithExternal, n as generatePluginFilesIfNeeded, o as WorkflowJobFunctionExecutionPolicySchema, p as assertUniqueLocalTailorDBTypeNames, r as loadApplication, t as defineApplication, w as getDistDir, x as getPluginGenerationDependencies, z as initOAuth2Client } from "./application-CUxVA7Fs.mjs";
6
- import { o as loadFilesWithIgnores, s as functionSchema, t as createExecutorService } from "./service-D12iQGcS.mjs";
5
+ import { A as fetchAll, B as initOAuth2Client, C as hasGenerationHooks, D as hashFile, E as hashContent, G as resolveStaticWebsiteUrls, H as isDefaultPlatform, I as getConsoleBaseUrl, J as LOG_LEVELS, K as byName, L as getOAuth2ClientId, M as fetchMachineUserToken, N as fetchPaged, R as getOrNull, S as getPluginGenerationDependencies, T as getDistDir, U as normalizeBaseUrl, V as initOperatorClient, W as rememberPlatformConfigForToken, _ as resolveTSConfigWithFallback, d as buildExecutorArgsExpr, f as buildResolverOperationHookExpr, g as stringifyFunction, h as TailorDBTypeSchema, i as resolverBundleKey, j as fetchAllTolerant, k as defaultPlatformBaseUrl, l as HTTP_METHODS, m as assertUniqueTailorDBTypeNamesWithExternal, n as generatePluginFilesIfNeeded, o as WorkflowJobFunctionExecutionPolicySchema, p as assertUniqueLocalTailorDBTypeNames, q as createApplyLimiter, r as loadApplication, t as defineApplication, v as platformBundleDefinePlugin, w as createBundleCache, z as getPlatformBaseUrl } from "./application-C1d52JP9.mjs";
6
+ import { o as loadFilesWithIgnores, s as functionSchema, t as createExecutorService } from "./service-CDPatibu.mjs";
7
7
  import { n as enumConstantsPlugin, t as EnumConstantsGeneratorID } from "./enum-constants-j9QBF0cB.mjs";
8
8
  import { t as multiline } from "./multiline-sfHpTZZK.mjs";
9
9
  import { n as fileUtilsPlugin, t as FileUtilsGeneratorID } from "./file-utils-DcyIPFQh.mjs";
@@ -14,11 +14,12 @@ import { t as userAgent } from "./user-agent-DX2Jnw0-.mjs";
14
14
  import { r as isCLIError, t as createCLIError } from "./errors-DVFS0AZk.mjs";
15
15
  import { n as tightenSecretFilePermissions, r as writeSecretFile } from "./secret-file-DBqZhjFQ.mjs";
16
16
  import { r as withSpan } from "./telemetry-CdqJEzkj.mjs";
17
+ import * as mod from "node:module";
17
18
  import { arg, createDefineCommand, defineCommand, runCommand } from "politty";
18
19
  import { z } from "zod";
19
20
  import { create, fromJson, toJson } from "@bufbuild/protobuf";
20
21
  import * as fs$1 from "node:fs";
21
- import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
22
+ import { mkdirSync, readFileSync, renameSync, rmSync, statSync, utimesSync, writeFileSync } from "node:fs";
22
23
  import { parseEnv } from "node:util";
23
24
  import { ValueSchema, timestampDate } from "@bufbuild/protobuf/wkt";
24
25
  import * as path from "pathe";
@@ -34,17 +35,16 @@ import { lt } from "semver";
34
35
  import { xdgConfig } from "xdg-basedir";
35
36
  import { Code, ConnectError } from "@connectrpc/connect";
36
37
  import pLimit from "p-limit";
37
- import { resolveTSConfig } from "pkg-types";
38
38
  import * as crypto$1 from "node:crypto";
39
39
  import { createHash, randomUUID } from "node:crypto";
40
40
  import { ExitPromptError } from "@inquirer/core";
41
41
  import { confirm, input, password, select } from "@inquirer/prompts";
42
42
  import { isCI } from "std-env";
43
43
  import * as rolldown from "rolldown";
44
- import * as fs from "node:fs/promises";
45
- import { glob, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
46
44
  import { parseSync } from "oxc-parser";
47
45
  import * as inflection from "inflection";
46
+ import * as fs from "node:fs/promises";
47
+ import { glob, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
48
48
  import { pathToString } from "@bufbuild/protobuf/reflect";
49
49
  import { createValidator } from "@bufbuild/protovalidate";
50
50
  import { setTimeout as setTimeout$1 } from "timers/promises";
@@ -1444,6 +1444,54 @@ function createCacheManager(options) {
1444
1444
  };
1445
1445
  }
1446
1446
 
1447
+ //#endregion
1448
+ //#region src/cli/services/stale-cleanup.ts
1449
+ const legacyBundleDirectories = [
1450
+ {
1451
+ name: "resolvers",
1452
+ suffixes: [".entry.js"]
1453
+ },
1454
+ {
1455
+ name: "executors",
1456
+ suffixes: [".entry.js"]
1457
+ },
1458
+ {
1459
+ name: "workflow-jobs",
1460
+ suffixes: [".js", ".js.map"]
1461
+ },
1462
+ {
1463
+ name: "auth-hooks",
1464
+ suffixes: [".entry.js"]
1465
+ },
1466
+ {
1467
+ name: "http-adapters",
1468
+ suffixes: [".entry.js"]
1469
+ }
1470
+ ];
1471
+ /**
1472
+ * Remove bundle artifacts created by SDK versions that used disk-backed entries.
1473
+ *
1474
+ * Concurrent callers are safe because current bundlers no longer create files
1475
+ * in these directories and each removal uses `force: true`.
1476
+ * @param outputRoot - SDK output directory
1477
+ */
1478
+ async function removeLegacyBundleFiles(outputRoot) {
1479
+ await Promise.all([...legacyBundleDirectories.map(({ name, suffixes }) => removeMatchingFiles(path.join(outputRoot, name), suffixes)), fs.rm(path.join(outputRoot, "hooks-validate-scripts"), {
1480
+ recursive: true,
1481
+ force: true
1482
+ })]);
1483
+ }
1484
+ async function removeMatchingFiles(outputDir, suffixes) {
1485
+ let files;
1486
+ try {
1487
+ files = await fs.readdir(outputDir);
1488
+ } catch (error) {
1489
+ if (error.code === "ENOENT") return;
1490
+ throw error;
1491
+ }
1492
+ for (const file of files) if (suffixes.some((suffix) => file.endsWith(suffix))) await fs.rm(path.join(outputDir, file), { force: true });
1493
+ }
1494
+
1447
1495
  //#endregion
1448
1496
  //#region src/cli/shared/type-generator.ts
1449
1497
  /**
@@ -1467,7 +1515,7 @@ function extractAttributesFromConfig(config) {
1467
1515
  * @returns Generated type definition source
1468
1516
  */
1469
1517
  function generateTypeDefinition(attributeMap, attributeList, env, machineUserNames, idpNames, connectionNames, aiGatewayNames) {
1470
- const mapFields = attributeMap ? Object.entries(attributeMap).map(([key, value]) => ` ${key}: ${value};`).join("\n") : "";
1518
+ const mapFields = attributeMap ? Object.entries(attributeMap).map(([key, { type, optional }]) => ` ${key}${optional ? "?" : ""}: ${type};`).join("\n") : "";
1471
1519
  const mapBody = !attributeMap || Object.keys(attributeMap).length === 0 ? "{}" : `{
1472
1520
  ${mapFields}
1473
1521
  }`;
@@ -1530,12 +1578,15 @@ function collectAttributesFromConfig(config) {
1530
1578
  const inferAttributeType = (field) => {
1531
1579
  const type = field?.type;
1532
1580
  const metadata = field?.metadata;
1533
- if (!metadata) return "string";
1581
+ if (!metadata) return { type: "string" };
1534
1582
  let typeStr = "string";
1535
1583
  if (type === "boolean") typeStr = "boolean";
1536
1584
  else if (type === "enum" && metadata.allowedValues) typeStr = metadata.allowedValues.map((v) => `"${v.value}"`).join(" | ");
1537
1585
  if (metadata.array) typeStr += "[]";
1538
- return typeStr;
1586
+ return {
1587
+ type: typeStr,
1588
+ optional: metadata.required === false
1589
+ };
1539
1590
  };
1540
1591
  if ("userProfile" in auth) {
1541
1592
  const userProfile = auth.userProfile;
@@ -2850,12 +2901,16 @@ function protoSubgraph(subgraph) {
2850
2901
 
2851
2902
  //#endregion
2852
2903
  //#region src/cli/commands/deploy/secrets-state.ts
2904
+ const SecretsStateEntrySchema = z.object({
2905
+ hash: z.string(),
2906
+ updateTime: z.string().optional()
2907
+ });
2853
2908
  const SecretsStateSchema = z.object({
2854
- vaults: z.record(z.string(), z.record(z.string(), z.string())),
2909
+ vaults: z.record(z.string(), z.record(z.string(), SecretsStateEntrySchema)),
2855
2910
  connections: z.record(z.string(), z.string()).optional()
2856
2911
  });
2857
2912
  const PersistedSecretsStateSchema = z.object({
2858
- version: z.literal(1),
2913
+ version: z.literal(2),
2859
2914
  workspaceId: z.string(),
2860
2915
  applicationKey: z.string(),
2861
2916
  state: SecretsStateSchema
@@ -2901,12 +2956,14 @@ function saveSecretsState(scope, state) {
2901
2956
  if (!scope.applicationId) return;
2902
2957
  const filePath = getSecretsStatePath(scope);
2903
2958
  mkdirSync(path.dirname(filePath), { recursive: true });
2904
- writeFileSync(filePath, JSON.stringify({
2905
- version: 1,
2959
+ const tempPath = `${filePath}.tmp-${randomUUID()}`;
2960
+ writeFileSync(tempPath, JSON.stringify({
2961
+ version: 2,
2906
2962
  workspaceId: scope.workspaceId,
2907
2963
  applicationKey: applicationStateKey(scope),
2908
2964
  state
2909
2965
  }, null, 2), "utf-8");
2966
+ renameSync(tempPath, filePath);
2910
2967
  }
2911
2968
  /**
2912
2969
  * Compute SHA-256 hex digest of a value.
@@ -2916,6 +2973,133 @@ function saveSecretsState(scope, state) {
2916
2973
  function hashValue(value) {
2917
2974
  return createHash("sha256").update(value).digest("hex");
2918
2975
  }
2976
+ /**
2977
+ * Serialize a platform timestamp into the string stored as update evidence.
2978
+ * @param updateTime - Timestamp from a Secret Manager list or mutation response
2979
+ * @returns Serialized timestamp, or undefined when the platform sent none
2980
+ */
2981
+ function serializeUpdateTime(updateTime) {
2982
+ return updateTime === void 0 ? void 0 : `${updateTime.seconds}.${updateTime.nanos}`;
2983
+ }
2984
+ const LOCK_POLL_INTERVAL_MS = 100;
2985
+ const LOCK_ACQUIRE_TIMEOUT_MS = 300 * 1e3;
2986
+ const LOCK_HEARTBEAT_INTERVAL_MS = 10 * 1e3;
2987
+ const LOCK_LEASE_MS = 60 * 1e3;
2988
+ const lockQueues = /* @__PURE__ */ new Map();
2989
+ /**
2990
+ * Run a remote-update/state-save sequence exclusively for one target's secrets state.
2991
+ *
2992
+ * Serializes concurrent deploys to the same workspace and application (across
2993
+ * processes sharing the same output directory) so the persisted hash state
2994
+ * always reflects the last remote write.
2995
+ * @param scope - Workspace and application identity for the deployment
2996
+ * @param fn - Critical section performing remote updates and the state save
2997
+ * @returns The value returned by fn
2998
+ */
2999
+ async function withSecretsStateLock(scope, fn) {
3000
+ if (!scope.applicationId) return fn();
3001
+ const lockPath = `${getSecretsStatePath(scope)}.lock`;
3002
+ let queue = lockQueues.get(lockPath);
3003
+ if (!queue) {
3004
+ queue = pLimit(1);
3005
+ lockQueues.set(lockPath, queue);
3006
+ }
3007
+ return queue(async () => {
3008
+ const token = await acquireFileLock(lockPath);
3009
+ const heartbeat = setInterval(() => refreshLock(lockPath, token), LOCK_HEARTBEAT_INTERVAL_MS);
3010
+ heartbeat.unref();
3011
+ try {
3012
+ return await fn();
3013
+ } finally {
3014
+ clearInterval(heartbeat);
3015
+ releaseFileLock(lockPath, token);
3016
+ }
3017
+ });
3018
+ }
3019
+ async function acquireFileLock(lockPath) {
3020
+ mkdirSync(path.dirname(lockPath), { recursive: true });
3021
+ const token = randomUUID();
3022
+ const deadline = Date.now() + LOCK_ACQUIRE_TIMEOUT_MS;
3023
+ for (;;) {
3024
+ let created = true;
3025
+ try {
3026
+ mkdirSync(lockPath);
3027
+ } catch (error) {
3028
+ if (error.code !== "EEXIST") throw error;
3029
+ created = false;
3030
+ }
3031
+ if (created) {
3032
+ try {
3033
+ writeFileSync(path.join(lockPath, "owner.json"), JSON.stringify({
3034
+ pid: process.pid,
3035
+ token
3036
+ }));
3037
+ } catch (error) {
3038
+ rmSync(lockPath, {
3039
+ recursive: true,
3040
+ force: true
3041
+ });
3042
+ throw error;
3043
+ }
3044
+ return token;
3045
+ }
3046
+ if (isLockExpired(lockPath) && stealLock(lockPath)) continue;
3047
+ if (Date.now() >= deadline) throw new Error("Timed out waiting for another deploy to the same workspace and application to finish. Wait for it to complete and retry; an interrupted deploy recovers automatically within a minute.");
3048
+ await new Promise((resolve) => setTimeout(resolve, LOCK_POLL_INTERVAL_MS));
3049
+ }
3050
+ }
3051
+ function isLockExpired(lockPath) {
3052
+ try {
3053
+ return Date.now() - statSync(lockPath).mtimeMs > LOCK_LEASE_MS;
3054
+ } catch {
3055
+ return false;
3056
+ }
3057
+ }
3058
+ function readLockToken(lockPath) {
3059
+ try {
3060
+ return JSON.parse(readFileSync(path.join(lockPath, "owner.json"), "utf-8")).token;
3061
+ } catch {
3062
+ return;
3063
+ }
3064
+ }
3065
+ function refreshLock(lockPath, token) {
3066
+ if (readLockToken(lockPath) !== token) return;
3067
+ const now = /* @__PURE__ */ new Date();
3068
+ try {
3069
+ utimesSync(lockPath, now, now);
3070
+ } catch {}
3071
+ }
3072
+ function releaseFileLock(lockPath, token) {
3073
+ if (readLockToken(lockPath) !== token) return;
3074
+ rmSync(lockPath, {
3075
+ recursive: true,
3076
+ force: true
3077
+ });
3078
+ }
3079
+ function stealLock(lockPath) {
3080
+ const trash = `${lockPath}.stale-${process.pid}-${Date.now()}`;
3081
+ try {
3082
+ renameSync(lockPath, trash);
3083
+ } catch {
3084
+ return false;
3085
+ }
3086
+ if (isLockExpired(trash)) {
3087
+ rmSync(trash, {
3088
+ recursive: true,
3089
+ force: true
3090
+ });
3091
+ return true;
3092
+ }
3093
+ try {
3094
+ renameSync(trash, lockPath);
3095
+ } catch {
3096
+ rmSync(trash, {
3097
+ recursive: true,
3098
+ force: true
3099
+ });
3100
+ }
3101
+ return false;
3102
+ }
2919
3103
 
2920
3104
  //#endregion
2921
3105
  //#region src/cli/commands/deploy/auth-connection.ts
@@ -3074,44 +3258,44 @@ async function planAuthConnections(client, workspaceId, appName, appId, auths) {
3074
3258
  async function applyAuthConnections(client, result, phase) {
3075
3259
  const { changeSet, stateScope } = result;
3076
3260
  if (phase === "create-update") {
3077
- await Promise.all(changeSet.creates.map(async (create) => {
3078
- await client.createAuthConnection(create.request);
3079
- await client.setMetadata(create.metaRequest);
3080
- logger.info(`Connection "${create.name}" was created. Authorize it with:\n tailor-sdk authconnection authorize --name ${create.name}\nOr via the Console: tailor-sdk authconnection open`);
3081
- }));
3082
- for (const replace of changeSet.replaces) {
3083
- if ((await client.updateAuthConnection(replace.updateRequest)).connection?.status === AuthConnection_Status.UNAUTHORIZED) logger.warn(`Connection "${replace.name}" requires re-authorization. Authorize with:\n tailor-sdk authconnection authorize --name ${replace.name}\nOr via the Console: tailor-sdk authconnection open`);
3084
- await client.setMetadata(replace.metaRequest);
3085
- }
3261
+ if (changeSet.creates.length > 0 || changeSet.replaces.length > 0) await withSecretsStateLock(stateScope, async () => {
3262
+ await Promise.all(changeSet.creates.map(async (create) => {
3263
+ await client.createAuthConnection(create.request);
3264
+ await client.setMetadata(create.metaRequest);
3265
+ logger.info(`Connection "${create.name}" was created. Authorize it with:\n tailor-sdk authconnection authorize --name ${create.name}\nOr via the Console: tailor-sdk authconnection open`);
3266
+ }));
3267
+ for (const replace of changeSet.replaces) {
3268
+ if ((await client.updateAuthConnection(replace.updateRequest)).connection?.status === AuthConnection_Status.UNAUTHORIZED) logger.warn(`Connection "${replace.name}" requires re-authorization. Authorize with:\n tailor-sdk authconnection authorize --name ${replace.name}\nOr via the Console: tailor-sdk authconnection open`);
3269
+ await client.setMetadata(replace.metaRequest);
3270
+ }
3271
+ const secretReplaces = changeSet.replaces.filter((replace) => replace.updateRequest.updateMask?.paths?.includes("oauth2.client_secret"));
3272
+ if (changeSet.creates.length > 0 || secretReplaces.length > 0) {
3273
+ const state = loadSecretsState(stateScope);
3274
+ if (!state.connections) state.connections = {};
3275
+ for (const create of changeSet.creates) {
3276
+ const conn = create.request.connection;
3277
+ if (conn?.config?.case === "oauth2") state.connections[create.name] = hashValue(conn.config.value.clientSecret ?? "");
3278
+ }
3279
+ for (const replace of secretReplaces) {
3280
+ const conn = replace.updateRequest.connection;
3281
+ if (conn?.config?.case === "oauth2") state.connections[replace.name] = hashValue(conn.config.value.clientSecret ?? "");
3282
+ }
3283
+ saveSecretsState(stateScope, state);
3284
+ }
3285
+ });
3086
3286
  await Promise.all(changeSet.updates.map(async (update) => {
3087
3287
  await client.setMetadata(update.metaRequest);
3088
3288
  }));
3089
- const secretReplaces = changeSet.replaces.filter((replace) => replace.updateRequest.updateMask?.paths?.includes("oauth2.client_secret"));
3090
- if (changeSet.creates.length > 0 || secretReplaces.length > 0) {
3091
- const state = loadSecretsState(stateScope);
3092
- if (!state.connections) state.connections = {};
3093
- for (const create of changeSet.creates) {
3094
- const conn = create.request.connection;
3095
- if (conn?.config?.case === "oauth2") state.connections[create.name] = hashValue(conn.config.value.clientSecret ?? "");
3096
- }
3097
- for (const replace of secretReplaces) {
3098
- const conn = replace.updateRequest.connection;
3099
- if (conn?.config?.case === "oauth2") state.connections[replace.name] = hashValue(conn.config.value.clientSecret ?? "");
3100
- }
3101
- saveSecretsState(stateScope, state);
3102
- }
3103
- } else {
3289
+ } else if (changeSet.deletes.length > 0) await withSecretsStateLock(stateScope, async () => {
3104
3290
  await Promise.all(changeSet.deletes.map(async (del) => {
3105
3291
  await client.deleteAuthConnection(del.request);
3106
3292
  }));
3107
- if (changeSet.deletes.length > 0) {
3108
- const state = loadSecretsState(stateScope);
3109
- if (state.connections) {
3110
- for (const del of changeSet.deletes) delete state.connections[del.name];
3111
- saveSecretsState(stateScope, state);
3112
- }
3293
+ const state = loadSecretsState(stateScope);
3294
+ if (state.connections) {
3295
+ for (const del of changeSet.deletes) delete state.connections[del.name];
3296
+ saveSecretsState(stateScope, state);
3113
3297
  }
3114
- }
3298
+ });
3115
3299
  }
3116
3300
 
3117
3301
  //#endregion
@@ -3424,14 +3608,14 @@ async function uploadFunctionScript(client, workspaceId, entry, isCreate) {
3424
3608
  async function applyFunctionRegistry(client, workspaceId, result, phase = "create-update") {
3425
3609
  const { changeSet } = result;
3426
3610
  if (phase === "create-update") {
3427
- for (const create of changeSet.creates) {
3611
+ const limitFunction = createApplyLimiter();
3612
+ await Promise.all([...changeSet.creates.map((create) => limitFunction(async () => {
3428
3613
  await uploadFunctionScript(client, workspaceId, create.entry, true);
3429
3614
  await client.setMetadata(create.metaRequest);
3430
- }
3431
- for (const update of changeSet.updates) {
3615
+ })), ...changeSet.updates.map((update) => limitFunction(async () => {
3432
3616
  await uploadFunctionScript(client, workspaceId, update.entry, false);
3433
3617
  await client.setMetadata(update.metaRequest);
3434
- }
3618
+ }))]);
3435
3619
  } else await Promise.all(changeSet.deletes.map((del) => client.deleteFunctionRegistry({
3436
3620
  workspaceId: del.workspaceId,
3437
3621
  name: del.name
@@ -6276,17 +6460,20 @@ async function planSecretManager(context) {
6276
6460
  name: vaultName,
6277
6461
  workspaceId
6278
6462
  });
6279
- let existingSecrets = [];
6280
- if (existing) existingSecrets = (await fetchAllTolerant(async (pageToken, maxPageSize) => {
6281
- const { secrets, nextPageToken } = await client.listSecretManagerSecrets({
6282
- workspaceId,
6283
- secretmanagerVaultName: vaultName,
6284
- pageToken,
6285
- pageSize: maxPageSize
6463
+ const existingSecretTimes = /* @__PURE__ */ new Map();
6464
+ if (existing) {
6465
+ const secrets = await fetchAllTolerant(async (pageToken, maxPageSize) => {
6466
+ const { secrets, nextPageToken } = await client.listSecretManagerSecrets({
6467
+ workspaceId,
6468
+ secretmanagerVaultName: vaultName,
6469
+ pageToken,
6470
+ pageSize: maxPageSize
6471
+ });
6472
+ return [secrets, nextPageToken];
6286
6473
  });
6287
- return [secrets, nextPageToken];
6288
- })).map((s) => s.name);
6289
- const existingSet = new Set(existingSecrets);
6474
+ for (const secret of secrets) existingSecretTimes.set(secret.name, serializeUpdateTime(secret.updateTime));
6475
+ }
6476
+ const existingSet = new Set(existingSecretTimes.keys());
6290
6477
  for (const secret of vault.secrets) {
6291
6478
  if (secret.value == null) {
6292
6479
  existingSet.delete(secret.name);
@@ -6294,9 +6481,10 @@ async function planSecretManager(context) {
6294
6481
  continue;
6295
6482
  }
6296
6483
  if (existingSet.has(secret.name)) {
6297
- const currentHash = hashValue(secret.value);
6298
- const storedHash = state.vaults[vaultName]?.[secret.name];
6299
- if (forceApplyAll || currentHash !== storedHash) secretChangeSet.updates.push({
6484
+ const stored = state.vaults[vaultName]?.[secret.name];
6485
+ const remoteUpdateTime = existingSecretTimes.get(secret.name);
6486
+ const unchanged = stored !== void 0 && stored.hash === hashValue(secret.value) && stored.updateTime !== void 0 && stored.updateTime === remoteUpdateTime;
6487
+ if (forceApplyAll || !unchanged) secretChangeSet.updates.push({
6300
6488
  name: `${vaultName}/${secret.name}`,
6301
6489
  secretName: secret.name,
6302
6490
  workspaceId,
@@ -6389,18 +6577,31 @@ async function applySecretManager(client, result, phase = "create-update", appli
6389
6577
  });
6390
6578
  await client.setMetadata(metaRequest);
6391
6579
  }));
6392
- await Promise.all(secretChangeSet.creates.map((create) => client.createSecretManagerSecret(secretCreateRequest(create))));
6393
- await Promise.all(secretChangeSet.updates.map((update) => client.updateSecretManagerSecret(secretUpdateRequest(update))));
6394
6580
  const secretHashUpdates = [...secretChangeSet.creates, ...secretChangeSet.updates];
6395
- if (application && secretHashUpdates.length > 0) {
6396
- const state = loadSecretsState(stateScope);
6397
- for (const secret of secretHashUpdates) {
6398
- if (!Object.hasOwn(state.vaults, secret.vaultName)) state.vaults[secret.vaultName] = {};
6399
- assertDefined(state.vaults[secret.vaultName], "vault state entry missing")[secret.secretName] = hashValue(secret.value);
6581
+ if (secretHashUpdates.length > 0) await withSecretsStateLock(stateScope, async () => {
6582
+ const appliedUpdateTimes = /* @__PURE__ */ new Map();
6583
+ await Promise.all(secretChangeSet.creates.map(async (create) => {
6584
+ const response = await client.createSecretManagerSecret(secretCreateRequest(create));
6585
+ appliedUpdateTimes.set(create.name, serializeUpdateTime(response.secret?.updateTime));
6586
+ }));
6587
+ await Promise.all(secretChangeSet.updates.map(async (update) => {
6588
+ const response = await client.updateSecretManagerSecret(secretUpdateRequest(update));
6589
+ appliedUpdateTimes.set(update.name, serializeUpdateTime(response.secret?.updateTime));
6590
+ }));
6591
+ if (application) {
6592
+ const state = loadSecretsState(stateScope);
6593
+ for (const secret of secretHashUpdates) {
6594
+ if (!Object.hasOwn(state.vaults, secret.vaultName)) state.vaults[secret.vaultName] = {};
6595
+ const updateTime = appliedUpdateTimes.get(secret.name);
6596
+ assertDefined(state.vaults[secret.vaultName], "vault state entry missing")[secret.secretName] = {
6597
+ hash: hashValue(secret.value),
6598
+ ...updateTime === void 0 ? {} : { updateTime }
6599
+ };
6600
+ }
6601
+ saveSecretsState(stateScope, state);
6400
6602
  }
6401
- saveSecretsState(stateScope, state);
6402
- }
6403
- } else {
6603
+ });
6604
+ } else if (secretChangeSet.deletes.length > 0 || vaultChangeSet.deletes.length > 0) await withSecretsStateLock(stateScope, async () => {
6404
6605
  await Promise.all(secretChangeSet.deletes.map((del) => client.deleteSecretManagerSecret({
6405
6606
  workspaceId: del.workspaceId,
6406
6607
  secretmanagerVaultName: del.vaultName,
@@ -6410,16 +6611,14 @@ async function applySecretManager(client, result, phase = "create-update", appli
6410
6611
  workspaceId: del.workspaceId,
6411
6612
  secretmanagerVaultName: del.name
6412
6613
  })));
6413
- if (secretChangeSet.deletes.length > 0 || vaultChangeSet.deletes.length > 0) {
6414
- const state = loadSecretsState(stateScope);
6415
- for (const del of secretChangeSet.deletes) if (Object.hasOwn(state.vaults, del.vaultName)) {
6416
- delete assertDefined(state.vaults[del.vaultName], "vault state entry missing")[del.secretName];
6417
- if (Object.keys(assertDefined(state.vaults[del.vaultName], "vault state entry missing")).length === 0) delete state.vaults[del.vaultName];
6418
- }
6419
- for (const del of vaultChangeSet.deletes) delete state.vaults[del.name];
6420
- saveSecretsState(stateScope, state);
6614
+ const state = loadSecretsState(stateScope);
6615
+ for (const del of secretChangeSet.deletes) if (Object.hasOwn(state.vaults, del.vaultName)) {
6616
+ delete assertDefined(state.vaults[del.vaultName], "vault state entry missing")[del.secretName];
6617
+ if (Object.keys(assertDefined(state.vaults[del.vaultName], "vault state entry missing")).length === 0) delete state.vaults[del.vaultName];
6421
6618
  }
6422
- }
6619
+ for (const del of vaultChangeSet.deletes) delete state.vaults[del.name];
6620
+ saveSecretsState(stateScope, state);
6621
+ });
6423
6622
  }
6424
6623
 
6425
6624
  //#endregion
@@ -9248,19 +9447,21 @@ function handleOptionalToRequiredError(error, messages) {
9248
9447
  * 1. Imports the migration script's main function
9249
9448
  * 2. Defines getDB() function inline
9250
9449
  * 3. Wraps migration in a transaction using getDB()
9251
- * 4. Exports as main() for TestExecScript
9450
+ * 4. Exports as main() for server-side execution
9252
9451
  * @param {string} sourceFile - Path to the migration script file
9253
9452
  * @param {string} namespace - TailorDB namespace
9254
9453
  * @param {number} migrationNumber - Migration number
9255
9454
  * @param {Record<string, string | number | boolean>} env - Environment variables to inject into the migration context
9455
+ * @param {string} [baseDir] - Directory to resolve the bundler's tsconfig against; defaults to the migration script's directory
9256
9456
  * @returns {Promise<MigrationBundleResult>} Bundled migration result
9257
9457
  */
9258
- async function bundleMigrationScript(sourceFile, namespace, migrationNumber, env = {}) {
9458
+ async function bundleMigrationScript(sourceFile, namespace, migrationNumber, env = {}, baseDir) {
9259
9459
  const outputDir = path.resolve(getDistDir(), "migrations");
9260
9460
  fs$1.mkdirSync(outputDir, { recursive: true });
9261
9461
  const entryPath = path.join(outputDir, `migration_${namespace}_${migrationNumber}.entry.js`);
9462
+ const absoluteSourcePath = path.resolve(sourceFile).replace(/\\/g, "/");
9262
9463
  const entryContent = multiline`
9263
- import { main as _migrationMain } from "${path.resolve(sourceFile).replace(/\\/g, "/")}";
9464
+ import { main as _migrationMain } from "${absoluteSourcePath}";
9264
9465
  import { Kysely, TailordbDialect } from "@tailor-platform/sdk/kysely";
9265
9466
 
9266
9467
  function getDB(namespace) {
@@ -9280,12 +9481,7 @@ async function bundleMigrationScript(sourceFile, namespace, migrationNumber, env
9280
9481
  }
9281
9482
  `;
9282
9483
  fs$1.writeFileSync(entryPath, entryContent);
9283
- let tsconfig;
9284
- try {
9285
- tsconfig = await resolveTSConfig();
9286
- } catch {
9287
- tsconfig = void 0;
9288
- }
9484
+ const tsconfig = await resolveTSConfigWithFallback(baseDir ?? path.dirname(absoluteSourcePath));
9289
9485
  return {
9290
9486
  namespace,
9291
9487
  migrationNumber,
@@ -9621,12 +9817,12 @@ async function detectPendingMigrations(client, workspaceId, namespacesWithMigrat
9621
9817
  * @returns {Promise<ExecutionResult>} Execution result
9622
9818
  */
9623
9819
  async function executeSingleMigration(options, migration) {
9624
- const { client, workspaceId, authInvoker, env } = options;
9820
+ const { client, workspaceId, authInvoker, env, configDir } = options;
9625
9821
  const result = await executeScript({
9626
9822
  client,
9627
9823
  workspaceId,
9628
9824
  name: `migration-${migration.namespace}-${formatMigrationNumber(migration.number)}.js`,
9629
- code: (await bundleMigrationScript(migration.scriptPath, migration.namespace, migration.number, env)).bundledCode,
9825
+ code: (await bundleMigrationScript(migration.scriptPath, migration.namespace, migration.number, env, configDir)).bundledCode,
9630
9826
  invoker: authInvoker
9631
9827
  });
9632
9828
  return {
@@ -9680,7 +9876,8 @@ async function executeMigrations(context, migrations) {
9680
9876
  client: context.client,
9681
9877
  workspaceId: context.workspaceId,
9682
9878
  authInvoker,
9683
- env: context.env
9879
+ env: context.env,
9880
+ configDir: context.configDir
9684
9881
  };
9685
9882
  logger.info(`Using machine user: ${styles.bold(machineUserName)} for namespace '${namespace}'`);
9686
9883
  for (const migration of namespaceMigrations) {
@@ -9993,7 +10190,8 @@ function buildMigrationContextForScripts(client, migrationContext, migrationsReq
9993
10190
  authNamespace: authService.config.name,
9994
10191
  machineUsers: authService.config.machineUsers ? Object.keys(authService.config.machineUsers) : void 0,
9995
10192
  dbConfig: dbConfigMap,
9996
- env: migrationContext.config.env ?? {}
10193
+ env: migrationContext.config.env ?? {},
10194
+ configDir: path.dirname(migrationContext.config.path)
9997
10195
  };
9998
10196
  }
9999
10197
  /**
@@ -12907,6 +13105,15 @@ function collectVisibleResolverNamespaces(application, applications) {
12907
13105
  addResource: addPossiblyAmbiguousNamespace
12908
13106
  });
12909
13107
  }
13108
+ /**
13109
+ * Detect whether any resource owned by this application was last applied by a
13110
+ * different SDK version, in which case every resource is re-applied.
13111
+ * @param client - Operator client instance
13112
+ * @param workspaceId - Workspace ID
13113
+ * @param application - Application being deployed
13114
+ * @param functionEntries - Function registry entries of the application
13115
+ * @returns True when an owned resource carries a different sdk-version label
13116
+ */
12910
13117
  async function shouldForceApplyAll(client, workspaceId, application, functionEntries) {
12911
13118
  const desiredLabels = (await buildMetaRequest({
12912
13119
  trn: resourceTrn(workspaceId, "application", application.name),
@@ -12943,14 +13150,13 @@ async function shouldForceApplyAll(client, workspaceId, application, functionEnt
12943
13150
  functionEntries.forEach((entry) => {
12944
13151
  candidateTrns.add(resourceTrn(workspaceId, "function_registry", entry.name));
12945
13152
  });
12946
- for (const trn of candidateTrns) {
12947
- const metadata = await getOrNull(async () => {
12948
- const { metadata } = await client.getMetadata({ trn });
12949
- return metadata;
12950
- });
12951
- if (metadata?.labels["sdk-name"] !== application.name) continue;
12952
- if (!hasMatchingSdkVersion(metadata.labels, desiredLabels)) return true;
12953
- }
13153
+ const results = await Promise.allSettled([...candidateTrns].map((trn) => getOrNull(async () => {
13154
+ const { metadata } = await client.getMetadata({ trn });
13155
+ return metadata;
13156
+ })));
13157
+ if (results.some((result) => result.status === "fulfilled" && result.value?.labels["sdk-name"] === application.name && !hasMatchingSdkVersion(result.value.labels, desiredLabels))) return true;
13158
+ const failure = results.find((result) => result.status === "rejected");
13159
+ if (failure) throw failure.reason;
12954
13160
  return false;
12955
13161
  }
12956
13162
  /**
@@ -13282,6 +13488,7 @@ async function loadDeployConfig(params) {
13282
13488
  }
13283
13489
  async function buildDeploymentTargets(params) {
13284
13490
  const { configPaths, loadedConfigs, buildTarget = buildDeploymentTarget, ...targetParams } = params;
13491
+ await removeLegacyBundleFiles(path.resolve(getDistDir()));
13285
13492
  return Promise.all(configPaths.map((configPath, index) => buildTarget({
13286
13493
  ...targetParams,
13287
13494
  configPath,
@@ -16223,6 +16430,7 @@ function hasDependency(generator, dependency) {
16223
16430
 
16224
16431
  //#endregion
16225
16432
  //#region src/cli/commands/generate/watch/index.ts
16433
+ const warnedFallbacks = /* @__PURE__ */ new Set();
16226
16434
  /**
16227
16435
  * Error codes.
16228
16436
  */
@@ -16377,6 +16585,22 @@ function createDependencyGraphManager(options = {}) {
16377
16585
  };
16378
16586
  }
16379
16587
  /**
16588
+ * Resolve a watch group's glob patterns against baseDir into absolute file paths.
16589
+ * @param groupId - Watch group identifier, used only for the progress log line
16590
+ * @param patterns - Glob patterns to resolve
16591
+ * @param baseDir - Directory relative patterns are resolved against
16592
+ * @returns Absolute paths of every matched file
16593
+ */
16594
+ async function globPatterns(groupId, patterns, baseDir) {
16595
+ const files = /* @__PURE__ */ new Set();
16596
+ for (const pattern of patterns) {
16597
+ const absolutePattern = path.resolve(baseDir, pattern);
16598
+ logger.log(`${styles.dim(`Watch pattern for`)} ${styles.dim(groupId + ":")} ${path.relative(process.cwd(), absolutePattern)}`);
16599
+ for await (const file of glob(absolutePattern)) files.add(path.resolve(file));
16600
+ }
16601
+ return files;
16602
+ }
16603
+ /**
16380
16604
  * Creates a dependency watcher.
16381
16605
  * @param options - Watcher options
16382
16606
  * @returns DependencyWatcher instance
@@ -16544,13 +16768,17 @@ function createDependencyWatcher(options = {}) {
16544
16768
  }
16545
16769
  return {
16546
16770
  initialize,
16547
- async addWatchGroup(groupId, patterns) {
16771
+ async addWatchGroup(groupId, patterns, baseDir) {
16548
16772
  validateWatchGroup(groupId, patterns);
16549
16773
  if (!isInitialized) await initialize();
16550
- const files = /* @__PURE__ */ new Set();
16551
- for (const pattern of patterns) {
16552
- logger.log(`${styles.dim(`Watch pattern for`)} ${styles.dim(groupId + ":")} ${path.relative(process.cwd(), pattern)}`);
16553
- for await (const file of glob(pattern)) files.add(path.resolve(file));
16774
+ let files = await globPatterns(groupId, patterns, baseDir);
16775
+ if (files.size === 0 && baseDir !== process.cwd()) {
16776
+ const fallbackKey = `${baseDir}\0${groupId}`;
16777
+ if (!warnedFallbacks.has(fallbackKey)) {
16778
+ warnedFallbacks.add(fallbackKey);
16779
+ logger.warn(`No files matched watch patterns for "${groupId}" relative to "${baseDir}"; falling back to process.cwd(). Update this config's file patterns to be relative to its own directory before v2, when this fallback will be removed.`);
16780
+ }
16781
+ files = await globPatterns(groupId, patterns, process.cwd());
16554
16782
  }
16555
16783
  const watchGroup = {
16556
16784
  id: groupId,
@@ -16567,7 +16795,7 @@ function createDependencyWatcher(options = {}) {
16567
16795
  async removeWatchGroup(groupId) {
16568
16796
  const watchGroup = watchGroups.get(groupId);
16569
16797
  if (!watchGroup) return;
16570
- if (chokidarWatcher) chokidarWatcher.unwatch(watchGroup.patterns);
16798
+ if (chokidarWatcher) chokidarWatcher.unwatch(Array.from(watchGroup.files));
16571
16799
  for (const filePath of watchGroup.files) dependencyGraphManager.removeNode(filePath);
16572
16800
  watchGroups.delete(groupId);
16573
16801
  dependencyCache.clear();
@@ -16967,7 +17195,10 @@ function createGenerationManager(params) {
16967
17195
  const pluginExecutorFiles = generatePluginFilesIfNeeded(pluginManager, app.tailorDBServices, config.path);
16968
17196
  return {
16969
17197
  pluginExecutorFiles,
16970
- executorService: app.executorService ?? (pluginExecutorFiles.length > 0 ? createExecutorService({ config: { files: [] } }) : void 0)
17198
+ executorService: app.executorService ?? (pluginExecutorFiles.length > 0 ? createExecutorService({
17199
+ config: { files: [] },
17200
+ baseDir: path.dirname(config.path)
17201
+ }) : void 0)
16971
17202
  };
16972
17203
  });
16973
17204
  if (app.authService) {
@@ -17034,15 +17265,16 @@ function createGenerationManager(params) {
17034
17265
  watcher.setRestartCallback(() => {
17035
17266
  restartWatchProcess();
17036
17267
  });
17037
- await watcher.addWatchGroup("Config", [config.path]);
17268
+ const configDir = path.dirname(config.path);
17269
+ await watcher.addWatchGroup("Config", [config.path], configDir);
17038
17270
  const app = application;
17039
17271
  for (const db of app.tailorDBServices) {
17040
17272
  const dbNamespace = db.namespace;
17041
- await watcher.addWatchGroup(`TailorDB/${dbNamespace}`, db.config.files);
17273
+ await watcher.addWatchGroup(`TailorDB/${dbNamespace}`, db.config.files, configDir);
17042
17274
  }
17043
17275
  for (const resolverService of app.resolverServices) {
17044
17276
  const resolverNamespace = resolverService.namespace;
17045
- await watcher.addWatchGroup(`Resolver/${resolverNamespace}`, resolverService["config"].files);
17277
+ await watcher.addWatchGroup(`Resolver/${resolverNamespace}`, resolverService["config"].files, configDir);
17046
17278
  }
17047
17279
  await new Promise(() => {});
17048
17280
  }
@@ -18690,7 +18922,7 @@ async function generate(options) {
18690
18922
  if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
18691
18923
  let pluginManager;
18692
18924
  if (plugins.length > 0) pluginManager = new PluginManager(plugins);
18693
- const { defineApplication } = await import("./application-Dp_-ioiP.mjs");
18925
+ const { defineApplication } = await import("./application-Nlh9BHQf.mjs");
18694
18926
  const application = defineApplication({
18695
18927
  config,
18696
18928
  pluginManager
@@ -19894,20 +20126,16 @@ function createGqlEntry() {
19894
20126
  /**
19895
20127
  * Bundle a query executor script for TestExecScript.
19896
20128
  * @param engine - Query engine type
20129
+ * @param baseDir - Directory to resolve the bundler's tsconfig against
19897
20130
  * @returns Bundled code
19898
20131
  */
19899
- async function bundleQueryScript(engine) {
20132
+ async function bundleQueryScript(engine, baseDir) {
19900
20133
  const outputDir = path.resolve(getDistDir(), "query");
19901
20134
  fs$1.mkdirSync(outputDir, { recursive: true });
19902
20135
  const entryPath = path.join(outputDir, `query_${engine}.entry.ts`);
19903
20136
  const entryContent = engine === "sql" ? createSqlEntry() : createGqlEntry();
19904
20137
  fs$1.writeFileSync(entryPath, entryContent);
19905
- let tsconfig;
19906
- try {
19907
- tsconfig = await resolveTSConfig();
19908
- } catch {
19909
- tsconfig = void 0;
19910
- }
20138
+ const tsconfig = await resolveTSConfigWithFallback(baseDir);
19911
20139
  return (await rolldown.build({
19912
20140
  plugins: [platformBundleDefinePlugin],
19913
20141
  input: entryPath,
@@ -20169,7 +20397,7 @@ async function loadTypeFieldOrder(config, namespace) {
20169
20397
  const fieldOrder = /* @__PURE__ */ new Map();
20170
20398
  const dbConfig = config.db?.[namespace];
20171
20399
  if (!dbConfig || !("files" in dbConfig) || dbConfig.files.length === 0) return fieldOrder;
20172
- const typeFiles = loadFilesWithIgnores(dbConfig);
20400
+ const typeFiles = loadFilesWithIgnores(dbConfig, path.dirname(config.path));
20173
20401
  await Promise.all(typeFiles.map(async (typeFile) => {
20174
20402
  try {
20175
20403
  const module = await import(pathToFileURL(typeFile).href);
@@ -20363,7 +20591,7 @@ async function query(options) {
20363
20591
  }
20364
20592
  async function prepareQueryExecutor(options) {
20365
20593
  const { client, workspaceId, config, application, machineUserResource, engine, namespaces } = await loadOptions(options);
20366
- const bundledCode = await bundleQueryScript(engine);
20594
+ const bundledCode = await bundleQueryScript(engine, path.dirname(config.path));
20367
20595
  const invoker = create(AuthInvokerSchema, {
20368
20596
  namespace: application.authNamespace,
20369
20597
  machineUserName: machineUserResource.name
@@ -20775,5 +21003,52 @@ function isDeno() {
20775
21003
  }
20776
21004
 
20777
21005
  //#endregion
20778
- export { listFolders as $, deploymentArgs as $n, handleOptionalToRequiredError as $t, generate as A, generateUserTypes as An, startCommand as At, remove as B, loadConsoleBaseUrl as Bn, deploy as Bt, waitWorkflowExecution as C, formatDiffSummary as Cn, listCommand$8 as Ct, listWorkflows as D, resourceTrn as Dn, jobsCommand as Dt, listCommand$2 as E, getNamespacesWithMigrations as En, getExecutorWaitFailureMessage as Et, openInConfiguredEditor as F, deleteUserTokens as Fn, getWorkflowExecution as Ft, treeCommand as G, readPlatformConfig as Gn, createWorkspace$1 as Gt, updateCommand$1 as H, loadStoredUserTokens as Hn, listCommand$9 as Ht, show as I, fetchLatestToken as In, listWorkflowExecutions as It, getCommand$1 as J, writePlatformConfig as Jn, ensureConfigId as Jt, listCommand$3 as K, resolveUserTokenKey as Kn, formatKeyValueTable as Kt, showCommand as L, hasAnyUserTokenEntry as Ln, functionExecutionStatusToString as Lt, generateMigrationScript as M, apiCall as Mn, getCommand$5 as Mt, writeDbTypesFile as N, assertWritable as Nn, getWorkflow as Nt, truncate as O, sdkNameLabelKey as On, listExecutorJobs as Ot, getConfiguredEditorCommand as P, loadConfig as Pn, executionsCommand as Pt, listCommand$4 as Q, confirmationArgs as Qn, MIGRATION_LABEL_KEY as Qt, extractOwnedNamespaces as R, hasUserTokenEntry as Rn, getCommand$6 as Rt, waitCommand as S, parseMigrationNumberArg as Sn, triggerExecutor as St, resumeWorkflow as T, hasChanges as Tn, getExecutorJob as Tt, updateOrganization as U, loadWorkspaceId as Un, listWorkspaces as Ut, removeCommand$1 as V, loadMachineUserName as Vn, deployFromCLI as Vt, organizationTree as W, platformConfigFromProfile as Wn, createCommand$1 as Wt, updateCommand$2 as X, commonArgs as Xn, waitForExecution as Xt, getOrganization as Y, defineAppCommand as Yn, executeScript as Yt, updateFolder as Z, configArg as Zn, bundleMigrationScript as Zt, deleteWorkspace as _, getNextMigrationNumber as _n, getCommand$4 as _t, updateUser as a, DIFF_FILE_NAME as an, toPageDirection as ar, createFolder as at, getAppHealth as b, reconstructSnapshotFromMigrations as bn, webhookCommand as bt, listCommand as c, SCHEMA_FILE_NAME as cn, getCommand$3 as ct, inviteUser as d, compareSnapshots as dn, tokenCommand as dt, parseMigrationLabelNumber as en, isVerbose as er, getCommand$2 as et, restoreCommand as f, createSnapshotFromLocalTypes as fn, listCommand$6 as ft, deleteCommand as g, getMigrationFiles as gn, listFunctionRegistries as gt, getWorkspace as h, getMigrationFilePath as hn, listCommand$7 as ht, updateCommand as i, DB_TYPES_FILE_NAME as in, resolveMachineUserInputSource as ir, createCommand as it, generateCommand as j, prompt as jn, startWorkflow as jt, truncateCommand as k, PluginManager as kn, watchExecutorJob as kt, listUsers as l, assertValidMigrationFiles as ln, getOAuth2Client as lt, getCommand as m, getMigrationDirPath as mn, generate$1 as mt, query as n, generateAllTypeManifestsFromSnapshot as nn, pagedLogArgs as nr, deleteCommand$1 as nt, removeCommand as o, INITIAL_SCHEMA_NUMBER as on, workspaceArgs as or, listCommand$5 as ot, restoreWorkspace as p, getLatestMigrationNumber as pn, listMachineUsers as pt, listOrganizations as q, saveUserTokens as qn, workspaceNameSchema as qt, queryCommand as r, protoGqlPermission as rn, paginationArgs as rr, deleteFolder as rt, removeUser as s, MIGRATE_FILE_NAME as sn, listOAuth2Clients as st, isNativeTypeScriptRuntime as t, compareSnapshotWithRemote as tn, multiConfigArg as tr, getFolder as tt, inviteCommand as u, compareLocalTypesWithSnapshot as un, getMachineUserToken as ut, listApps as v, isValidMigrationNumber as vn, getFunctionRegistry as vt, resumeCommand as w, formatMigrationDiff as wn, listExecutors as wt, healthCommand as x, formatMigrationNumber as xn, triggerCommand as xt, listCommand$1 as y, loadDiff as yn, listWebhookExecutors as yt, logBetaWarning as z, loadAccessToken as zn, getExecutor as zt };
20779
- //# sourceMappingURL=runtime-BD2vYJFT.mjs.map
21006
+ //#region src/cli/shared/register-tsconfig-paths-hook.ts
21007
+ /**
21008
+ * Register the tsconfig `paths` alias resolve hook alongside tsx.
21009
+ *
21010
+ * tsx's own tsconfig-paths support is scoped to the tsconfig discovered from
21011
+ * where tsx was registered, so a project-local alias in a dynamically
21012
+ * imported user file (resolver, executor, workflow, TailorDB type) can fail
21013
+ * to resolve when the importing file lives outside that directory. This
21014
+ * hook activates only when tsx's own resolution throws (a fallback, not an
21015
+ * override): it then re-derives `paths` from each importing file's own
21016
+ * directory, without touching TypeScript transformation (left to tsx).
21017
+ *
21018
+ * Uses `module.register()` rather than `module.registerHooks()`: chaining
21019
+ * another `register()` loader after tsx's composes correctly regardless of
21020
+ * which of the two internal registration APIs tsx itself picks (it varies
21021
+ * by Node.js version).
21022
+ * @param hookUrl - URL of the tsconfig-paths-hook.mjs module.
21023
+ */
21024
+ async function registerTsconfigPathsHook(hookUrl) {
21025
+ if (isNativeTypeScriptRuntime()) return;
21026
+ if (typeof mod.register !== "function") return;
21027
+ mod.register(hookUrl);
21028
+ }
21029
+
21030
+ //#endregion
21031
+ //#region src/cli/shared/register-typescript-runtime.ts
21032
+ /**
21033
+ * Register TypeScript loading for the CLI: tsx for transformation, plus the
21034
+ * tsconfig `paths` alias resolve hook tsx's own cwd-scoped resolver misses.
21035
+ *
21036
+ * Shared by both the `tailor` binary entrypoint and the programmatic `./cli`
21037
+ * API entrypoint so the two registration steps can't drift apart.
21038
+ * @param hookUrl - URL of the tsconfig-paths-hook.mjs module, resolved by the
21039
+ * caller via its own `import.meta.url`. Bundling can move this shared module
21040
+ * to a different output location than tsconfig-paths-hook.mjs, so the URL
21041
+ * can't be resolved relative to this file — it must come from an entrypoint
21042
+ * whose bundled output path stays predictable.
21043
+ */
21044
+ async function registerTypeScriptRuntime(hookUrl) {
21045
+ if (!isNativeTypeScriptRuntime()) {
21046
+ const { register } = await import("tsx/esm/api");
21047
+ register();
21048
+ }
21049
+ await registerTsconfigPathsHook(hookUrl);
21050
+ }
21051
+
21052
+ //#endregion
21053
+ export { listFolders as $, deploymentArgs as $n, handleOptionalToRequiredError as $t, generate as A, generateUserTypes as An, startCommand as At, remove as B, loadConsoleBaseUrl as Bn, deploy as Bt, waitWorkflowExecution as C, formatDiffSummary as Cn, listCommand$8 as Ct, listWorkflows as D, resourceTrn as Dn, jobsCommand as Dt, listCommand$2 as E, getNamespacesWithMigrations as En, getExecutorWaitFailureMessage as Et, openInConfiguredEditor as F, deleteUserTokens as Fn, getWorkflowExecution as Ft, treeCommand as G, readPlatformConfig as Gn, createWorkspace$1 as Gt, updateCommand$1 as H, loadStoredUserTokens as Hn, listCommand$9 as Ht, show as I, fetchLatestToken as In, listWorkflowExecutions as It, getCommand$1 as J, writePlatformConfig as Jn, ensureConfigId as Jt, listCommand$3 as K, resolveUserTokenKey as Kn, formatKeyValueTable as Kt, showCommand as L, hasAnyUserTokenEntry as Ln, functionExecutionStatusToString as Lt, generateMigrationScript as M, apiCall as Mn, getCommand$5 as Mt, writeDbTypesFile as N, assertWritable as Nn, getWorkflow as Nt, truncate as O, sdkNameLabelKey as On, listExecutorJobs as Ot, getConfiguredEditorCommand as P, loadConfig as Pn, executionsCommand as Pt, listCommand$4 as Q, confirmationArgs as Qn, MIGRATION_LABEL_KEY as Qt, extractOwnedNamespaces as R, hasUserTokenEntry as Rn, getCommand$6 as Rt, waitCommand as S, parseMigrationNumberArg as Sn, triggerExecutor as St, resumeWorkflow as T, hasChanges as Tn, getExecutorJob as Tt, updateOrganization as U, loadWorkspaceId as Un, listWorkspaces as Ut, removeCommand$1 as V, loadMachineUserName as Vn, deployFromCLI as Vt, organizationTree as W, platformConfigFromProfile as Wn, createCommand$1 as Wt, updateCommand$2 as X, commonArgs as Xn, waitForExecution as Xt, getOrganization as Y, defineAppCommand as Yn, executeScript as Yt, updateFolder as Z, configArg as Zn, bundleMigrationScript as Zt, deleteWorkspace as _, getNextMigrationNumber as _n, getCommand$4 as _t, updateUser as a, DIFF_FILE_NAME as an, toPageDirection as ar, createFolder as at, getAppHealth as b, reconstructSnapshotFromMigrations as bn, webhookCommand as bt, listCommand as c, SCHEMA_FILE_NAME as cn, getCommand$3 as ct, inviteUser as d, compareSnapshots as dn, tokenCommand as dt, parseMigrationLabelNumber as en, isVerbose as er, getCommand$2 as et, restoreCommand as f, createSnapshotFromLocalTypes as fn, listCommand$6 as ft, deleteCommand as g, getMigrationFiles as gn, listFunctionRegistries as gt, getWorkspace as h, getMigrationFilePath as hn, listCommand$7 as ht, updateCommand as i, DB_TYPES_FILE_NAME as in, resolveMachineUserInputSource as ir, createCommand as it, generateCommand as j, prompt as jn, startWorkflow as jt, truncateCommand as k, PluginManager as kn, watchExecutorJob as kt, listUsers as l, assertValidMigrationFiles as ln, getOAuth2Client as lt, getCommand as m, getMigrationDirPath as mn, generate$1 as mt, query as n, generateAllTypeManifestsFromSnapshot as nn, pagedLogArgs as nr, deleteCommand$1 as nt, removeCommand as o, INITIAL_SCHEMA_NUMBER as on, workspaceArgs as or, listCommand$5 as ot, restoreWorkspace as p, getLatestMigrationNumber as pn, listMachineUsers as pt, listOrganizations as q, saveUserTokens as qn, workspaceNameSchema as qt, queryCommand as r, protoGqlPermission as rn, paginationArgs as rr, deleteFolder as rt, removeUser as s, MIGRATE_FILE_NAME as sn, listOAuth2Clients as st, registerTypeScriptRuntime as t, compareSnapshotWithRemote as tn, multiConfigArg as tr, getFolder as tt, inviteCommand as u, compareLocalTypesWithSnapshot as un, getMachineUserToken as ut, listApps as v, isValidMigrationNumber as vn, getFunctionRegistry as vt, resumeCommand as w, formatMigrationDiff as wn, listExecutors as wt, healthCommand as x, formatMigrationNumber as xn, triggerCommand as xt, listCommand$1 as y, loadDiff as yn, listWebhookExecutors as yt, logBetaWarning as z, loadAccessToken as zn, getExecutor as zt };
21054
+ //# sourceMappingURL=register-typescript-runtime-Bd4bcLbW.mjs.map