@tailor-platform/sdk 2.0.0-next.9 → 2.0.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 (170) hide show
  1. package/CHANGELOG.md +611 -0
  2. package/dist/{application-D_oSqto2.mjs → application-CM6hKnSK.mjs} +489 -118
  3. package/dist/application-CM6hKnSK.mjs.map +1 -0
  4. package/dist/application-CXNaUNhv.mjs +3 -0
  5. package/dist/cli/commands/deploy/aigateway.d.mts +1 -1
  6. package/dist/cli/commands/deploy/application.d.mts +1 -1
  7. package/dist/cli/commands/deploy/auth.d.mts +1 -1
  8. package/dist/cli/commands/deploy/deploy.d.mts +1 -0
  9. package/dist/cli/commands/deploy/executor.d.mts +1 -1
  10. package/dist/cli/commands/deploy/function-registry.d.mts +1 -2
  11. package/dist/cli/commands/deploy/idp.d.mts +1 -1
  12. package/dist/cli/commands/deploy/label.d.mts +2 -0
  13. package/dist/cli/commands/deploy/resolver.d.mts +1 -1
  14. package/dist/cli/commands/deploy/staticwebsite.d.mts +1 -1
  15. package/dist/cli/commands/deploy/tailordb/index.d.mts +3 -1
  16. package/dist/cli/commands/deploy/types.d.mts +2 -1
  17. package/dist/cli/commands/deploy/workflow-execution-policy.d.mts +1 -2
  18. package/dist/cli/commands/deploy/workflow.d.mts +1 -1
  19. package/dist/cli/commands/executor/get.d.mts +1 -10
  20. package/dist/cli/commands/executor/jobs.d.mts +1 -38
  21. package/dist/cli/commands/executor/trigger.d.mts +1 -11
  22. package/dist/cli/commands/generate/seed/bundler.d.mts +2 -1
  23. package/dist/cli/commands/tailordb/migrate/bundler.d.mts +3 -2
  24. package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +11 -1
  25. package/dist/cli/commands/tailordb/migrate/schema-checks.d.mts +5 -0
  26. package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +1 -1
  27. package/dist/cli/commands/workflow/executions.d.mts +1 -13
  28. package/dist/cli/commands/workflow/get.d.mts +1 -10
  29. package/dist/cli/commands/workflow/start.d.mts +2 -14
  30. package/dist/cli/index.mjs +12 -6561
  31. package/dist/cli/lib.d.mts +9 -12
  32. package/dist/cli/lib.mjs +99 -42
  33. package/dist/cli/lib.mjs.map +1 -1
  34. package/dist/cli/{index.d.mts → main.d.mts} +1 -1
  35. package/dist/cli/main.mjs +6777 -0
  36. package/dist/cli/main.mjs.map +1 -0
  37. package/dist/cli/services/http-adapter/bundler.d.mts +1 -0
  38. package/dist/cli/services/workflow/bundler.d.mts +2 -1
  39. package/dist/cli/shared/client.d.mts +28 -3
  40. package/dist/cli/shared/config-loader.d.mts +11 -4
  41. package/dist/cli/shared/error-json.d.mts +23 -0
  42. package/dist/cli/shared/tsconfig-paths-plugin.d.mts +2 -0
  43. package/dist/cli/shared/type-generator.d.mts +4 -3
  44. package/dist/completion/zsh-worker.zsh +85 -22
  45. package/dist/configure/config/types.d.mts +29 -4
  46. package/dist/configure/index.d.mts +4 -3
  47. package/dist/configure/index.mjs +183 -6
  48. package/dist/configure/index.mjs.map +1 -1
  49. package/dist/configure/services/executor/index.d.mts +2 -2
  50. package/dist/configure/services/executor/trigger/event.d.mts +245 -2
  51. package/dist/configure/services/executor/trigger/index.d.mts +3 -3
  52. package/dist/configure/services/idp/index.d.mts +2 -2
  53. package/dist/configure/services/idp/permission.d.mts +1 -16
  54. package/dist/configure/services/idp/types.d.mts +5 -1
  55. package/dist/configure/services/index.d.mts +4 -3
  56. package/dist/configure/services/resolver/index.d.mts +2 -1
  57. package/dist/configure/services/resolver/permission.d.mts +64 -0
  58. package/dist/configure/services/resolver/resolver.d.mts +14 -2
  59. package/dist/configure/services/tailordb/index.d.mts +0 -1
  60. package/dist/configure/services/tailordb/permission.d.mts +1 -16
  61. package/dist/configure/services/workflow/execution-policy.d.mts +3 -3
  62. package/dist/configure/services/workflow/execution-policy.types.d.mts +1 -1
  63. package/dist/configure/services/workflow/job.d.mts +11 -2
  64. package/dist/configure/services/workflow/workflow.d.mts +10 -0
  65. package/dist/configure/types/permission-operand.types.d.mts +20 -0
  66. package/dist/{crashreport-CxHne11E.mjs → crashreport-B5LqCTfF.mjs} +2 -2
  67. package/dist/{crashreport-CxHne11E.mjs.map → crashreport-B5LqCTfF.mjs.map} +1 -1
  68. package/dist/{crashreport-0ioNRZ4K.mjs → crashreport-eI7ty7ok.mjs} +1 -1
  69. package/dist/{errors-DfnF4ibq.mjs → errors-D7583Zz7.mjs} +2 -44
  70. package/dist/errors-D7583Zz7.mjs.map +1 -0
  71. package/dist/{globals-CBZ0egXT.mjs → globals-TfAVItuK.mjs} +21 -5
  72. package/dist/globals-TfAVItuK.mjs.map +1 -0
  73. package/dist/logger-BtX0suGY.mjs +48 -0
  74. package/dist/logger-BtX0suGY.mjs.map +1 -0
  75. package/dist/{logger-BwS4ppwO.mjs → logger-CXQq9YIp.mjs} +110 -13
  76. package/dist/logger-CXQq9YIp.mjs.map +1 -0
  77. package/dist/node-builtins-CmaL2Cbq.mjs +36 -0
  78. package/dist/node-builtins-CmaL2Cbq.mjs.map +1 -0
  79. package/dist/plugin/builtin/enum-constants/index.mjs +115 -2
  80. package/dist/plugin/builtin/enum-constants/index.mjs.map +1 -0
  81. package/dist/plugin/builtin/file-utils/index.mjs +149 -2
  82. package/dist/plugin/builtin/file-utils/index.mjs.map +1 -0
  83. package/dist/plugin/builtin/kysely-type/index.mjs +274 -2
  84. package/dist/plugin/builtin/kysely-type/index.mjs.map +1 -0
  85. package/dist/plugin/builtin/seed/index.mjs +1 -1
  86. package/dist/plugin/builtin/seed/seed-type-processor.d.mts +2 -0
  87. package/dist/{register-ts-hook-DgnmGTCt.mjs → register-ts-hook-LYV7zH-e.mjs} +2949 -1001
  88. package/dist/register-ts-hook-LYV7zH-e.mjs.map +1 -0
  89. package/dist/{registry-i7EdJ-D5.mjs → registry-BIGVUrMB.mjs} +3 -3
  90. package/dist/registry-BIGVUrMB.mjs.map +1 -0
  91. package/dist/runtime/globals.d.mts +7 -0
  92. package/dist/runtime/index.d.mts +3 -1
  93. package/dist/runtime/index.mjs +3 -2
  94. package/dist/runtime/logger.d.mts +98 -0
  95. package/dist/runtime/logger.mjs +3 -0
  96. package/dist/runtime/workflow.d.mts +15 -7
  97. package/dist/runtime/workflow.mjs +1 -1
  98. package/dist/{seed-LUVr7jHL.mjs → seed-B-yckgQY.mjs} +42 -3
  99. package/dist/seed-B-yckgQY.mjs.map +1 -0
  100. package/dist/{service-DaeJlBoH.mjs → service-B5WynBHQ.mjs} +3 -3
  101. package/dist/{service-DaeJlBoH.mjs.map → service-B5WynBHQ.mjs.map} +1 -1
  102. package/dist/service-M7OYziQP.mjs +3 -0
  103. package/dist/{service-CXFce28G.mjs → service-k1xy_A5G.mjs} +30 -3
  104. package/dist/{service-CXFce28G.mjs.map → service-k1xy_A5G.mjs.map} +1 -1
  105. package/dist/{service_pb-BoLM0X4K.mjs → service_pb-D5--My_M.mjs} +5 -5
  106. package/dist/service_pb-D5--My_M.mjs.map +1 -0
  107. package/dist/{service_pb-r1T7kpJc.mjs → service_pb-i8CmnQP4.mjs} +1 -1
  108. package/dist/tailor-proto/src/tailor/v1/application_pb.d.mts +106 -1
  109. package/dist/tailor-proto/src/tailor/v1/executor_resource_pb.d.mts +24 -1
  110. package/dist/tailor-proto/src/tailor/v1/function_pb.d.mts +49 -1
  111. package/dist/tailor-proto/src/tailor/v1/service_pb.d.mts +89 -6
  112. package/dist/tailor-proto/src/tailor/v1/telemetryrouter_resource_pb.d.mts +26 -1
  113. package/dist/tailor-proto/src/tailor/v1/workflow_pb.d.mts +101 -1
  114. package/dist/tailor-proto/src/tailor/v1/workflow_resource_pb.d.mts +22 -1
  115. package/dist/types/auth.generated.d.mts +14 -2
  116. package/dist/types/executor.generated.d.mts +45 -3
  117. package/dist/types/http-adapter.generated.d.mts +5 -0
  118. package/dist/types/idp.generated.d.mts +31 -1
  119. package/dist/types/resolver.generated.d.mts +30 -2
  120. package/dist/types/tailordb.generated.d.mts +15 -1
  121. package/dist/utils/test/index.d.mts +1 -2
  122. package/dist/utils/test/index.mjs +1 -169
  123. package/dist/utils/test/index.mjs.map +1 -1
  124. package/dist/vitest/environment.mjs +1 -1
  125. package/dist/vitest/index.d.mts +6 -4
  126. package/dist/vitest/index.mjs +112 -62
  127. package/dist/vitest/index.mjs.map +1 -1
  128. package/dist/vitest/mock.d.mts +2 -1
  129. package/dist/vitest/mocks/logger.d.mts +45 -0
  130. package/dist/vitest/mocks/workflow.d.mts +8 -8
  131. package/dist/vitest/setup.mjs +1 -1
  132. package/dist/{workflow-CsBvRE3g.mjs → workflow-Bamae_Yc.mjs} +5 -5
  133. package/dist/workflow-Bamae_Yc.mjs.map +1 -0
  134. package/dist/{workspace_resource_pb-Db3fv68L.mjs → workspace_resource_pb-DXnO2AT-.mjs} +13 -8
  135. package/dist/workspace_resource_pb-DXnO2AT-.mjs.map +1 -0
  136. package/docs/cli/application.md +5 -1
  137. package/docs/cli/tailordb.md +47 -13
  138. package/docs/cli-reference.md +31 -30
  139. package/docs/configuration.md +53 -1
  140. package/docs/github-actions.md +2 -2
  141. package/docs/migration/v2.md +307 -10
  142. package/docs/runtime.md +5 -1
  143. package/docs/services/executor.md +83 -3
  144. package/docs/services/idp.md +8 -6
  145. package/docs/services/resolver.md +60 -4
  146. package/docs/services/tailordb-migration.md +31 -7
  147. package/docs/services/tailordb.md +7 -5
  148. package/docs/services/workflow.md +33 -3
  149. package/docs/testing.md +34 -7
  150. package/package.json +31 -24
  151. package/dist/application-CtuzFhg8.mjs +0 -3
  152. package/dist/application-D_oSqto2.mjs.map +0 -1
  153. package/dist/cli/index.mjs.map +0 -1
  154. package/dist/enum-constants-j9QBF0cB.mjs +0 -116
  155. package/dist/enum-constants-j9QBF0cB.mjs.map +0 -1
  156. package/dist/errors-DfnF4ibq.mjs.map +0 -1
  157. package/dist/file-utils-yEiIS4nJ.mjs +0 -150
  158. package/dist/file-utils-yEiIS4nJ.mjs.map +0 -1
  159. package/dist/globals-CBZ0egXT.mjs.map +0 -1
  160. package/dist/kysely-type-DqIRgDYR.mjs +0 -275
  161. package/dist/kysely-type-DqIRgDYR.mjs.map +0 -1
  162. package/dist/logger-BwS4ppwO.mjs.map +0 -1
  163. package/dist/register-ts-hook-DgnmGTCt.mjs.map +0 -1
  164. package/dist/registry-i7EdJ-D5.mjs.map +0 -1
  165. package/dist/seed-LUVr7jHL.mjs.map +0 -1
  166. package/dist/service-DjhjpJpm.mjs +0 -3
  167. package/dist/service_pb-BoLM0X4K.mjs.map +0 -1
  168. package/dist/utils/test/mock.d.mts +0 -86
  169. package/dist/workflow-CsBvRE3g.mjs.map +0 -1
  170. package/dist/workspace_resource_pb-Db3fv68L.mjs.map +0 -1
@@ -1,11 +1,13 @@
1
1
  import { n as isSdkBranded } from "./brand-Eo4pLXPJ.mjs";
2
2
  import { t as assertDefined } from "./assert-DBxo8jPo.mjs";
3
- import { a as parseBoolean, n as logger, r as styles } from "./logger-BwS4ppwO.mjs";
4
- import { a as AuthConfigSchema, c as stripTailorDBTypeBuilderHelpers, d as applyRelationMetadataToFieldConfig, f as buildRelationInfo, g as functionSchema, h as loadFilesWithIgnores, l as TailorDBServiceConfigSchema, m as validateRelationConfig, n as loadExecutor, o as AuthInvokerSchema, p as processRelationMetadata, s as TailorFieldSchema, t as createExecutorService, u as TailorDBTypeSchema } from "./service-CXFce28G.mjs";
3
+ import { a as parseBoolean, n as logger, r as styles } from "./logger-CXQq9YIp.mjs";
4
+ import { a as AuthConfigSchema, c as stripTailorDBTypeBuilderHelpers, d as applyRelationMetadataToFieldConfig, f as buildRelationInfo, g as functionSchema, h as loadFilesWithIgnores, l as TailorDBServiceConfigSchema, m as validateRelationConfig, n as loadExecutor, o as AuthInvokerSchema, p as processRelationMetadata, s as TailorFieldSchema, t as createExecutorService, u as TailorDBTypeSchema } from "./service-k1xy_A5G.mjs";
5
5
  import { t as multiline } from "./multiline-sfHpTZZK.mjs";
6
6
  import { t as userAgent } from "./user-agent-Bgsszb5I.mjs";
7
+ import { t as createCLIError } from "./errors-D7583Zz7.mjs";
8
+ import { n as isNodeBuiltinImport, t as getNodeBuiltinMessage } from "./node-builtins-CmaL2Cbq.mjs";
7
9
  import { t as isPluginGeneratedType } from "./type-source-DH_LH20p.mjs";
8
- import { builtinModules, createRequire } from "node:module";
10
+ import { createRequire } from "node:module";
9
11
  import * as path from "pathe";
10
12
  import { resolve } from "pathe";
11
13
  import { resolveTSConfig } from "pkg-types";
@@ -17,11 +19,11 @@ import { MethodOptions_IdempotencyLevel } from "@bufbuild/protobuf/wkt";
17
19
  import { pathToFileURL } from "node:url";
18
20
  import { OAuth2Client } from "@badgateway/oauth2-client";
19
21
  import { Code, ConnectError, createClient } from "@connectrpc/connect";
20
- import { getGlobalDispatcher } from "undici";
21
22
  import pLimit from "p-limit";
22
23
  import * as crypto from "node:crypto";
23
24
  import * as rolldown from "rolldown";
24
25
  import { parseSync } from "oxc-parser";
26
+ import { createPathsMatcher, getTsconfig } from "get-tsconfig";
25
27
  import * as inflection from "inflection";
26
28
  import * as globals from "globals";
27
29
  import * as os from "node:os";
@@ -180,7 +182,7 @@ function initOAuth2Client(config) {
180
182
  */
181
183
  async function initOperatorClient(accessToken, config) {
182
184
  const platformConfig = config ?? getPlatformConfigForToken(accessToken);
183
- const [{ createTracingInterceptor }, { OperatorService }] = await Promise.all([import("./interceptor-e33JtsC-.mjs"), import("./service_pb-r1T7kpJc.mjs")]);
185
+ const [{ createTracingInterceptor }, { OperatorService }] = await Promise.all([import("./interceptor-e33JtsC-.mjs"), import("./service_pb-i8CmnQP4.mjs")]);
184
186
  const interceptors = [
185
187
  await userAgentInterceptor(),
186
188
  await bearerTokenInterceptor(accessToken),
@@ -233,9 +235,10 @@ async function bearerTokenInterceptor(accessToken) {
233
235
  /**
234
236
  * Create an interceptor that retries failed unary requests with backoff.
235
237
  *
236
- * Retries unary methods on `Unavailable`/`ResourceExhausted`, and `Internal`
237
- * only for methods declared idempotent, up to 3 attempts. Workspace creation is
238
- * excluded because it has no idempotency key and a lost response is ambiguous.
238
+ * Retries unary methods on `Unavailable`/`ResourceExhausted`, and
239
+ * `Aborted`/`Internal` only for methods declared side-effect-free or idempotent,
240
+ * up to 3 attempts. Workspace creation is excluded because it has no idempotency
241
+ * key and a lost response is ambiguous.
239
242
  * As a targeted exception for the deploy/apply flow, a post-retry `AlreadyExists`
240
243
  * from an allowlisted Create (see `RETRY_SAFE_CREATE_METHODS`) is treated as
241
244
  * success, since it means a prior attempt already committed the resource
@@ -260,7 +263,7 @@ function retryInterceptor() {
260
263
  logger.debug(`retry: ${req.method.name} returned AlreadyExists on attempt ${i + 1}; treating as success (prior attempt likely committed)`);
261
264
  return synthesizeEmptyUnaryResponse(req);
262
265
  }
263
- const { reportCrash } = await import("./crashreport-0ioNRZ4K.mjs");
266
+ const { reportCrash } = await import("./crashreport-eI7ty7ok.mjs");
264
267
  await reportCrash(error, "handledError");
265
268
  }
266
269
  if (req.method.name !== "CreateWorkspace" && isRetirable(error, req.method.idempotency)) {
@@ -306,8 +309,10 @@ function connectCodeName(error) {
306
309
  *
307
310
  * Membership is deliberately an allowlist, not `startsWith("Create")`: swallowing
308
311
  * synthesizes an empty response (see `synthesizeEmptyUnaryResponse`), which is only
309
- * safe when every caller ignores the response body. These are the deploy/apply
310
- * resource creations that fire under heavy parallelism and discard their response.
312
+ * safe when every caller tolerates an empty response body. These are the deploy/apply
313
+ * resource creations that fire under heavy parallelism and discard their response
314
+ * except `CreateSecretManagerSecret`, whose caller reads `secret.updateTime` but
315
+ * degrades safely when it is absent (the next deploy re-updates the secret).
311
316
  *
312
317
  * Intentionally excluded because their callers read the response body — swallowing
313
318
  * would hand back an empty message and corrupt downstream state:
@@ -412,6 +417,7 @@ function isRetirable(error, idempotency) {
412
417
  switch (error.code) {
413
418
  case Code.ResourceExhausted:
414
419
  case Code.Unavailable: return true;
420
+ case Code.Aborted:
415
421
  case Code.Internal: return idempotency === MethodOptions_IdempotencyLevel.NO_SIDE_EFFECTS || idempotency === MethodOptions_IdempotencyLevel.IDEMPOTENT;
416
422
  default: return false;
417
423
  }
@@ -660,12 +666,20 @@ async function fetchPlatformMachineUserToken(clientId, clientSecret, config) {
660
666
  }).clientCredentials();
661
667
  }
662
668
  /**
663
- * Close undici's global HTTP connection pool to prevent libuv UV_HANDLE_CLOSING
669
+ * Close the global HTTP connection pool to prevent libuv UV_HANDLE_CLOSING
664
670
  * assertion failure on Windows at process exit (Node.js 23.x+).
665
671
  * See: https://github.com/nodejs/node/issues/56645
672
+ *
673
+ * The pool is reached through the global dispatcher symbol rather than the `undici`
674
+ * package: importing that package installs its own Agent over these same globals,
675
+ * replacing the HTTP stack Node's `fetch` already uses. The symbol is versioned per
676
+ * Dispatcher API generation, and the newest one wins because older symbols hold a
677
+ * wrapper around that same pool — closing both would destroy it twice.
666
678
  */
667
679
  async function closeConnectionPool() {
668
- await getGlobalDispatcher().close();
680
+ const globals = globalThis;
681
+ const dispatcher = globals[Symbol.for("undici.globalDispatcher.2")] ?? globals[Symbol.for("undici.globalDispatcher.1")];
682
+ if (typeof dispatcher?.close === "function") await dispatcher.close();
669
683
  }
670
684
 
671
685
  //#endregion
@@ -687,17 +701,27 @@ function hashFile(filePath) {
687
701
  const content = fs.readFileSync(filePath);
688
702
  return crypto.createHash("sha256").update(content).digest("hex");
689
703
  }
704
+ const MISSING_FILE_MARKER = "<missing>";
690
705
  /**
691
706
  * Compute a deterministic SHA-256 hash for multiple files.
692
707
  *
693
708
  * Paths are sorted alphabetically before hashing so that the result
694
709
  * is independent of the order the paths are supplied (e.g. glob ordering).
695
- * Each file's individual hash is concatenated and then hashed again.
710
+ * Each file's individual hash is concatenated and then hashed again. A path
711
+ * that does not exist contributes a fixed marker instead of a content hash.
696
712
  * @param filePaths - Array of absolute file paths
697
713
  * @returns Hex-encoded SHA-256 hash representing all files
698
714
  */
699
715
  function hashFiles(filePaths) {
700
- return hashContent(filePaths.toSorted().map((fp) => hashFile(fp)).join(""));
716
+ return hashContent(filePaths.toSorted().map((fp) => hashFileOrMissing(fp)).join(""));
717
+ }
718
+ function hashFileOrMissing(filePath) {
719
+ try {
720
+ return hashFile(filePath);
721
+ } catch (error) {
722
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") return MISSING_FILE_MARKER;
723
+ throw error;
724
+ }
701
725
  }
702
726
 
703
727
  //#endregion
@@ -773,7 +797,7 @@ function computeBundlerContextHash(params) {
773
797
  */
774
798
  async function withCache(params) {
775
799
  const { cache, kind, namespace, name, sourceFile, contextHash, build } = params;
776
- if (!cache) return await build([]);
800
+ if (!cache) return await build([], () => {});
777
801
  const content = cache.tryRestore({
778
802
  kind,
779
803
  namespace,
@@ -784,15 +808,16 @@ async function withCache(params) {
784
808
  logger.debug(` ${styles.dim("cached")}: ${name}`);
785
809
  return content;
786
810
  }
811
+ const extraDependencies = /* @__PURE__ */ new Set();
787
812
  const { plugin, getResult } = createDepCollectorPlugin();
788
- const code = await build([plugin]);
813
+ const code = await build([plugin], (filePath) => extraDependencies.add(filePath));
789
814
  cache.save({
790
815
  kind,
791
816
  namespace,
792
817
  name,
793
818
  sourceFile,
794
819
  content: code,
795
- dependencyPaths: getResult(),
820
+ dependencyPaths: [...getResult(), ...extraDependencies],
796
821
  contextHash
797
822
  });
798
823
  return code;
@@ -823,7 +848,12 @@ function createBundleCache(store) {
823
848
  const { kind, namespace, name, sourceFile, content, dependencyPaths, contextHash } = params;
824
849
  const cacheKey = buildCacheKey(kind, name, namespace);
825
850
  const allDeps = dependencyPaths.includes(sourceFile) ? dependencyPaths : [sourceFile, ...dependencyPaths];
826
- const inputHash = combineHash(hashFiles(allDeps), contextHash);
851
+ let inputHash;
852
+ try {
853
+ inputHash = combineHash(hashFiles(allDeps), contextHash);
854
+ } catch {
855
+ return;
856
+ }
827
857
  const contentHash = hashContent(content);
828
858
  store.storeBundleContent(cacheKey, content);
829
859
  store.setEntry(cacheKey, {
@@ -2032,7 +2062,7 @@ function transformStartCalls(source, startContext, currentFilePath) {
2032
2062
  transformedCall = `tailor.workflow.startWorkflow(${JSON.stringify(call.targetName)}, ${call.argsText || "undefined"}${optionsPart})`;
2033
2063
  } else {
2034
2064
  const optionsPart = call.optionsText !== void 0 ? `, ${call.optionsText}` : "";
2035
- transformedCall = `tailor.workflow.startJobFunction(${JSON.stringify(call.targetName)}, ${call.argsText || "undefined"}${optionsPart})`;
2065
+ transformedCall = `tailor.workflow.execJobFunction(${JSON.stringify(call.targetName)}, ${call.argsText || "undefined"}${optionsPart})`;
2036
2066
  }
2037
2067
  replacements.push({
2038
2068
  start: call.callRange.start,
@@ -2044,7 +2074,7 @@ function transformStartCalls(source, startContext, currentFilePath) {
2044
2074
  return needsNormalizerHelper && authNamespace ? buildNormalizerHelperSource(authNamespace) + transformed : transformed;
2045
2075
  }
2046
2076
  function createStartTransformPlugin(startContext) {
2047
- if (!startContext) return void 0;
2077
+ if (!startContext || startContext.modules.size === 0) return void 0;
2048
2078
  return {
2049
2079
  name: "start-transform",
2050
2080
  transform: {
@@ -2057,6 +2087,50 @@ function createStartTransformPlugin(startContext) {
2057
2087
  };
2058
2088
  }
2059
2089
 
2090
+ //#endregion
2091
+ //#region src/cli/shared/bundle-log.ts
2092
+ const ESCALATED_LOG_CODE = "UNRESOLVED_IMPORT";
2093
+ /**
2094
+ * Collect unresolved imports while keeping every other rolldown log suppressed.
2095
+ * @param options - Context used to explain which tsconfig was in effect
2096
+ * @returns Rolldown options and a post-build assertion
2097
+ */
2098
+ function createBundleLog(options = {}) {
2099
+ const unresolvedImports = /* @__PURE__ */ new Map();
2100
+ return {
2101
+ options: {
2102
+ logLevel: "warn",
2103
+ onLog: (_level, log) => {
2104
+ if (log.code !== ESCALATED_LOG_CODE) return;
2105
+ unresolvedImports.set(JSON.stringify([log.exporter, log.id]), log);
2106
+ }
2107
+ },
2108
+ assertAllResolved() {
2109
+ if (unresolvedImports.size > 0) throw unresolvedImportError([...unresolvedImports.values()], options.tsconfig);
2110
+ }
2111
+ };
2112
+ }
2113
+ function unresolvedImportError(logs, tsconfig) {
2114
+ const imports = logs.map(formatUnresolvedImport);
2115
+ return createCLIError({
2116
+ code: "UNRESOLVED_IMPORT",
2117
+ message: imports.length === 1 ? `Could not resolve ${imports[0]}.` : `Could not resolve ${imports.length} imports.`,
2118
+ details: imports.length === 1 ? void 0 : imports.map((item) => `- ${item}`).join("\n"),
2119
+ suggestion: unresolvedImportSuggestion(logs, tsconfig)
2120
+ });
2121
+ }
2122
+ function unresolvedImportSuggestion(logs, tsconfig) {
2123
+ const nodeSuggestions = logs.map((log) => log.exporter).filter((specifier) => specifier !== void 0).filter(isNodeBuiltinImport).map(getNodeBuiltinMessage);
2124
+ const hasOtherImports = logs.some((log) => log.exporter === void 0 || !isNodeBuiltinImport(log.exporter));
2125
+ const pathSuggestion = tsconfig ? `Check that each import path is correct, and that a \`compilerOptions.paths\` entry covering it is declared in the importing file's own tsconfig.json or an ancestor. The build used "${tsconfig}".` : "No tsconfig.json was found, so `compilerOptions.paths` aliases were not applied. Add a tsconfig.json declaring the aliases these files import.";
2126
+ return [.../* @__PURE__ */ new Set([...nodeSuggestions, ...hasOtherImports ? [pathSuggestion] : []])].join("\n");
2127
+ }
2128
+ function formatUnresolvedImport(log) {
2129
+ const specifier = log.exporter ?? "an imported module";
2130
+ const importerId = log.id?.startsWith("\0") ? `a generated entry (${log.id.slice(1)})` : log.id && `"${log.id}"`;
2131
+ return `"${specifier}"${importerId ? ` imported from ${importerId}` : ""}`;
2132
+ }
2133
+
2060
2134
  //#endregion
2061
2135
  //#region src/cli/shared/bundle-log-level.ts
2062
2136
  const INFO_LEVEL_CONSOLE_METHODS = [
@@ -2081,20 +2155,36 @@ const DEBUG_LEVEL_CONSOLE_METHODS = [
2081
2155
  ];
2082
2156
  const WARN_LEVEL_CONSOLE_METHODS = ["console.warn"];
2083
2157
  const ERROR_LEVEL_CONSOLE_METHODS = ["console.error"];
2158
+ const DEBUG_LEVEL_LOGGER_METHODS = ["globalThis.tailor.logger.debug"];
2159
+ const INFO_LEVEL_LOGGER_METHODS = ["globalThis.tailor.logger.info"];
2160
+ const WARN_LEVEL_LOGGER_METHODS = ["globalThis.tailor.logger.warn"];
2161
+ const ERROR_LEVEL_LOGGER_METHODS = ["globalThis.tailor.logger.error"];
2084
2162
  const MANUAL_PURE_FUNCTIONS_BY_LOG_LEVEL = {
2085
2163
  DEBUG: [],
2086
- INFO: DEBUG_LEVEL_CONSOLE_METHODS,
2087
- WARN: [...DEBUG_LEVEL_CONSOLE_METHODS, ...INFO_LEVEL_CONSOLE_METHODS],
2164
+ INFO: [...DEBUG_LEVEL_CONSOLE_METHODS, ...DEBUG_LEVEL_LOGGER_METHODS],
2165
+ WARN: [
2166
+ ...DEBUG_LEVEL_CONSOLE_METHODS,
2167
+ ...INFO_LEVEL_CONSOLE_METHODS,
2168
+ ...DEBUG_LEVEL_LOGGER_METHODS,
2169
+ ...INFO_LEVEL_LOGGER_METHODS
2170
+ ],
2088
2171
  ERROR: [
2089
2172
  ...DEBUG_LEVEL_CONSOLE_METHODS,
2090
2173
  ...INFO_LEVEL_CONSOLE_METHODS,
2091
- ...WARN_LEVEL_CONSOLE_METHODS
2174
+ ...WARN_LEVEL_CONSOLE_METHODS,
2175
+ ...DEBUG_LEVEL_LOGGER_METHODS,
2176
+ ...INFO_LEVEL_LOGGER_METHODS,
2177
+ ...WARN_LEVEL_LOGGER_METHODS
2092
2178
  ],
2093
2179
  SILENT: [
2094
2180
  ...DEBUG_LEVEL_CONSOLE_METHODS,
2095
2181
  ...INFO_LEVEL_CONSOLE_METHODS,
2096
2182
  ...WARN_LEVEL_CONSOLE_METHODS,
2097
- ...ERROR_LEVEL_CONSOLE_METHODS
2183
+ ...ERROR_LEVEL_CONSOLE_METHODS,
2184
+ ...DEBUG_LEVEL_LOGGER_METHODS,
2185
+ ...INFO_LEVEL_LOGGER_METHODS,
2186
+ ...WARN_LEVEL_LOGGER_METHODS,
2187
+ ...ERROR_LEVEL_LOGGER_METHODS
2098
2188
  ]
2099
2189
  };
2100
2190
  function normalizeBundleLogLevel(value) {
@@ -2145,6 +2235,13 @@ const platformBundleDefinePlugin = {
2145
2235
  transform(code) {
2146
2236
  if (!code.includes("process.env.__TAILOR_PLATFORM_BUNDLE")) return null;
2147
2237
  return { code: code.replace(GATE, "true") };
2238
+ },
2239
+ resolveId(source) {
2240
+ if (source === "node:async_hooks") return {
2241
+ id: source,
2242
+ external: true
2243
+ };
2244
+ return null;
2148
2245
  }
2149
2246
  };
2150
2247
 
@@ -2163,7 +2260,7 @@ async function resolveTSConfigWithFallback(baseDir) {
2163
2260
  const fallback = await tryResolve(process.cwd());
2164
2261
  if (fallback && !warnedBaseDirs.has(baseDir)) {
2165
2262
  warnedBaseDirs.add(baseDir);
2166
- logger.warn(`No tsconfig found from "${baseDir}"; falling back to the tsconfig resolved from process.cwd(). Move (or extend) a tsconfig into this config's own directory before v2, when this fallback will be removed.`);
2263
+ logger.warn(`No tsconfig found from "${baseDir}"; falling back to the tsconfig resolved from process.cwd(). Move (or extend) a tsconfig into this directory before v2, when this fallback will be removed.`);
2167
2264
  }
2168
2265
  return fallback;
2169
2266
  }
@@ -2175,6 +2272,83 @@ async function tryResolve(dir) {
2175
2272
  }
2176
2273
  }
2177
2274
 
2275
+ //#endregion
2276
+ //#region src/cli/shared/tsconfig-paths-plugin.ts
2277
+ /**
2278
+ * Create a {@link TsconfigLookupCache} to share across every bundle in a CLI run.
2279
+ * @returns A fresh, empty lookup cache
2280
+ */
2281
+ function createTsconfigLookupCache() {
2282
+ return {
2283
+ tsconfigCache: /* @__PURE__ */ new Map(),
2284
+ contextCache: /* @__PURE__ */ new Map()
2285
+ };
2286
+ }
2287
+ /**
2288
+ * Create the rolldown plugin that falls back to tsconfig `paths` aliases from
2289
+ * the importing file's own nearest tsconfig.
2290
+ * @param options - Resolution context for bundlers whose entry inlines user code
2291
+ * @returns Rolldown plugin to add to a bundler's plugin list
2292
+ */
2293
+ function createTsconfigPathsPlugin(options = {}) {
2294
+ const { tsconfigCache, contextCache } = options.cache ?? createTsconfigLookupCache();
2295
+ return {
2296
+ name: "tailor-tsconfig-paths",
2297
+ resolveId: {
2298
+ order: "post",
2299
+ async handler(source, importer) {
2300
+ if (!importer) return null;
2301
+ if (source.startsWith(".") || source.startsWith("/") || source.startsWith("\0")) return null;
2302
+ const resolutionBasis = importer.startsWith("\0") ? options.virtualEntrySourceFile : importer;
2303
+ if (!resolutionBasis) return null;
2304
+ const resolution = getResolutionContext(path.dirname(resolutionBasis), tsconfigCache, contextCache, options.onTsconfigRead);
2305
+ if (!resolution) return null;
2306
+ const candidates = resolution.matcher(source);
2307
+ if (candidates.length === 0) return null;
2308
+ if (await this.resolve(source, importer, { skipSelf: true })) return null;
2309
+ for (const candidate of candidates) {
2310
+ const resolved = await this.resolve(candidate, importer, { skipSelf: true });
2311
+ if (resolved) return resolved;
2312
+ }
2313
+ return null;
2314
+ }
2315
+ }
2316
+ };
2317
+ }
2318
+ function getResolutionContext(startDir, tsconfigCache, contextCache, onTsconfigRead) {
2319
+ const cached = contextCache.get(startDir);
2320
+ if (cached !== void 0) {
2321
+ reportTsconfigDependencies(tsconfigCache, onTsconfigRead);
2322
+ return cached;
2323
+ }
2324
+ const tsconfig = getTsconfig(startDir, "tsconfig.json", tsconfigCache);
2325
+ reportTsconfigDependencies(tsconfigCache, onTsconfigRead);
2326
+ const paths = tsconfig?.config.compilerOptions?.paths;
2327
+ const matcher = paths && Object.keys(paths).length > 0 ? createPathsMatcher(tsconfig) : null;
2328
+ const resolution = matcher ? { matcher } : null;
2329
+ contextCache.set(startDir, resolution);
2330
+ return resolution;
2331
+ }
2332
+ function reportTsconfigDependencies(cache, onTsconfigRead) {
2333
+ if (!onTsconfigRead) return;
2334
+ const directories = /* @__PURE__ */ new Set();
2335
+ const dependencies = /* @__PURE__ */ new Set();
2336
+ for (const [key, value] of cache) {
2337
+ const dependencyPath = dependencyPathFromCacheKey(key);
2338
+ if (!dependencyPath) continue;
2339
+ if (key.startsWith("statSync:") && isDirectoryStat(value)) directories.add(dependencyPath);
2340
+ else dependencies.add(dependencyPath);
2341
+ }
2342
+ for (const dependencyPath of dependencies) if (!directories.has(dependencyPath)) onTsconfigRead(dependencyPath);
2343
+ }
2344
+ function dependencyPathFromCacheKey(key) {
2345
+ if (key.startsWith("readFileSync:") && key.endsWith(":utf8")) return key.slice(13, -5);
2346
+ for (const prefix of ["existsSync:", "statSync:"]) if (key.startsWith(prefix)) return key.slice(prefix.length);
2347
+ }
2348
+ function isDirectoryStat(value) {
2349
+ return typeof value === "object" && value !== null && "isDirectory" in value && typeof value.isDirectory === "function" && value.isDirectory();
2350
+ }
2351
+
2178
2352
  //#endregion
2179
2353
  //#region src/cli/shared/virtual-entry.ts
2180
2354
  /**
@@ -2182,17 +2356,20 @@ async function tryResolve(dir) {
2182
2356
  * @param name - Logical entry name
2183
2357
  * @param code - Entry module source
2184
2358
  * @param sourceType - Parser type for the generated module
2359
+ * @param resolutionBasis - Source file whose directory resolves generated imports
2185
2360
  * @returns Rolldown input and plugin for loading the entry
2186
2361
  */
2187
- function createVirtualEntry(name, code, sourceType = "js") {
2188
- const input = `tailor-sdk-entry:${name}.${sourceType}`;
2362
+ function createVirtualEntry(name, code, sourceType = "js", resolutionBasis) {
2363
+ const input = `tailor-entry:${name}.${sourceType}`;
2189
2364
  const resolvedId = `\0${input}`;
2190
2365
  return {
2191
2366
  input,
2192
2367
  plugin: {
2193
- name: "tailor-sdk-virtual-entry",
2194
- resolveId(source, importer) {
2195
- return source === input && importer === void 0 ? resolvedId : null;
2368
+ name: "tailor-virtual-entry",
2369
+ async resolveId(source, importer) {
2370
+ if (source === input && importer === void 0) return resolvedId;
2371
+ if (importer !== resolvedId || !resolutionBasis || source.startsWith(".") || path.isAbsolute(source) || source.startsWith("\0")) return null;
2372
+ return this.resolve(source, resolutionBasis, { skipSelf: true });
2196
2373
  },
2197
2374
  load(id) {
2198
2375
  return id === resolvedId ? code : null;
@@ -2200,6 +2377,27 @@ function createVirtualEntry(name, code, sourceType = "js") {
2200
2377
  }
2201
2378
  };
2202
2379
  }
2380
+ /**
2381
+ * Resolve bare imports in a generated on-disk entry from its owning project.
2382
+ *
2383
+ * Generated entries live under the CLI output directory, which may be outside
2384
+ * the project selected by a config path. Resolving their injected dependencies
2385
+ * from that output directory would ignore the selected project's installation.
2386
+ * @param entryPath - Absolute path of the generated entry
2387
+ * @param projectDir - Directory whose dependencies the generated entry uses
2388
+ * @returns Rolldown plugin that rebases generated bare imports
2389
+ */
2390
+ function createGeneratedEntryResolverPlugin(entryPath, projectDir) {
2391
+ const normalizedEntryPath = path.resolve(entryPath);
2392
+ const resolutionBasis = path.join(path.resolve(projectDir), "__tailor_sdk_generated_entry__.js");
2393
+ return {
2394
+ name: "tailor-generated-entry-resolver",
2395
+ async resolveId(source, importer) {
2396
+ if (importer === void 0 || path.resolve(importer) !== normalizedEntryPath || source.startsWith(".") || path.isAbsolute(source) || source.startsWith("\0")) return null;
2397
+ return this.resolve(source, resolutionBasis, { skipSelf: true });
2398
+ }
2399
+ };
2400
+ }
2203
2401
 
2204
2402
  //#endregion
2205
2403
  //#region src/cli/services/auth/bundler.ts
@@ -2213,7 +2411,7 @@ function createVirtualEntry(name, code, sourceType = "js") {
2213
2411
  * @returns Map of function name to bundled code
2214
2412
  */
2215
2413
  async function bundleAuthHooks(options) {
2216
- const { configPath, authName, handlerAccessPath, env = {}, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG", baseDir } = options;
2414
+ const { configPath, authName, handlerAccessPath, env = {}, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG", baseDir, tsconfigCache } = options;
2217
2415
  logger.newline();
2218
2416
  logger.log(`Bundling auth hook for ${styles.info(`"${authName}"`)}`);
2219
2417
  const absoluteConfigPath = path.resolve(configPath);
@@ -2232,7 +2430,7 @@ async function bundleAuthHooks(options) {
2232
2430
  bundleLogLevel,
2233
2431
  prefix: JSON.stringify(Object.fromEntries(Object.entries(env).toSorted(([a], [b]) => a.localeCompare(b))))
2234
2432
  }),
2235
- async build(cachePlugins) {
2433
+ async build(cachePlugins, trackDependency) {
2236
2434
  const entryContent = multiline`
2237
2435
  import _config from "${absoluteConfigPath}";
2238
2436
  const __auth_hook_function = _config.${handlerAccessPath};
@@ -2241,12 +2439,16 @@ async function bundleAuthHooks(options) {
2241
2439
  return await __auth_hook_function({ ...args, env });
2242
2440
  }
2243
2441
  `;
2244
- const entry = createVirtualEntry(`auth-hook:${functionName}`, entryContent);
2442
+ const entry = createVirtualEntry(`auth-hook:${functionName}`, entryContent, "js", absoluteConfigPath);
2245
2443
  const startPlugin = createStartTransformPlugin(startContext);
2246
2444
  const plugins = [entry.plugin];
2247
2445
  if (startPlugin) plugins.push(startPlugin);
2248
- plugins.push(platformBundleDefinePlugin, ...cachePlugins);
2249
- return (await rolldown.build({
2446
+ plugins.push(createTsconfigPathsPlugin({
2447
+ onTsconfigRead: trackDependency,
2448
+ cache: tsconfigCache
2449
+ }), platformBundleDefinePlugin, ...cachePlugins);
2450
+ const bundleLog = createBundleLog({ tsconfig });
2451
+ const result = await rolldown.build({
2250
2452
  input: entry.input,
2251
2453
  write: false,
2252
2454
  output: {
@@ -2259,8 +2461,10 @@ async function bundleAuthHooks(options) {
2259
2461
  plugins,
2260
2462
  transform: { define: { "process.env.TAILOR_APP_LOG_LEVEL": JSON.stringify(bundleLogLevel) } },
2261
2463
  treeshake: composeFunctionTreeshakeOptions([createLogLevelTreeshakeOptions(bundleLogLevel)]),
2262
- logLevel: "silent"
2263
- })).output[0].code;
2464
+ ...bundleLog.options
2465
+ });
2466
+ bundleLog.assertAllResolved();
2467
+ return result.output[0].code;
2264
2468
  }
2265
2469
  });
2266
2470
  logger.log(`${styles.success("Bundled")} auth hook for ${styles.info(`"${authName}"`)}`);
@@ -3190,9 +3394,14 @@ async function bundleScriptTarget(args) {
3190
3394
  if (unresolved.length > 0) throw new Error(`${context} captures unresolvable variables (${unresolved.join(", ")}). Hooks and validators must not reference variables that cannot be resolved from the source file.
3191
3395
  ${kind}: ${fnSource}`);
3192
3396
  const entryContent = buildMinimalEntryFromResolved(imports, declarations, fnSource, sourceFilePath, kind === "typeValidate");
3193
- const entry = createVirtualEntry(`tailordb-script:${typeName}:${targetIndex}`, entryContent, "ts");
3194
- const bundledCode = (await rolldown.build({
3195
- plugins: [entry.plugin, platformBundleDefinePlugin],
3397
+ const entry = createVirtualEntry(`tailordb-script:${typeName}:${targetIndex}`, entryContent, "ts", sourceFilePath);
3398
+ const bundleLog = createBundleLog({ tsconfig });
3399
+ const buildResult = await rolldown.build({
3400
+ plugins: [
3401
+ entry.plugin,
3402
+ createTsconfigPathsPlugin({ virtualEntrySourceFile: sourceFilePath }),
3403
+ platformBundleDefinePlugin
3404
+ ],
3196
3405
  input: entry.input,
3197
3406
  write: false,
3198
3407
  output: {
@@ -3207,8 +3416,10 @@ async function bundleScriptTarget(args) {
3207
3416
  annotations: true,
3208
3417
  unknownGlobalSideEffects: false
3209
3418
  },
3210
- logLevel: "silent"
3211
- })).output[0].code;
3419
+ ...bundleLog.options
3420
+ });
3421
+ bundleLog.assertAllResolved();
3422
+ const bundledCode = buildResult.output[0].code;
3212
3423
  return assertParsableExpression(buildPrecompiledExpr(bundledCode, argsObject), context);
3213
3424
  }
3214
3425
  /**
@@ -3725,6 +3936,8 @@ function buildExecutorArgsExpr(triggerKind, env) {
3725
3936
  case "schedule": return `({ ...args, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, ${envExpr} })`;
3726
3937
  case "resolverExecuted": return `({ ...args, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, success: !!args.succeeded, result: args.succeeded?.result.resolver, error: args.failed?.error, ${envExpr} })`;
3727
3938
  case "incomingWebhook": return `({ ...args, appNamespace: args.namespaceName, rawBody: args.raw_body, ${envExpr} })`;
3939
+ case "workflowExecution":
3940
+ case "workflowJobExecution": return `({ ...args, event: args.eventType?.split(".").pop(), rawEvent: args.eventType, ${ACTOR_TRANSFORM_EXPR}, ...(args.succeeded ? { success: true } : args.failed ? { success: false, error: args.failed.error ?? "" } : {}), ${envExpr} })`;
3728
3941
  default: return `({ ...args, event: args.eventType?.split(".").pop(), rawEvent: args.eventType, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, ${envExpr} })`;
3729
3942
  }
3730
3943
  }
@@ -3742,6 +3955,112 @@ function buildExecutorArgsExpr(triggerKind, env) {
3742
3955
  function buildResolverOperationHookExpr(env) {
3743
3956
  return `({ ...context.pipeline, input: context.args, caller: ${tailorPrincipalMap}, env: ${JSON.stringify(env)} });`;
3744
3957
  }
3958
+ function isSingleResolverCondition(conditions) {
3959
+ return conditions.length === 3 && typeof conditions[1] === "string";
3960
+ }
3961
+ function resolverPermissionOperandExpr(operand) {
3962
+ if (typeof operand === "object") {
3963
+ if (operand.user === "_loggedIn") return `(context.caller !== null)`;
3964
+ if (operand.user === "id") return `context.caller?.id`;
3965
+ return `context.caller?.attributes?.[${JSON.stringify(operand.user)}]`;
3966
+ }
3967
+ return JSON.stringify(operand);
3968
+ }
3969
+ function isArbitraryAttributeOperand(operand) {
3970
+ return typeof operand === "object" && operand.user !== "_loggedIn";
3971
+ }
3972
+ function resolverPermissionConditionExpr(condition) {
3973
+ const [left, operator, right] = condition;
3974
+ const leftExpr = resolverPermissionOperandExpr(left);
3975
+ const rightExpr = resolverPermissionOperandExpr(right);
3976
+ if (operator === "!=") {
3977
+ const userOperandExpr = isArbitraryAttributeOperand(left) ? leftExpr : isArbitraryAttributeOperand(right) ? rightExpr : void 0;
3978
+ if (userOperandExpr) return `(${userOperandExpr} !== undefined && ${leftExpr} !== ${rightExpr})`;
3979
+ }
3980
+ return `(${leftExpr} ${operator === "=" ? "===" : "!=="} ${rightExpr})`;
3981
+ }
3982
+ function resolverPermissionPolicyExpr(policy) {
3983
+ const conditions = isSingleResolverCondition(policy.conditions) ? [policy.conditions] : policy.conditions;
3984
+ if (conditions.length === 0) throw new Error("Resolver permission policy must have at least one condition, got an empty array.");
3985
+ return conditions.map(resolverPermissionConditionExpr).join(" && ");
3986
+ }
3987
+ /**
3988
+ * Build a JS object literal capturing whether `policy` matched and its
3989
+ * (possibly empty) description, for runtime denial-reason attribution.
3990
+ * @param policy - The policy to compile
3991
+ * @returns A JS object literal expression: `{ matched, description }`
3992
+ */
3993
+ function policyEntryExpr(policy) {
3994
+ return `{ matched: ${resolverPermissionPolicyExpr(policy)}, description: ${JSON.stringify(policy.description ?? "")} }`;
3995
+ }
3996
+ /**
3997
+ * Build the permission guard statement injected at resolver entry.
3998
+ *
3999
+ * Rejects the call with `TailorErrorMessage` when the caller doesn't match
4000
+ * `permission`, evaluated against `context.caller` — the original caller,
4001
+ * unaffected by `authInvoker`. `permission` is deny-by-default: a caller is
4002
+ * granted only by a matching `permit: true` policy, and a matching
4003
+ * `permit: false` policy always overrides that grant. The thrown message only
4004
+ * includes the description(s) of the policy/policies that actually caused the
4005
+ * denial.
4006
+ *
4007
+ * The schema requires at least one `permit: true` policy (an array of only
4008
+ * `permit: false` policies is rejected at build time), so `allowPolicies` is
4009
+ * never empty here for schema-valid input; this function still handles that
4010
+ * case defensively since it also runs against test-authored raw shapes.
4011
+ * @param permission - The resolver's `permission` config
4012
+ * @returns A JS statement, or `undefined` when `permission` is omitted or `"allowAnonymous"`
4013
+ */
4014
+ function buildResolverPermissionGuardExpr(permission) {
4015
+ if (!permission || permission === "allowAnonymous") return;
4016
+ if (permission.length === 0) throw new Error("Resolver permission must have at least one policy, got an empty array.");
4017
+ const denyPolicies = permission.filter((policy) => policy.permit === false);
4018
+ const allowPolicies = permission.filter((policy) => policy.permit !== false);
4019
+ return `{
4020
+ const $denyPolicies = ${`[${denyPolicies.map(policyEntryExpr).join(", ")}]`};
4021
+ const $allowPolicies = ${`[${allowPolicies.map(policyEntryExpr).join(", ")}]`};
4022
+ const $matchedDeny = $denyPolicies.filter((p) => p.matched);
4023
+ const $anyAllowMatched = $allowPolicies.some((p) => p.matched);
4024
+ if ($matchedDeny.length > 0 || ($allowPolicies.length > 0 && !$anyAllowMatched)) {
4025
+ const $reasons = ($matchedDeny.length > 0 ? $matchedDeny : $allowPolicies)
4026
+ .map((p) => p.description)
4027
+ .filter(Boolean);
4028
+ throw new TailorErrorMessage($reasons.length > 0 ? "access denied: " + $reasons.join("; ") : "access denied");
4029
+ }
4030
+ }`;
4031
+ }
4032
+ /**
4033
+ * Build the permission guard and input-validation statements shared by every
4034
+ * resolver entry wrapper (production bundling and `function test-run`).
4035
+ *
4036
+ * Kept as a single generator so a resolver-wrapping behavior (like the
4037
+ * permission guard) can't be added to one entry-point template and forgotten
4038
+ * in the other. References `context.caller`, `context.input`, `invoker`, and
4039
+ * `_internalResolver` — the caller's wrapper must bind a `context` object
4040
+ * with `user`/`input` properties and an `invoker` binding (from
4041
+ * `INVOKER_EXPR`) before inlining this expression.
4042
+ * @param permission - The resolver's `permission` config
4043
+ * @returns A JS statement block to inline before calling `_internalResolver.body(...)`
4044
+ */
4045
+ function buildResolverPermissionAndInputCheckExpr(permission) {
4046
+ return `
4047
+ ${buildResolverPermissionGuardExpr(permission) ?? ""}
4048
+ if (_internalResolver.input) {
4049
+ const result = t.object(_internalResolver.input).parse({
4050
+ value: context.input,
4051
+ data: context.input,
4052
+ invoker,
4053
+ });
4054
+
4055
+ if (result.issues) {
4056
+ throw new TailorErrors(result.issues.map(issue => ({
4057
+ message: issue.message,
4058
+ path: issue.path ?? [],
4059
+ })));
4060
+ }
4061
+ }
4062
+ `;
4063
+ }
3745
4064
 
3746
4065
  //#endregion
3747
4066
  //#region src/cli/services/executor/bundler.ts
@@ -3756,7 +4075,7 @@ function buildResolverOperationHookExpr(env) {
3756
4075
  */
3757
4076
  async function bundleExecutors(options) {
3758
4077
  const bundledCode = /* @__PURE__ */ new Map();
3759
- const { config, startContext, additionalFiles = [], cache, inlineSourcemap, bundleLogLevel = "DEBUG", baseDir } = options;
4078
+ const { config, startContext, additionalFiles = [], cache, inlineSourcemap, bundleLogLevel = "DEBUG", baseDir, tsconfigCache } = options;
3760
4079
  const files = [...loadFilesWithIgnores(config, baseDir), ...additionalFiles];
3761
4080
  if (files.length === 0) {
3762
4081
  logger.warn(`No executor files found for patterns: ${config.files.join(", ")}`);
@@ -3785,12 +4104,12 @@ async function bundleExecutors(options) {
3785
4104
  return bundledCode;
3786
4105
  }
3787
4106
  const tsconfig = await resolveTSConfigWithFallback(baseDir);
3788
- const results = await withBundleConcurrency(executors, (executor) => bundleSingleExecutor(executor, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel));
4107
+ const results = await withBundleConcurrency(executors, (executor) => bundleSingleExecutor(executor, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel, tsconfigCache));
3789
4108
  for (const [name, code] of results) bundledCode.set(name, code);
3790
4109
  logger.log(`${styles.success("Bundled")} ${styles.info("\"executor\"")}`);
3791
4110
  return bundledCode;
3792
4111
  }
3793
- async function bundleSingleExecutor(executor, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
4112
+ async function bundleSingleExecutor(executor, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG", tsconfigCache) {
3794
4113
  const serializedStartContext = serializeStartContext(startContext);
3795
4114
  const contextHash = computeBundlerContextHash({
3796
4115
  sourceFile: executor.sourceFile,
@@ -3805,9 +4124,10 @@ async function bundleSingleExecutor(executor, tsconfig, startContext, cache, inl
3805
4124
  name: executor.name,
3806
4125
  sourceFile: executor.sourceFile,
3807
4126
  contextHash,
3808
- async build(cachePlugins) {
4127
+ async build(cachePlugins, trackDependency) {
4128
+ const absoluteSourcePath = path.resolve(executor.sourceFile);
3809
4129
  const entryContent = multiline`
3810
- import _internalExecutor from "${path.resolve(executor.sourceFile)}";
4130
+ import _internalExecutor from "${absoluteSourcePath}";
3811
4131
 
3812
4132
  const __executor_function = async (args) => {
3813
4133
  const invoker = ${INVOKER_EXPR};
@@ -3816,12 +4136,16 @@ async function bundleSingleExecutor(executor, tsconfig, startContext, cache, inl
3816
4136
 
3817
4137
  export { __executor_function as main };
3818
4138
  `;
3819
- const entry = createVirtualEntry(`executor:${executor.name}`, entryContent);
4139
+ const entry = createVirtualEntry(`executor:${executor.name}`, entryContent, "js", absoluteSourcePath);
3820
4140
  const startPlugin = createStartTransformPlugin(startContext);
3821
4141
  const plugins = [entry.plugin];
3822
4142
  if (startPlugin) plugins.push(startPlugin);
3823
- plugins.push(platformBundleDefinePlugin, ...cachePlugins);
3824
- return (await rolldown.build({
4143
+ plugins.push(createTsconfigPathsPlugin({
4144
+ onTsconfigRead: trackDependency,
4145
+ cache: tsconfigCache
4146
+ }), platformBundleDefinePlugin, ...cachePlugins);
4147
+ const bundleLog = createBundleLog({ tsconfig });
4148
+ const result = await rolldown.build({
3825
4149
  input: entry.input,
3826
4150
  write: false,
3827
4151
  output: {
@@ -3833,22 +4157,15 @@ async function bundleSingleExecutor(executor, tsconfig, startContext, cache, inl
3833
4157
  tsconfig,
3834
4158
  plugins,
3835
4159
  treeshake: composeFunctionTreeshakeOptions([createLogLevelTreeshakeOptions(bundleLogLevel)]),
3836
- logLevel: "silent"
3837
- })).output[0].code;
4160
+ ...bundleLog.options
4161
+ });
4162
+ bundleLog.assertAllResolved();
4163
+ return result.output[0].code;
3838
4164
  }
3839
4165
  });
3840
4166
  return [executor.name, code];
3841
4167
  }
3842
4168
 
3843
- //#endregion
3844
- //#region src/cli/services/http-adapter/node-builtins.ts
3845
- const NODE_BUILTINS = new Set(builtinModules.filter((m) => !m.startsWith("_")));
3846
- function isNodeBuiltinImport(source) {
3847
- if (source.startsWith("node:")) return true;
3848
- const root = source.includes("/") ? source.slice(0, source.indexOf("/")) : source;
3849
- return NODE_BUILTINS.has(root);
3850
- }
3851
-
3852
4169
  //#endregion
3853
4170
  //#region src/parser/service/http-adapter/methods.ts
3854
4171
  /**
@@ -3897,9 +4214,10 @@ const GRAPHQL_WEB_MODULE = createRequire(import.meta.url).resolve("@0no-co/graph
3897
4214
  * @param baseDir - Directory the owning config's tsconfig is resolved against
3898
4215
  * @param cache - Optional bundle cache for skipping unchanged builds
3899
4216
  * @param bundleLogLevel - Controls which console calls are kept in bundled code
4217
+ * @param tsconfigCache - Optional tsconfig lookup cache shared across bundles in this CLI run
3900
4218
  * @returns Bundled scripts keyed by adapter name
3901
4219
  */
3902
- async function bundleHttpAdapters(adapters, baseDir, cache, bundleLogLevel = "DEBUG") {
4220
+ async function bundleHttpAdapters(adapters, baseDir, cache, bundleLogLevel = "DEBUG", tsconfigCache) {
3903
4221
  if (adapters.length === 0) return {
3904
4222
  bundledInputs: /* @__PURE__ */ new Map(),
3905
4223
  bundledOutputs: /* @__PURE__ */ new Map()
@@ -3912,7 +4230,7 @@ async function bundleHttpAdapters(adapters, baseDir, cache, bundleLogLevel = "DE
3912
4230
  adapter,
3913
4231
  kind
3914
4232
  }));
3915
- }), ({ adapter, kind }) => bundleAdapterScript(adapter, kind, tsconfig, cache, bundleLogLevel));
4233
+ }), ({ adapter, kind }) => bundleAdapterScript(adapter, kind, tsconfig, cache, bundleLogLevel, tsconfigCache));
3916
4234
  const bundledInputs = /* @__PURE__ */ new Map();
3917
4235
  const bundledOutputs = /* @__PURE__ */ new Map();
3918
4236
  for (const [name, kind, code] of results) if (kind === "input") bundledInputs.set(name, code);
@@ -3923,7 +4241,7 @@ async function bundleHttpAdapters(adapters, baseDir, cache, bundleLogLevel = "DE
3923
4241
  bundledOutputs
3924
4242
  };
3925
4243
  }
3926
- async function bundleAdapterScript(adapter, kind, tsconfig, cache, bundleLogLevel = "DEBUG") {
4244
+ async function bundleAdapterScript(adapter, kind, tsconfig, cache, bundleLogLevel = "DEBUG", tsconfigCache) {
3927
4245
  const contextHash = computeBundlerContextHash({
3928
4246
  sourceFile: adapter.sourceFile,
3929
4247
  extraContext: kind === "input" ? adapter.methods.join(",") : "",
@@ -3938,16 +4256,16 @@ async function bundleAdapterScript(adapter, kind, tsconfig, cache, bundleLogLeve
3938
4256
  name: adapter.name,
3939
4257
  sourceFile: adapter.sourceFile,
3940
4258
  contextHash,
3941
- async build(cachePlugins) {
4259
+ async build(cachePlugins, trackDependency) {
3942
4260
  const absoluteSourcePath = path.resolve(adapter.sourceFile);
3943
4261
  const entryContent = kind === "input" ? buildInputEntry(absoluteSourcePath, adapter.methods, GRAPHQL_WEB_MODULE) : buildOutputEntry(absoluteSourcePath);
3944
- const entry = createVirtualEntry(`http-adapter:${adapter.name}:${kind}`, entryContent);
4262
+ const entry = createVirtualEntry(`http-adapter:${adapter.name}:${kind}`, entryContent, "js", absoluteSourcePath);
3945
4263
  const plugins = [
3946
4264
  entry.plugin,
3947
4265
  {
3948
4266
  name: "http-adapter-reject-node-imports",
3949
4267
  resolveId(source) {
3950
- if (isNodeBuiltinImport(source)) throw new Error(`HTTP adapter "${adapter.name}" imports Node module "${source}", which is unavailable in the gateway runtime`);
4268
+ if (isNodeBuiltinImport(source)) throw new Error(`HTTP adapter "${adapter.name}": ${getNodeBuiltinMessage(source)}`);
3951
4269
  return null;
3952
4270
  }
3953
4271
  },
@@ -3965,9 +4283,14 @@ async function bundleAdapterScript(adapter, kind, tsconfig, cache, bundleLogLeve
3965
4283
  return null;
3966
4284
  }
3967
4285
  },
4286
+ createTsconfigPathsPlugin({
4287
+ onTsconfigRead: trackDependency,
4288
+ cache: tsconfigCache
4289
+ }),
3968
4290
  ...cachePlugins
3969
4291
  ];
3970
- const bundled = (await rolldown.build({
4292
+ const bundleLog = createBundleLog({ tsconfig });
4293
+ const result = await rolldown.build({
3971
4294
  input: entry.input,
3972
4295
  write: false,
3973
4296
  output: {
@@ -3980,8 +4303,10 @@ async function bundleAdapterScript(adapter, kind, tsconfig, cache, bundleLogLeve
3980
4303
  plugins,
3981
4304
  transform: { target: "es2017" },
3982
4305
  treeshake: composeFunctionTreeshakeOptions([createLogLevelTreeshakeOptions(bundleLogLevel)]),
3983
- logLevel: "silent"
3984
- })).output[0].code;
4306
+ ...bundleLog.options
4307
+ });
4308
+ bundleLog.assertAllResolved();
4309
+ const bundled = result.output[0].code;
3985
4310
  const byteLength = Buffer.byteLength(bundled, "utf8");
3986
4311
  if (byteLength > ADAPTER_BUNDLE_ERROR_BYTES) throw new Error(`HTTP adapter "${adapter.name}" ${kind} script is ${byteLength} bytes, exceeding the ${ADAPTER_BUNDLE_ERROR_BYTES} byte limit`);
3987
4312
  if (byteLength > ADAPTER_BUNDLE_WARN_BYTES) logger.warn(`HTTP adapter "${adapter.name}" ${kind} script is ${byteLength} bytes, larger than the recommended ${ADAPTER_BUNDLE_WARN_BYTES} byte limit`);
@@ -4148,6 +4473,42 @@ function isAsyncFunction(fn) {
4148
4473
  //#endregion
4149
4474
  //#region src/parser/service/resolver/schema.ts
4150
4475
  const QueryTypeSchema = z.union([z.literal("query"), z.literal("mutation")]).describe("GraphQL operation type");
4476
+ const ResolverPermissionOperandSchema = z.union([
4477
+ z.strictObject({ user: z.string() }),
4478
+ z.string(),
4479
+ z.boolean()
4480
+ ]);
4481
+ const ResolverPermissionOperatorSchema = z.union([z.literal("="), z.literal("!=")]);
4482
+ const isUserOperand = (operand) => typeof operand === "object";
4483
+ const KNOWN_USER_OPERAND_TYPES = {
4484
+ _loggedIn: "boolean",
4485
+ id: "string"
4486
+ };
4487
+ const operandTypeMismatch = (userOperand, otherOperand) => {
4488
+ if (typeof userOperand !== "object") return;
4489
+ const expected = KNOWN_USER_OPERAND_TYPES[userOperand.user];
4490
+ if (expected === void 0 || typeof otherOperand === "object" || typeof otherOperand === expected) return;
4491
+ return {
4492
+ key: userOperand.user,
4493
+ expected
4494
+ };
4495
+ };
4496
+ const ResolverPermissionConditionSchema = z.tuple([
4497
+ ResolverPermissionOperandSchema,
4498
+ ResolverPermissionOperatorSchema,
4499
+ ResolverPermissionOperandSchema
4500
+ ]).refine(([left, , right]) => isUserOperand(left) !== isUserOperand(right), "Resolver permission condition must reference a `user` operand on exactly one side (comparing two `user` operands to each other can match on `undefined === undefined`)").superRefine(([left, , right], ctx) => {
4501
+ for (const mismatch of [operandTypeMismatch(left, right), operandTypeMismatch(right, left)]) if (mismatch) ctx.addIssue({
4502
+ code: "custom",
4503
+ message: `\`${mismatch.key}\` must compare to a ${mismatch.expected}`
4504
+ });
4505
+ }).readonly();
4506
+ const ResolverPermissionPolicySchema = z.strictObject({
4507
+ conditions: z.union([ResolverPermissionConditionSchema, z.array(ResolverPermissionConditionSchema).min(1, "Resolver permission policy must have at least one condition").readonly()]),
4508
+ permit: z.boolean(),
4509
+ description: z.string().optional().describe("Reason recorded for this policy, used in the access-denied error message")
4510
+ });
4511
+ const ResolverPermissionSchema = z.union([z.array(ResolverPermissionPolicySchema).min(1, "Resolver permission must have at least one policy").refine((policies) => policies.some((policy) => policy.permit === true), "Resolver permission must include at least one `permit: true` policy — a policy array with only `permit: false` policies still lets any caller through by simply not authenticating, since none of the deny conditions apply to a caller with no user attributes at all").readonly(), z.literal("allowAnonymous")]).describe("Access requirement for this resolver, evaluated against the original caller (unaffected by `invoker`) before `body` runs. \"allowAnonymous\" documents that anonymous callers are allowed. Omitted (default): unchanged, anonymous callers can reach the resolver");
4151
4512
  const ResolverSchema = z.strictObject({
4152
4513
  operation: QueryTypeSchema.describe("GraphQL operation type (query or mutation)"),
4153
4514
  name: z.string().describe("Resolver name"),
@@ -4156,7 +4517,8 @@ const ResolverSchema = z.strictObject({
4156
4517
  body: functionSchema.describe("Resolver implementation function"),
4157
4518
  output: TailorFieldSchema.describe("Output field definition"),
4158
4519
  publishEvents: z.boolean().optional().describe("Enable publishing events from this resolver"),
4159
- invoker: AuthInvokerSchema.optional().describe("Machine user to execute this resolver as")
4520
+ invoker: AuthInvokerSchema.optional().describe("Machine user to execute this resolver as"),
4521
+ permission: ResolverPermissionSchema.optional()
4160
4522
  });
4161
4523
 
4162
4524
  //#endregion
@@ -4189,9 +4551,10 @@ async function loadResolver(resolverFilePath) {
4189
4551
  * @param cache - Optional bundle cache for skipping unchanged builds
4190
4552
  * @param inlineSourcemap - Whether to enable inline sourcemaps
4191
4553
  * @param bundleLogLevel - Controls which console calls are kept in bundled code
4554
+ * @param tsconfigCache - Optional tsconfig lookup cache shared across bundles in this CLI run
4192
4555
  * @returns Map of resolver name to bundled code
4193
4556
  */
4194
- async function bundleResolvers(namespace, config, baseDir, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
4557
+ async function bundleResolvers(namespace, config, baseDir, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG", tsconfigCache) {
4195
4558
  const bundledCode = /* @__PURE__ */ new Map();
4196
4559
  const files = loadFilesWithIgnores(config, baseDir);
4197
4560
  if (files.length === 0) {
@@ -4209,16 +4572,17 @@ async function bundleResolvers(namespace, config, baseDir, startContext, cache,
4209
4572
  }
4210
4573
  resolvers.push({
4211
4574
  name: resolver.name,
4212
- sourceFile: file
4575
+ sourceFile: file,
4576
+ permission: resolver.permission
4213
4577
  });
4214
4578
  }
4215
4579
  const tsconfig = await resolveTSConfigWithFallback(baseDir);
4216
- const results = await withBundleConcurrency(resolvers, (resolver) => bundleSingleResolver(namespace, resolver, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel));
4580
+ const results = await withBundleConcurrency(resolvers, (resolver) => bundleSingleResolver(namespace, resolver, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel, tsconfigCache));
4217
4581
  for (const [name, code] of results) bundledCode.set(name, code);
4218
4582
  logger.log(`${styles.success("Bundled")} ${styles.info(`"${namespace}"`)}`);
4219
4583
  return bundledCode;
4220
4584
  }
4221
- async function bundleSingleResolver(namespace, resolver, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
4585
+ async function bundleSingleResolver(namespace, resolver, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG", tsconfigCache) {
4222
4586
  const serializedStartContext = serializeStartContext(startContext);
4223
4587
  const contextHash = computeBundlerContextHash({
4224
4588
  sourceFile: resolver.sourceFile,
@@ -4234,39 +4598,30 @@ async function bundleSingleResolver(namespace, resolver, tsconfig, startContext,
4234
4598
  name: resolver.name,
4235
4599
  sourceFile: resolver.sourceFile,
4236
4600
  contextHash,
4237
- async build(cachePlugins) {
4601
+ async build(cachePlugins, trackDependency) {
4602
+ const absoluteSourcePath = path.resolve(resolver.sourceFile);
4238
4603
  const entryContent = multiline`
4239
- import _internalResolver from "${path.resolve(resolver.sourceFile)}";
4604
+ import _internalResolver from "${absoluteSourcePath}";
4240
4605
  import { t } from "@tailor-platform/sdk";
4241
4606
 
4242
4607
  const $tailor_resolver_body = async (context) => {
4243
4608
  const invoker = ${INVOKER_EXPR};
4244
- if (_internalResolver.input) {
4245
- const result = t.object(_internalResolver.input).parse({
4246
- value: context.input,
4247
- data: context.input,
4248
- invoker,
4249
- });
4250
-
4251
- if (result.issues) {
4252
- throw new TailorErrors(result.issues.map(issue => ({
4253
- message: issue.message,
4254
- path: issue.path ?? [],
4255
- })));
4256
- }
4257
- }
4258
-
4609
+ ${buildResolverPermissionAndInputCheckExpr(resolver.permission)}
4259
4610
  return _internalResolver.body({ ...context, invoker });
4260
4611
  };
4261
4612
 
4262
4613
  export { $tailor_resolver_body as main };
4263
4614
  `;
4264
- const entry = createVirtualEntry(`resolver:${resolver.name}`, entryContent);
4615
+ const entry = createVirtualEntry(`resolver:${resolver.name}`, entryContent, "js", absoluteSourcePath);
4265
4616
  const startPlugin = createStartTransformPlugin(startContext);
4266
4617
  const plugins = [entry.plugin];
4267
4618
  if (startPlugin) plugins.push(startPlugin);
4268
- plugins.push(platformBundleDefinePlugin, ...cachePlugins);
4269
- return (await rolldown.build({
4619
+ plugins.push(createTsconfigPathsPlugin({
4620
+ onTsconfigRead: trackDependency,
4621
+ cache: tsconfigCache
4622
+ }), platformBundleDefinePlugin, ...cachePlugins);
4623
+ const bundleLog = createBundleLog({ tsconfig });
4624
+ const result = await rolldown.build({
4270
4625
  input: entry.input,
4271
4626
  write: false,
4272
4627
  output: {
@@ -4278,8 +4633,10 @@ async function bundleSingleResolver(namespace, resolver, tsconfig, startContext,
4278
4633
  tsconfig,
4279
4634
  plugins,
4280
4635
  treeshake: composeFunctionTreeshakeOptions([createLogLevelTreeshakeOptions(bundleLogLevel)]),
4281
- logLevel: "silent"
4282
- })).output[0].code;
4636
+ ...bundleLog.options
4637
+ });
4638
+ bundleLog.assertAllResolved();
4639
+ return result.output[0].code;
4283
4640
  }
4284
4641
  });
4285
4642
  return [resolver.name, code];
@@ -4479,9 +4836,10 @@ function safeRealpath(p) {
4479
4836
  * @param cache - Optional bundle cache for skipping unchanged builds
4480
4837
  * @param inlineSourcemap - Whether to enable inline sourcemaps
4481
4838
  * @param bundleLogLevel - Controls which console calls are kept in bundled code
4839
+ * @param tsconfigCache - Optional tsconfig lookup cache shared across bundles in this CLI run
4482
4840
  * @returns Workflow job bundling result
4483
4841
  */
4484
- async function bundleWorkflowJobs(allJobs, mainJobNames, env = {}, startContext, baseDir, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
4842
+ async function bundleWorkflowJobs(allJobs, mainJobNames, env = {}, startContext, baseDir, cache, inlineSourcemap, bundleLogLevel = "DEBUG", tsconfigCache) {
4485
4843
  if (allJobs.length === 0) {
4486
4844
  logger.warn("No workflow jobs to bundle");
4487
4845
  return {
@@ -4494,7 +4852,7 @@ async function bundleWorkflowJobs(allJobs, mainJobNames, env = {}, startContext,
4494
4852
  logger.newline();
4495
4853
  logger.log(`Bundling ${styles.highlight(usedJobs.length.toString())} files for ${styles.info("\"workflow-job\"")}`);
4496
4854
  const tsconfig = await resolveTSConfigWithFallback(baseDir);
4497
- const results = await withBundleConcurrency(usedJobs, (job) => bundleSingleJob(job, usedJobs, tsconfig, env, startContext, cache, inlineSourcemap, bundleLogLevel));
4855
+ const results = await withBundleConcurrency(usedJobs, (job) => bundleSingleJob(job, usedJobs, tsconfig, env, startContext, cache, inlineSourcemap, bundleLogLevel, tsconfigCache));
4498
4856
  const bundledCode = /* @__PURE__ */ new Map();
4499
4857
  for (const [name, code] of results) bundledCode.set(name, code);
4500
4858
  logger.log(`${styles.success("Bundled")} ${styles.info("\"workflow-job\"")}`);
@@ -4570,7 +4928,7 @@ async function filterUsedJobs(allJobs, mainJobNames, startContext) {
4570
4928
  mainJobDeps
4571
4929
  };
4572
4930
  }
4573
- async function bundleSingleJob(job, allJobs, tsconfig, env, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
4931
+ async function bundleSingleJob(job, allJobs, tsconfig, env, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG", tsconfigCache) {
4574
4932
  const serializedStartContext = serializeStartContext(startContext);
4575
4933
  const sortedEnvPrefix = JSON.stringify(Object.fromEntries(Object.entries(env).toSorted(([a], [b]) => a.localeCompare(b))));
4576
4934
  const contextHash = computeBundlerContextHash({
@@ -4587,7 +4945,7 @@ async function bundleSingleJob(job, allJobs, tsconfig, env, startContext, cache,
4587
4945
  name: job.name,
4588
4946
  sourceFile: job.sourceFile,
4589
4947
  contextHash,
4590
- async build(cachePlugins) {
4948
+ async build(cachePlugins, trackDependency) {
4591
4949
  const absoluteSourcePath = path.resolve(job.sourceFile);
4592
4950
  const entryContent = multiline`
4593
4951
  import { ${job.exportName} } from "${absoluteSourcePath}";
@@ -4598,7 +4956,7 @@ async function bundleSingleJob(job, allJobs, tsconfig, env, startContext, cache,
4598
4956
  return await ${job.exportName}.body(input, { env, invoker });
4599
4957
  }
4600
4958
  `;
4601
- const entry = createVirtualEntry(`workflow-job:${job.name}`, entryContent);
4959
+ const entry = createVirtualEntry(`workflow-job:${job.name}`, entryContent, "js", absoluteSourcePath);
4602
4960
  const resolvedSourceFile = safeRealpath(job.sourceFile);
4603
4961
  const otherJobExportNames = allJobs.filter((candidate) => candidate.name !== job.name && safeRealpath(candidate.sourceFile) === resolvedSourceFile).map((j) => j.exportName);
4604
4962
  const plugins = [
@@ -4617,10 +4975,15 @@ async function bundleSingleJob(job, allJobs, tsconfig, env, startContext, cache,
4617
4975
  }
4618
4976
  }
4619
4977
  },
4978
+ createTsconfigPathsPlugin({
4979
+ onTsconfigRead: trackDependency,
4980
+ cache: tsconfigCache
4981
+ }),
4620
4982
  platformBundleDefinePlugin,
4621
4983
  ...cachePlugins
4622
4984
  ];
4623
- return (await rolldown.build({
4985
+ const bundleLog = createBundleLog({ tsconfig });
4986
+ const result = await rolldown.build({
4624
4987
  input: entry.input,
4625
4988
  write: false,
4626
4989
  output: {
@@ -4632,8 +4995,10 @@ async function bundleSingleJob(job, allJobs, tsconfig, env, startContext, cache,
4632
4995
  tsconfig,
4633
4996
  plugins,
4634
4997
  treeshake: composeFunctionTreeshakeOptions([createLogLevelTreeshakeOptions(bundleLogLevel)]),
4635
- logLevel: "silent"
4636
- })).output[0].code;
4998
+ ...bundleLog.options
4999
+ });
5000
+ bundleLog.assertAllResolved();
5001
+ return result.output[0].code;
4637
5002
  }
4638
5003
  });
4639
5004
  return [job.name, code];
@@ -4644,7 +5009,8 @@ async function bundleSingleJob(job, allJobs, tsconfig, env, startContext, cache,
4644
5009
  const WorkflowJobSchema = z.strictObject({
4645
5010
  name: z.string().describe("Job name (must be unique across the project)"),
4646
5011
  start: functionSchema.describe("Start function that initiates the job"),
4647
- body: functionSchema.describe("Job implementation function")
5012
+ body: functionSchema.describe("Job implementation function"),
5013
+ publishEvents: z.boolean().optional().describe("Enable publishing job execution events for this job")
4648
5014
  });
4649
5015
  const durationUnits = [
4650
5016
  "ms",
@@ -4680,7 +5046,7 @@ const RetryPolicySchema = z.strictObject({
4680
5046
  });
4681
5047
  const ConcurrencyPolicySchema = z.strictObject({ maxConcurrentExecutions: z.number().int().min(1).max(1e3).describe("Maximum number of concurrent executions (1-1000)") });
4682
5048
  const ExecutionPolicyNameSchema = z.string().regex(/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/, "Invalid execution policy name: must match [a-z0-9-] (3-63 chars; must start and end with [a-z0-9])").describe("Workspace-unique execution policy name embedded in the resource TRN");
4683
- const ExecutionPolicyKeySchema = z.string().regex(/^[a-z0-9][a-z0-9_:.-]{0,62}[a-z0-9*]$/, "Invalid execution policy key: must match [a-z0-9_:.-] (2-64 chars; must start with [a-z0-9] and end with [a-z0-9] or a trailing '*')").describe("Execution policy key passed to startJobFunction's executionPolicyKey option");
5049
+ const ExecutionPolicyKeySchema = z.string().regex(/^[a-z0-9][a-z0-9_:.-]{0,62}[a-z0-9*]$/, "Invalid execution policy key: must match [a-z0-9_:.-] (2-64 chars; must start with [a-z0-9] and end with [a-z0-9] or a trailing '*')").describe("Execution policy key passed to execJobFunction's executionPolicyKey option");
4684
5050
  const WorkflowJobFunctionExecutionPolicySchema = z.strictObject({
4685
5051
  name: ExecutionPolicyNameSchema,
4686
5052
  key: ExecutionPolicyKeySchema,
@@ -4690,7 +5056,8 @@ const WorkflowSchema = z.strictObject({
4690
5056
  name: z.string().describe("Workflow name"),
4691
5057
  mainJob: WorkflowJobSchema.describe("Main job that starts the workflow"),
4692
5058
  retryPolicy: RetryPolicySchema.optional().describe("Retry policy for the workflow"),
4693
- concurrencyPolicy: ConcurrencyPolicySchema.optional().describe("Concurrency policy for the workflow")
5059
+ concurrencyPolicy: ConcurrencyPolicySchema.optional().describe("Concurrency policy for the workflow"),
5060
+ publishEvents: z.boolean().optional().describe("Enable publishing workflow execution events for this workflow")
4694
5061
  });
4695
5062
 
4696
5063
  //#endregion
@@ -4817,7 +5184,8 @@ async function loadFileContent(filePath) {
4817
5184
  if (jobResult.success) jobs.push({
4818
5185
  name: jobResult.data.name,
4819
5186
  exportName,
4820
- sourceFile: filePath
5187
+ sourceFile: filePath,
5188
+ ...jobResult.data.publishEvents !== void 0 ? { publishEvents: jobResult.data.publishEvents } : {}
4821
5189
  });
4822
5190
  else if (isSdkBranded(exportValue, ["workflow", "workflow-job"])) throw jobResult.error;
4823
5191
  }
@@ -5044,7 +5412,7 @@ const IdPSchema = z.strictObject({
5044
5412
  clients: z.array(z.string()).describe("OAuth2 client names that can use this IdP"),
5045
5413
  lang: IdPLangSchema.optional().describe("UI language for IdP pages"),
5046
5414
  userAuthPolicy: IdPUserAuthPolicySchema.transform((input) => IdPUserAuthPolicySchema.parse(input ?? {})).optional().describe("User authentication policy configuration"),
5047
- publishUserEvents: z.boolean().optional().describe("Enable publishing user lifecycle events"),
5415
+ publishEvents: z.boolean().optional().describe("Enable publishing user lifecycle events"),
5048
5416
  gqlOperations: IdPGqlOperationsSchema.optional().describe("Configure which GraphQL operations are enabled"),
5049
5417
  emailConfig: IdPEmailConfigSchema.optional().describe("Namespace-level email configuration defaults"),
5050
5418
  permission: IdPPermissionSchema.optional().describe("Per-operation permission policies for IdP users")
@@ -5375,6 +5743,7 @@ async function loadApplication(params) {
5375
5743
  }), baseDir);
5376
5744
  const inlineSourcemap = resolveInlineSourcemap(config.inlineSourcemap);
5377
5745
  const bundleLogLevel = resolveBundleLogLevel(config.logLevel);
5746
+ const tsconfigCache = createTsconfigLookupCache();
5378
5747
  const bundledScripts = {
5379
5748
  resolvers: /* @__PURE__ */ new Map(),
5380
5749
  executors: /* @__PURE__ */ new Map(),
@@ -5382,7 +5751,7 @@ async function loadApplication(params) {
5382
5751
  authHooks: /* @__PURE__ */ new Map()
5383
5752
  };
5384
5753
  for (const pipeline of resolverResult.resolverServices) {
5385
- const resolverBundles = await bundleResolvers(pipeline.namespace, pipeline.config, baseDir, startContext, bundleCache, inlineSourcemap, bundleLogLevel);
5754
+ const resolverBundles = await bundleResolvers(pipeline.namespace, pipeline.config, baseDir, startContext, bundleCache, inlineSourcemap, bundleLogLevel, tsconfigCache);
5386
5755
  for (const [name, code] of resolverBundles) bundledScripts.resolvers.set(resolverBundleKey(pipeline.namespace, name), code);
5387
5756
  }
5388
5757
  if (executorService) bundledScripts.executors = await bundleExecutors({
@@ -5392,12 +5761,13 @@ async function loadApplication(params) {
5392
5761
  cache: bundleCache,
5393
5762
  inlineSourcemap,
5394
5763
  bundleLogLevel,
5395
- baseDir
5764
+ baseDir,
5765
+ tsconfigCache
5396
5766
  });
5397
5767
  let workflowBuildResult;
5398
5768
  if (workflowService && workflowService.jobs.length > 0) {
5399
5769
  const mainJobNames = workflowService.workflowSources.map((ws) => ws.workflow.mainJob.name);
5400
- workflowBuildResult = await bundleWorkflowJobs(workflowService.jobs, mainJobNames, config.env ?? {}, startContext, baseDir, bundleCache, inlineSourcemap, bundleLogLevel);
5770
+ workflowBuildResult = await bundleWorkflowJobs(workflowService.jobs, mainJobNames, config.env ?? {}, startContext, baseDir, bundleCache, inlineSourcemap, bundleLogLevel, tsconfigCache);
5401
5771
  bundledScripts.workflowJobs = workflowBuildResult.bundledCode;
5402
5772
  }
5403
5773
  let httpAdapterBuildResult;
@@ -5406,7 +5776,7 @@ async function loadApplication(params) {
5406
5776
  sourceFile: a.sourceFile,
5407
5777
  methods: a.methods,
5408
5778
  hasOutput: a.hasOutput
5409
- })), baseDir, bundleCache, bundleLogLevel);
5779
+ })), baseDir, bundleCache, bundleLogLevel, tsconfigCache);
5410
5780
  if (authResult.authService?.config.hooks?.beforeLogin) {
5411
5781
  const authName = authResult.authService.config.name;
5412
5782
  bundledScripts.authHooks = await bundleAuthHooks({
@@ -5418,7 +5788,8 @@ async function loadApplication(params) {
5418
5788
  cache: bundleCache,
5419
5789
  inlineSourcemap,
5420
5790
  bundleLogLevel,
5421
- baseDir
5791
+ baseDir,
5792
+ tsconfigCache
5422
5793
  });
5423
5794
  }
5424
5795
  for (const pipeline of resolverResult.resolverServices) await pipeline.loadResolvers();
@@ -5452,5 +5823,5 @@ async function loadApplication(params) {
5452
5823
  }
5453
5824
 
5454
5825
  //#endregion
5455
- export { fetchAllTolerant as A, initOperatorClient as B, createBundleCache as C, closeConnectionPool as D, hashFile as E, getConsoleBaseUrl as F, byName as G, normalizeBaseUrl as H, getOAuth2ClientId as I, LOG_LEVELS as K, getOrNull as L, fetchPaged as M, fetchPlatformMachineUserToken as N, defaultPlatformBaseUrl as O, fetchUserInfo as P, getPlatformBaseUrl as R, hasGenerationHooks as S, hashContent as T, rememberPlatformConfigForToken as U, isDefaultPlatform as V, resolveStaticWebsiteUrls as W, platformBundleDefinePlugin as _, resolveInlineSourcemap as a, resolveBundleLogLevel as b, WorkflowJobSchema as c, INVOKER_EXPR as d, buildExecutorArgsExpr as f, stringifyFunction as g, assertUniqueTailorDBTypeNamesWithExternal as h, resolverBundleKey as i, fetchMachineUserToken as j, fetchAll as k, ResolverSchema as l, assertUniqueLocalTailorDBTypeNames as m, generatePluginFilesIfNeeded as n, getApplicationAuthNamespace as o, buildResolverOperationHookExpr as p, loadApplication as r, WorkflowJobFunctionExecutionPolicySchema as s, defineApplication as t, HTTP_METHODS as u, composeFunctionTreeshakeOptions as v, getDistDir as w, getPluginGenerationDependencies as x, createLogLevelTreeshakeOptions as y, initOAuth2Client as z };
5456
- //# sourceMappingURL=application-D_oSqto2.mjs.map
5826
+ export { LOG_LEVELS as $, hashContent as A, getConsoleBaseUrl as B, createLogLevelTreeshakeOptions as C, hasGenerationHooks as D, getPluginGenerationDependencies as E, fetchAllTolerant as F, initOperatorClient as G, getOrNull as H, fetchMachineUserToken as I, normalizeBaseUrl as J, isDefaultPlatform as K, fetchPaged as L, closeConnectionPool as M, defaultPlatformBaseUrl as N, createBundleCache as O, fetchAll as P, createApplyLimiter as Q, fetchPlatformMachineUserToken as R, composeFunctionTreeshakeOptions as S, createBundleLog as T, getPlatformBaseUrl as U, getOAuth2ClientId as V, initOAuth2Client as W, resolveStaticWebsiteUrls as X, rememberPlatformConfigForToken as Y, byName as Z, stringifyFunction as _, resolveInlineSourcemap as a, resolveTSConfigWithFallback as b, WorkflowJobSchema as c, INVOKER_EXPR as d, buildExecutorArgsExpr as f, assertUniqueTailorDBTypeNamesWithExternal as g, assertUniqueLocalTailorDBTypeNames as h, resolverBundleKey as i, hashFile as j, getDistDir as k, ResolverSchema as l, buildResolverPermissionAndInputCheckExpr as m, generatePluginFilesIfNeeded as n, getApplicationAuthNamespace as o, buildResolverOperationHookExpr as p, isNotFoundError as q, loadApplication as r, WorkflowJobFunctionExecutionPolicySchema as s, defineApplication as t, HTTP_METHODS as u, createGeneratedEntryResolverPlugin as v, resolveBundleLogLevel as w, platformBundleDefinePlugin as x, createTsconfigPathsPlugin as y, fetchUserInfo as z };
5827
+ //# sourceMappingURL=application-CM6hKnSK.mjs.map