@tailor-platform/sdk 2.0.0-next.5 → 2.0.0-next.7

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 (129) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/dist/{application-Bf8wxOi6.mjs → application-GzW98_Xr.mjs} +377 -1418
  3. package/dist/application-GzW98_Xr.mjs.map +1 -0
  4. package/dist/application-OM0taSPn.mjs +3 -0
  5. package/dist/cli/commands/deploy/deploy.d.mts +8 -3
  6. package/dist/cli/commands/generate/options.d.mts +0 -1
  7. package/dist/cli/commands/generate/service.d.mts +1 -1
  8. package/dist/cli/commands/staticwebsite/deploy.d.mts +19 -0
  9. package/dist/cli/commands/workspace/create.d.mts +3 -0
  10. package/dist/cli/commands/workspace/list.d.mts +1 -0
  11. package/dist/cli/commands/workspace/transform.d.mts +2 -0
  12. package/dist/cli/index.mjs +781 -1553
  13. package/dist/cli/index.mjs.map +1 -1
  14. package/dist/cli/lib.d.mts +7 -3
  15. package/dist/cli/lib.mjs +49 -3
  16. package/dist/cli/lib.mjs.map +1 -1
  17. package/dist/cli/shared/config-loader.d.mts +1 -1
  18. package/dist/cli/shared/readonly-guard.d.mts +25 -0
  19. package/dist/cli/shared/tailordb-namespaces.d.mts +37 -0
  20. package/dist/cli/shared/workspace-name.d.mts +1 -0
  21. package/dist/completion/zsh-worker.zsh +15 -303
  22. package/dist/configure/config/types.d.mts +5 -1
  23. package/dist/configure/index.mjs +20 -19
  24. package/dist/configure/index.mjs.map +1 -1
  25. package/dist/configure/services/auth/types.d.mts +18 -23
  26. package/dist/configure/services/executor/executor.d.mts +2 -13
  27. package/dist/configure/services/executor/operation.d.mts +8 -3
  28. package/dist/configure/services/tailordb/schema.d.mts +1 -7
  29. package/dist/configure/services/tailordb/types.d.mts +1 -1
  30. package/dist/configure/services/workflow/execution-policy.d.mts +2 -2
  31. package/dist/configure/services/workflow/job.d.mts +10 -10
  32. package/dist/configure/services/workflow/workflow.d.mts +6 -4
  33. package/dist/configure/types/type.d.mts +1 -9
  34. package/dist/{crashreport-D3RjuSYb.mjs → crashreport-0ioNRZ4K.mjs} +1 -1
  35. package/dist/{crashreport-Cg-pqRJV.mjs → crashreport-CxHne11E.mjs} +4 -3
  36. package/dist/{crashreport-Cg-pqRJV.mjs.map → crashreport-CxHne11E.mjs.map} +1 -1
  37. package/dist/errors-DfnF4ibq.mjs +100 -0
  38. package/dist/errors-DfnF4ibq.mjs.map +1 -0
  39. package/dist/{globals-BjhJJ2dN.mjs → globals-CBZ0egXT.mjs} +13 -10
  40. package/dist/globals-CBZ0egXT.mjs.map +1 -0
  41. package/dist/{logger-BEiZZ3qT.mjs → logger-BwS4ppwO.mjs} +3 -3
  42. package/dist/logger-BwS4ppwO.mjs.map +1 -0
  43. package/dist/parser/service/tailordb/type-source.d.mts +10 -0
  44. package/dist/{register-ts-hook-BhzVkej0.mjs → register-ts-hook-DvEs6YsL.mjs} +2571 -1636
  45. package/dist/register-ts-hook-DvEs6YsL.mjs.map +1 -0
  46. package/dist/{registry-BSbq6SPo.mjs → registry-i7EdJ-D5.mjs} +10 -10
  47. package/dist/registry-i7EdJ-D5.mjs.map +1 -0
  48. package/dist/runtime/field-parse.d.mts +10 -0
  49. package/dist/runtime/globals.d.mts +3 -3
  50. package/dist/runtime/index.mjs +1 -1
  51. package/dist/runtime/workflow.d.mts +18 -33
  52. package/dist/runtime/workflow.mjs +1 -1
  53. package/dist/{schema-iCd1ugGp.mjs → schema--xYWRGfe.mjs} +42 -24
  54. package/dist/schema--xYWRGfe.mjs.map +1 -0
  55. package/dist/{secret-file-aoNXJmKa.mjs → secret-file-C3J4Gy8r.mjs} +2 -27
  56. package/dist/secret-file-C3J4Gy8r.mjs.map +1 -0
  57. package/dist/{secretmanager-Bd45j7an.mjs → secretmanager-IY4UvinW.mjs} +42 -9
  58. package/dist/secretmanager-IY4UvinW.mjs.map +1 -0
  59. package/dist/service-BJAQ70e5.mjs +3 -0
  60. package/dist/{service-DeZeYa06.mjs → service-DaeJlBoH.mjs} +3 -3
  61. package/dist/{service-DeZeYa06.mjs.map → service-DaeJlBoH.mjs.map} +1 -1
  62. package/dist/{service-CzZEVrp9.mjs → service-Dmxa2I4i.mjs} +64 -28
  63. package/dist/service-Dmxa2I4i.mjs.map +1 -0
  64. package/dist/service_pb-BoLM0X4K.mjs +167 -0
  65. package/dist/service_pb-BoLM0X4K.mjs.map +1 -0
  66. package/dist/{service_pb-DZkfjB_6.mjs → service_pb-r1T7kpJc.mjs} +1 -1
  67. package/dist/types/executor.generated.d.mts +60 -42
  68. package/dist/user-agent-Bgsszb5I.mjs +28 -0
  69. package/dist/user-agent-Bgsszb5I.mjs.map +1 -0
  70. package/dist/utils/test/index.mjs +11 -11
  71. package/dist/utils/test/index.mjs.map +1 -1
  72. package/dist/utils/test/mock.d.mts +6 -6
  73. package/dist/vitest/environment.mjs +1 -1
  74. package/dist/vitest/index.d.mts +8 -8
  75. package/dist/vitest/index.mjs +613 -227
  76. package/dist/vitest/index.mjs.map +1 -1
  77. package/dist/vitest/mock.d.mts +8 -8
  78. package/dist/vitest/mocks/aigateway.d.mts +14 -4
  79. package/dist/vitest/mocks/authconnection.d.mts +14 -4
  80. package/dist/vitest/mocks/file.d.mts +23 -6
  81. package/dist/vitest/mocks/iconv.d.mts +28 -4
  82. package/dist/vitest/mocks/idp.d.mts +25 -9
  83. package/dist/vitest/mocks/secretmanager.d.mts +13 -4
  84. package/dist/vitest/mocks/tailordb.d.mts +48 -7
  85. package/dist/vitest/mocks/workflow.d.mts +59 -33
  86. package/dist/vitest/setup.mjs +2 -2
  87. package/dist/vitest/workflow-local.d.mts +2 -2
  88. package/dist/workflow-CsBvRE3g.mjs +34 -0
  89. package/dist/workflow-CsBvRE3g.mjs.map +1 -0
  90. package/dist/{service_pb-Bk7dL-yT.mjs → workspace_resource_pb-Db3fv68L.mjs} +47 -165
  91. package/dist/workspace_resource_pb-Db3fv68L.mjs.map +1 -0
  92. package/docs/cli/application.md +63 -15
  93. package/docs/cli/function.md +2 -2
  94. package/docs/cli/tailordb.md +8 -140
  95. package/docs/cli/workspace.md +6 -4
  96. package/docs/cli-reference.md +11 -8
  97. package/docs/configuration.md +2 -0
  98. package/docs/github-actions.md +8 -0
  99. package/docs/migration/v2.md +169 -11
  100. package/docs/runtime.md +5 -6
  101. package/docs/services/auth.md +7 -7
  102. package/docs/services/executor.md +5 -0
  103. package/docs/services/tailordb.md +44 -0
  104. package/docs/services/workflow.md +43 -43
  105. package/docs/testing.md +112 -96
  106. package/package.json +2 -5
  107. package/dist/application-Bf8wxOi6.mjs.map +0 -1
  108. package/dist/application-CUkjzfij.mjs +0 -3
  109. package/dist/cli/erd-viewer-assets/app.js +0 -1424
  110. package/dist/cli/erd-viewer-assets/index.html +0 -77
  111. package/dist/cli/erd-viewer-assets/serve.json +0 -13
  112. package/dist/cli/erd-viewer-assets/styles.css +0 -1036
  113. package/dist/configure/types/field-runtime.d.mts +0 -16
  114. package/dist/errors-118wUDRr.mjs +0 -42
  115. package/dist/errors-118wUDRr.mjs.map +0 -1
  116. package/dist/globals-BjhJJ2dN.mjs.map +0 -1
  117. package/dist/logger-BEiZZ3qT.mjs.map +0 -1
  118. package/dist/register-ts-hook-BhzVkej0.mjs.map +0 -1
  119. package/dist/registry-BSbq6SPo.mjs.map +0 -1
  120. package/dist/resource_pb-BRv7AMXK.mjs +0 -49
  121. package/dist/resource_pb-BRv7AMXK.mjs.map +0 -1
  122. package/dist/schema-iCd1ugGp.mjs.map +0 -1
  123. package/dist/secret-file-aoNXJmKa.mjs.map +0 -1
  124. package/dist/secretmanager-Bd45j7an.mjs.map +0 -1
  125. package/dist/service-BT0GPd01.mjs +0 -3
  126. package/dist/service-CzZEVrp9.mjs.map +0 -1
  127. package/dist/service_pb-Bk7dL-yT.mjs.map +0 -1
  128. package/dist/workflow-GNuSnsTx.mjs +0 -22
  129. package/dist/workflow-GNuSnsTx.mjs.map +0 -1
@@ -1,291 +1,31 @@
1
1
  import { n as isSdkBranded } from "./brand-Eo4pLXPJ.mjs";
2
- import { i as PageDirection } from "./resource_pb-BRv7AMXK.mjs";
3
2
  import { t as assertDefined } from "./assert-DBxo8jPo.mjs";
4
- import { a as parseBoolean, n as logger, r as styles } from "./logger-BEiZZ3qT.mjs";
5
- 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-CzZEVrp9.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-Dmxa2I4i.mjs";
6
5
  import { t as multiline } from "./multiline-sfHpTZZK.mjs";
7
- import { t as readPackageJson } from "./package-json-8b0O9TlX.mjs";
8
- import { i as userAgent, n as tightenSecretFilePermissions, r as writeSecretFile } from "./secret-file-aoNXJmKa.mjs";
9
- import { t as createCLIError } from "./errors-118wUDRr.mjs";
6
+ import { t as userAgent } from "./user-agent-Bgsszb5I.mjs";
10
7
  import { t as isPluginGeneratedType } from "./type-source-DH_LH20p.mjs";
11
8
  import { builtinModules, createRequire } from "node:module";
12
9
  import * as path from "pathe";
13
- import { join, resolve } from "pathe";
10
+ import { resolve } from "pathe";
14
11
  import { resolveTSConfig } from "pkg-types";
15
- import { arg } from "politty";
16
12
  import { z } from "zod";
17
13
  import { create } from "@bufbuild/protobuf";
18
- import * as fs$1 from "node:fs";
19
- import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
20
- import { parseEnv } from "node:util";
14
+ import * as fs from "node:fs";
15
+ import { readFileSync } from "node:fs";
21
16
  import { MethodOptions_IdempotencyLevel } from "@bufbuild/protobuf/wkt";
22
17
  import { pathToFileURL } from "node:url";
23
- import { parseYAML, stringifyYAML } from "confbox";
24
- import { findUpSync } from "find-up-simple";
25
- import { lt } from "semver";
26
- import { xdgConfig } from "xdg-basedir";
27
18
  import { OAuth2Client } from "@badgateway/oauth2-client";
28
19
  import { Code, ConnectError, createClient } from "@connectrpc/connect";
29
20
  import { getGlobalDispatcher } from "undici";
30
21
  import pLimit from "p-limit";
31
22
  import * as crypto from "node:crypto";
32
23
  import * as rolldown from "rolldown";
33
- import * as fs from "node:fs/promises";
34
24
  import { parseSync } from "oxc-parser";
35
25
  import * as inflection from "inflection";
36
26
  import * as globals from "globals";
37
27
  import * as os from "node:os";
38
28
 
39
- //#region src/cli/shared/args.ts
40
- const unitToMs = {
41
- ms: 1,
42
- s: 1e3,
43
- m: 60 * 1e3
44
- };
45
- const durationPattern = /^(\d+)(ms|s|m)$/;
46
- /**
47
- * Schema for duration string validation (e.g., "3s", "500ms", "1m")
48
- * Only validates format; use parseDuration() to convert to milliseconds
49
- */
50
- const durationArg = z.string().refine((val) => durationPattern.test(val), { message: "Invalid duration format. Expected format: '3s', '500ms', '1m'" }).refine((val) => {
51
- const match = val.match(durationPattern);
52
- if (!match) return false;
53
- const digits = match[1];
54
- return digits !== void 0 && parseInt(digits, 10) > 0;
55
- }, { message: "Duration must be greater than 0" });
56
- /**
57
- * Parse a validated duration string into milliseconds
58
- * @param duration - Duration string (e.g., "3s", "500ms", "1m")
59
- * @returns Duration in milliseconds
60
- */
61
- function parseDuration(duration) {
62
- const match = assertDefined(duration.match(durationPattern), `invalid duration format: ${duration}`);
63
- const value = parseInt(assertDefined(match[1], "duration digits group missing"), 10);
64
- const unit = assertDefined(match[2], "duration unit group missing");
65
- return value * unitToMs[unit];
66
- }
67
- /**
68
- * Schema for positive integer validation (from string input)
69
- * Transforms the string to a number
70
- */
71
- const positiveIntArg = z.coerce.number().int().positive();
72
- /**
73
- * Schema for non-negative integer validation (from string input).
74
- * Accepts 0 (used for `--limit 0` to disable the limit).
75
- */
76
- const nonNegativeIntArg = z.coerce.number().int().nonnegative();
77
- /**
78
- * Schema for sort order (`asc` or `desc`).
79
- */
80
- const orderArg = z.enum(["asc", "desc"]);
81
- /**
82
- * Translate a CLI `--order` value into the proto `PageDirection` enum.
83
- * Returns `undefined` when the user did not specify an order so that
84
- * callers can omit the field and fall back to the server default.
85
- * @param order - Order string from CLI args (`"asc"` | `"desc"` | undefined)
86
- * @returns PageDirection, or undefined when `order` is undefined
87
- */
88
- function toPageDirection(order) {
89
- if (order === void 0) return void 0;
90
- return order === "asc" ? PageDirection.ASC : PageDirection.DESC;
91
- }
92
- function hasMachineUserFlag(argv) {
93
- return argv.slice(0, argv.indexOf("--") === -1 ? argv.length : argv.indexOf("--")).some((token) => token === "-m" || token.startsWith("-m=") || token === "--machine-user" || token.startsWith("--machine-user=") || token === "--machineUser" || token.startsWith("--machineUser=") || token === "--machineuser" || token.startsWith("--machineuser="));
94
- }
95
- /**
96
- * Resolve whether a parsed machine user value came from an explicit CLI option or env fallback.
97
- * @param machineUser - Parsed machine user value
98
- * @param argv - Raw CLI argv, excluding the executable and script path
99
- * @param options - Source resolution options
100
- * @returns Machine user input source, or undefined when no value was parsed
101
- */
102
- function resolveMachineUserInputSource(machineUser, argv = process.argv.slice(2), options = {}) {
103
- if (machineUser === void 0) return void 0;
104
- if (options.valueIsExplicit) return "option";
105
- if (hasMachineUserFlag(argv)) return "option";
106
- return process.env.TAILOR_PLATFORM_MACHINE_USER_NAME === machineUser ? "env" : "option";
107
- }
108
- /**
109
- * Load env files from parsed arguments.
110
- * Processes --env-file first, then --env-file-if-exists.
111
- *
112
- * Follows Node.js --env-file behavior:
113
- * - Variables already set in the environment are NOT overwritten
114
- * - Variables from later files override those from earlier files
115
- * @param envFiles - Required env file path(s) that must exist
116
- * @param envFilesIfExists - Optional env file path(s) that are loaded if they exist
117
- */
118
- function loadEnvFiles(envFiles, envFilesIfExists) {
119
- const originalEnvKeys = new Set(Object.keys(process.env));
120
- const load = (files, required) => {
121
- for (const file of [files ?? []].flat()) {
122
- const envPath = path.resolve(process.cwd(), file);
123
- if (!fs$1.existsSync(envPath)) {
124
- if (required) throw new Error(`Environment file not found: ${envPath}`);
125
- continue;
126
- }
127
- const parsed = parseEnv(fs$1.readFileSync(envPath, "utf-8"));
128
- for (const [key, value] of Object.entries(parsed)) {
129
- if (originalEnvKeys.has(key)) continue;
130
- process.env[key] = value;
131
- }
132
- }
133
- };
134
- load(envFiles, true);
135
- load(envFilesIfExists, false);
136
- }
137
- /**
138
- * Common arguments for all CLI commands
139
- *
140
- * NOTE: --env-file and --env-file-if-exists collide with Node.js flags due to a bug
141
- * (https://github.com/nodejs/node/issues/54232). Node.js parses these even after the
142
- * script path, causing warnings (twice due to tsx loader).
143
- */
144
- const commonArgs = {
145
- "env-file": arg(z.string().optional(), {
146
- alias: "e",
147
- description: "Path to the environment file (error if not found)",
148
- completion: {
149
- type: "file",
150
- matcher: [".env.*", ".env"]
151
- }
152
- }),
153
- "env-file-if-exists": arg(z.string().optional(), {
154
- description: "Path to the environment file (ignored if not found)",
155
- completion: {
156
- type: "file",
157
- matcher: [".env.*", ".env"]
158
- },
159
- effect: (_value, { args }) => {
160
- loadEnvFiles(args["env-file"], args["env-file-if-exists"]);
161
- }
162
- }),
163
- verbose: arg(z.boolean().default(false), {
164
- description: "Enable verbose logging",
165
- effect: (value) => {
166
- verboseMode = value;
167
- }
168
- }),
169
- json: arg(z.boolean().default(false), {
170
- alias: "j",
171
- description: "Output as JSON",
172
- effect: (value) => {
173
- logger.jsonMode = value;
174
- }
175
- })
176
- };
177
- /**
178
- * Arguments for commands that require workspace context
179
- */
180
- const workspaceArgs = {
181
- "workspace-id": arg(z.string().optional(), {
182
- alias: "w",
183
- description: "Workspace ID",
184
- env: "TAILOR_PLATFORM_WORKSPACE_ID",
185
- completion: { type: "none" }
186
- }),
187
- profile: arg(z.string().optional(), {
188
- alias: "p",
189
- description: "Workspace profile",
190
- env: "TAILOR_PLATFORM_PROFILE",
191
- completion: { type: "none" }
192
- })
193
- };
194
- /**
195
- * Shared config arg for commands that accept a config file path
196
- */
197
- const configArg = { config: arg(z.string().default("tailor.config.ts"), {
198
- alias: "c",
199
- description: "Path to Tailor config file",
200
- env: "TAILOR_CONFIG_PATH",
201
- completion: {
202
- type: "file",
203
- extensions: ["ts"]
204
- }
205
- }) };
206
- /**
207
- * Shared config arg for commands that accept one or more comma-separated config file paths
208
- */
209
- const multiConfigArg = { config: arg(z.string().default("tailor.config.ts"), {
210
- alias: "c",
211
- description: "Path to SDK config file. Use comma-separated paths to deploy multiple apps together.",
212
- env: "TAILOR_PLATFORM_SDK_CONFIG_PATH",
213
- completion: {
214
- type: "file",
215
- extensions: ["ts"]
216
- }
217
- }) };
218
- /**
219
- * Arguments for commands that interact with deployed resources (includes config)
220
- */
221
- const deploymentArgs = {
222
- ...workspaceArgs,
223
- ...configArg
224
- };
225
- /**
226
- * Arguments for commands that require confirmation
227
- */
228
- const confirmationArgs = { yes: arg(z.boolean().default(false), {
229
- alias: "y",
230
- description: "Skip confirmation prompts"
231
- }) };
232
- /**
233
- * Arguments for commands that require organization context
234
- */
235
- const organizationArgs = { "organization-id": arg(z.string(), {
236
- alias: "o",
237
- description: "Organization ID",
238
- env: "TAILOR_PLATFORM_ORGANIZATION_ID",
239
- completion: { type: "none" }
240
- }) };
241
- /**
242
- * Arguments for list commands that accept `--order` / `--limit`. Sort
243
- * order defaults to `desc` (newest first) because most callers want the
244
- * latest items; pass `--order asc` to opt in to ascending order. The
245
- * limit is unbounded by default so existing invocations keep returning
246
- * every item; pass `--limit N` to cap the result size.
247
- * @param defaultOrder - Default value for `--order` (defaults to `"desc"`)
248
- * @returns Argument shape suitable for spreading into a command schema
249
- */
250
- const paginationArgs = (defaultOrder = "desc") => ({
251
- order: arg(orderArg.default(defaultOrder), { description: "Sort order (asc or desc)" }),
252
- limit: arg(nonNegativeIntArg.optional(), {
253
- alias: "l",
254
- description: "Maximum number of items to return (0 or omit: unlimited)"
255
- })
256
- });
257
- /**
258
- * Arguments for time-series log list commands. Defaults to newest-first
259
- * (`desc`) and a 50-item cap so that listing stays responsive on busy
260
- * workspaces. Pass `--limit 0` to disable the cap and fetch all entries.
261
- */
262
- const pagedLogArgs = {
263
- order: arg(orderArg.default("desc"), { description: "Sort order (asc or desc)" }),
264
- limit: arg(nonNegativeIntArg.default(50), {
265
- alias: "l",
266
- description: "Maximum number of items to return (0: unlimited)"
267
- })
268
- };
269
- /**
270
- * Arguments for commands that require folder context
271
- */
272
- const folderArgs = { "folder-id": arg(z.string(), {
273
- alias: "f",
274
- description: "Folder ID",
275
- env: "TAILOR_PLATFORM_FOLDER_ID",
276
- completion: { type: "none" }
277
- }) };
278
- let verboseMode = false;
279
- /**
280
- * Returns whether verbose mode is enabled.
281
- * Used by the global cleanup handler which doesn't have access to parsed args.
282
- * @returns Whether verbose mode is enabled
283
- */
284
- function isVerbose() {
285
- return verboseMode;
286
- }
287
-
288
- //#endregion
289
29
  //#region src/parser/app-config/log-level.ts
290
30
  const LOG_LEVELS = [
291
31
  "DEBUG",
@@ -298,64 +38,6 @@ function isLogLevel(value) {
298
38
  return LOG_LEVELS.includes(value);
299
39
  }
300
40
 
301
- //#endregion
302
- //#region src/parser/app-config/schema.ts
303
- const envValueSchema = z.union([
304
- z.string(),
305
- z.number(),
306
- z.boolean()
307
- ]);
308
- const LogLevelSchema = z.enum(LOG_LEVELS);
309
- const logLevelSchema = z.string().refine((value) => LogLevelSchema.safeParse(value.trim().toUpperCase()).success, { message: `'logLevel' must be one of: ${LOG_LEVELS.join(", ")}.` });
310
- /**
311
- * Structural validation schema for `defineConfig({...})`. Validates only
312
- * top-level fields with platform-side constraints (notably `id`); fields
313
- * that carry SDK builder objects (`auth`, `idp`, `db`, ...) are accepted
314
- * as opaque values, since their internal shapes are validated by their
315
- * own factory functions and parser-level schemas.
316
- *
317
- * The `id` is auto-managed by `deploy` and stored as a plain UUID. A
318
- * label-compatible prefix is added at the metadata boundary, so user-facing
319
- * configs only need to carry a UUID.
320
- */
321
- const AppConfigSchema = z.strictObject({
322
- id: z.uuid({ message: "'id' must be a UUID." }).optional(),
323
- name: z.string().min(1, { message: "'name' must be a non-empty string." }),
324
- env: z.record(z.string(), envValueSchema).optional(),
325
- cors: z.array(z.string()).optional(),
326
- allowedIpAddresses: z.array(z.string()).optional(),
327
- disableIntrospection: z.boolean().optional(),
328
- inlineSourcemap: z.boolean().optional(),
329
- logLevel: logLevelSchema.optional(),
330
- db: z.unknown().optional(),
331
- resolver: z.unknown().optional(),
332
- idp: z.unknown().optional(),
333
- auth: z.unknown().optional(),
334
- executor: z.unknown().optional(),
335
- workflow: z.unknown().optional(),
336
- httpAdapter: z.unknown().optional(),
337
- staticWebsites: z.unknown().optional(),
338
- aiGateways: z.unknown().optional(),
339
- secrets: z.unknown().optional()
340
- });
341
-
342
- //#endregion
343
- //#region src/parser/plugin-config/schema.ts
344
- const PluginConfigSchema = z.looseObject({
345
- id: z.string(),
346
- description: z.string(),
347
- importPath: z.string().optional(),
348
- pluginConfig: z.unknown().optional(),
349
- typeConfigRequired: z.union([z.boolean(), functionSchema]).optional(),
350
- onTypeLoaded: functionSchema.optional(),
351
- onNamespaceLoaded: functionSchema.optional(),
352
- onTailorDBReady: functionSchema.optional(),
353
- onResolverReady: functionSchema.optional(),
354
- onExecutorReady: functionSchema.optional()
355
- }).refine((p) => {
356
- return !(p.onTypeLoaded || p.onNamespaceLoaded) || !!p.importPath;
357
- }, { message: "importPath is required when plugin has definition-time hooks (onTypeLoaded/onNamespaceLoaded)" }).transform((plugin) => plugin);
358
-
359
41
  //#endregion
360
42
  //#region src/cli/shared/apply-concurrency.ts
361
43
  /**
@@ -498,7 +180,7 @@ function initOAuth2Client(config) {
498
180
  */
499
181
  async function initOperatorClient(accessToken, config) {
500
182
  const platformConfig = config ?? getPlatformConfigForToken(accessToken);
501
- const [{ createTracingInterceptor }, { OperatorService }] = await Promise.all([import("./interceptor-e33JtsC-.mjs"), import("./service_pb-DZkfjB_6.mjs")]);
183
+ const [{ createTracingInterceptor }, { OperatorService }] = await Promise.all([import("./interceptor-e33JtsC-.mjs"), import("./service_pb-r1T7kpJc.mjs")]);
502
184
  const interceptors = [
503
185
  await userAgentInterceptor(),
504
186
  await bearerTokenInterceptor(accessToken),
@@ -551,9 +233,9 @@ async function bearerTokenInterceptor(accessToken) {
551
233
  /**
552
234
  * Create an interceptor that retries failed unary requests with backoff.
553
235
  *
554
- * Retries any unary method on `Unavailable`/`ResourceExhausted`, and `Internal`
555
- * only for methods declared idempotent, up to 3 attempts (despite the historical
556
- * "idempotent" naming, the first two codes are retried regardless of idempotency).
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.
557
239
  * As a targeted exception for the deploy/apply flow, a post-retry `AlreadyExists`
558
240
  * from an allowlisted Create (see `RETRY_SAFE_CREATE_METHODS`) is treated as
559
241
  * success, since it means a prior attempt already committed the resource
@@ -578,10 +260,10 @@ function retryInterceptor() {
578
260
  logger.debug(`retry: ${req.method.name} returned AlreadyExists on attempt ${i + 1}; treating as success (prior attempt likely committed)`);
579
261
  return synthesizeEmptyUnaryResponse(req);
580
262
  }
581
- const { reportCrash } = await import("./crashreport-D3RjuSYb.mjs");
263
+ const { reportCrash } = await import("./crashreport-0ioNRZ4K.mjs");
582
264
  await reportCrash(error, "handledError");
583
265
  }
584
- if (isRetirable(error, req.method.idempotency)) {
266
+ if (req.method.name !== "CreateWorkspace" && isRetirable(error, req.method.idempotency)) {
585
267
  lastError = error;
586
268
  logger.debug(`retry: ${req.method.name} attempt ${i + 1} failed with ${connectCodeName(error)}; retrying`);
587
269
  continue;
@@ -986,806 +668,6 @@ async function closeConnectionPool() {
986
668
  await getGlobalDispatcher().close();
987
669
  }
988
670
 
989
- //#endregion
990
- //#region src/cli/shared/token-store.ts
991
- const SERVICE_NAME = "tailor-platform-cli";
992
- let entryClass;
993
- async function getEntryClass() {
994
- if (entryClass !== void 0) return entryClass;
995
- try {
996
- const mod = await import("@napi-rs/keyring");
997
- const probe = new mod.Entry(SERVICE_NAME, "__probe__");
998
- probe.setPassword("probe");
999
- probe.deletePassword();
1000
- entryClass = mod.Entry;
1001
- } catch {
1002
- logger.warn("System keyring is not available. Tokens will be stored in the config file. Set TAILOR_PLATFORM_TOKEN environment variable for CI environments.");
1003
- entryClass = false;
1004
- }
1005
- return entryClass;
1006
- }
1007
- /**
1008
- * Check whether the OS keyring is available and functional.
1009
- * @returns true if keyring is available
1010
- */
1011
- async function isKeyringAvailable() {
1012
- return await getEntryClass() !== false;
1013
- }
1014
- /**
1015
- * Load tokens from the OS keyring for a given account.
1016
- * @param account - User identifier (e.g. email or client ID)
1017
- * @returns Token data or undefined if not found or keyring unavailable
1018
- */
1019
- async function loadKeyringTokens(account) {
1020
- const Entry = await getEntryClass();
1021
- if (!Entry) return void 0;
1022
- try {
1023
- const raw = new Entry(SERVICE_NAME, account).getPassword();
1024
- if (raw === null) return void 0;
1025
- return JSON.parse(raw);
1026
- } catch {
1027
- return;
1028
- }
1029
- }
1030
- /**
1031
- * Save tokens to the OS keyring for a given account.
1032
- * @param account - User identifier (e.g. email or client ID)
1033
- * @param tokens - Token data to store
1034
- */
1035
- async function saveKeyringTokens(account, tokens) {
1036
- const Entry = await getEntryClass();
1037
- if (!Entry) return;
1038
- new Entry(SERVICE_NAME, account).setPassword(JSON.stringify(tokens));
1039
- }
1040
- /**
1041
- * Delete tokens from the OS keyring for a given account.
1042
- * @param account - User identifier (e.g. email or client ID)
1043
- */
1044
- async function deleteKeyringTokens(account) {
1045
- const Entry = await getEntryClass();
1046
- if (!Entry) return;
1047
- try {
1048
- new Entry(SERVICE_NAME, account).deletePassword();
1049
- } catch {}
1050
- }
1051
-
1052
- //#endregion
1053
- //#region src/cli/shared/context.ts
1054
- const pfProfileSchema = z.object({
1055
- user: z.string(),
1056
- workspace_id: z.string(),
1057
- readonly: z.boolean().optional(),
1058
- machine_user: z.string().optional(),
1059
- machine_user_override: z.enum(["allow", "deny"]).optional(),
1060
- platform_url: z.url().optional(),
1061
- oauth2_client_id: z.string().optional(),
1062
- console_url: z.url().optional()
1063
- });
1064
- const pfUserSchemaV1 = z.object({
1065
- access_token: z.string(),
1066
- refresh_token: z.string().optional(),
1067
- token_expires_at: z.string()
1068
- });
1069
- const pfUserKeyringSchema = z.object({
1070
- storage: z.literal("keyring"),
1071
- token_expires_at: z.string()
1072
- });
1073
- const pfUserFileSchema = z.object({
1074
- storage: z.literal("file"),
1075
- token_expires_at: z.string(),
1076
- access_token: z.string(),
1077
- refresh_token: z.string().optional()
1078
- });
1079
- const pfUserSchemaV2 = z.discriminatedUnion("storage", [pfUserKeyringSchema, pfUserFileSchema]);
1080
- const pfUserKeyringSchemaV3 = pfUserKeyringSchema.extend({ email: z.string().optional() });
1081
- const pfUserFileSchemaV3 = pfUserFileSchema.extend({ email: z.string().optional() });
1082
- const pfUserSchemaV3 = z.discriminatedUnion("storage", [pfUserKeyringSchemaV3, pfUserFileSchemaV3]);
1083
- const pfConfigSchemaV1 = z.object({
1084
- version: z.literal(1),
1085
- users: z.partialRecord(z.string(), pfUserSchemaV1),
1086
- profiles: z.partialRecord(z.string(), pfProfileSchema),
1087
- current_user: z.string().nullable()
1088
- });
1089
- const V2_CONFIG_VERSION = 2;
1090
- const LATEST_CONFIG_VERSION = 3;
1091
- const V2_MIN_SDK_VERSION = "1.29.0";
1092
- const V3_MIN_SDK_VERSION = "2.0.0";
1093
- const semverSchema = z.templateLiteral([
1094
- z.number().int(),
1095
- ".",
1096
- z.number().int(),
1097
- ".",
1098
- z.number().int()
1099
- ]);
1100
- const pfConfigSchemaV2 = z.object({
1101
- version: z.literal(V2_CONFIG_VERSION),
1102
- min_sdk_version: semverSchema,
1103
- latest_version: z.number().int().optional(),
1104
- latest_min_sdk_version: semverSchema.optional(),
1105
- users: z.partialRecord(z.string(), pfUserSchemaV2),
1106
- profiles: z.partialRecord(z.string(), pfProfileSchema),
1107
- current_user: z.string().nullable()
1108
- });
1109
- const pfConfigSchemaV3 = z.object({
1110
- version: z.literal(LATEST_CONFIG_VERSION),
1111
- min_sdk_version: semverSchema,
1112
- latest_version: z.number().int().optional(),
1113
- latest_min_sdk_version: semverSchema.optional(),
1114
- users: z.partialRecord(z.string(), pfUserSchemaV3),
1115
- profiles: z.partialRecord(z.string(), pfProfileSchema),
1116
- current_user: z.string().nullable()
1117
- });
1118
- function platformConfigPath() {
1119
- if (!xdgConfig) throw new Error("User home directory not found");
1120
- return path.join(xdgConfig, "tailor-platform", "config.yaml");
1121
- }
1122
- /**
1123
- * Convert stored profile platform fields to platform client settings.
1124
- * @param profile - Profile platform settings
1125
- * @returns Platform client settings
1126
- */
1127
- function platformConfigFromProfile(profile) {
1128
- const config = {
1129
- ...profile?.platform_url ? { platformUrl: profile.platform_url } : {},
1130
- ...profile?.oauth2_client_id ? { oauth2ClientId: profile.oauth2_client_id } : {},
1131
- ...profile?.console_url ? { consoleUrl: profile.console_url } : {}
1132
- };
1133
- return Object.keys(config).length > 0 ? config : void 0;
1134
- }
1135
- function platformUserKey(user, config) {
1136
- const platformUrl = getPlatformBaseUrl(config);
1137
- if (platformUrl === normalizeBaseUrl("https://api.tailor.tech")) return user;
1138
- return `${platformUrl}|${user}`;
1139
- }
1140
- function userFromPlatformUserKey(userKey, config) {
1141
- const platformPrefix = `${getPlatformBaseUrl(config)}|`;
1142
- return userKey.startsWith(platformPrefix) ? userKey.slice(platformPrefix.length) : userKey;
1143
- }
1144
- function canUseLegacyUserKey(platformUrl) {
1145
- try {
1146
- return getPlatformBaseUrl() === platformUrl;
1147
- } catch {
1148
- return false;
1149
- }
1150
- }
1151
- function findUserByEmail(users, email, platformConfig) {
1152
- const platformUrl = getPlatformBaseUrl(platformConfig);
1153
- const platformPrefix = `${platformUrl}|`;
1154
- const defaultPlatform = platformUrl === normalizeBaseUrl(defaultPlatformBaseUrl);
1155
- return Object.entries(users).find(([key, entry]) => {
1156
- if (entry?.email !== email) return false;
1157
- return defaultPlatform ? !key.includes("|") : key.startsWith(platformPrefix);
1158
- });
1159
- }
1160
- function findUserEntry(config, user, platformConfig, opts = {}) {
1161
- const userKey = platformUserKey(user, platformConfig);
1162
- const userEntry = config.users[userKey];
1163
- if (userEntry) return {
1164
- userKey,
1165
- userEntry
1166
- };
1167
- const emailMatch = findUserByEmail(config.users, user, platformConfig);
1168
- if (emailMatch?.[1]) return {
1169
- userKey: emailMatch[0],
1170
- userEntry: emailMatch[1]
1171
- };
1172
- const platformUrl = getPlatformBaseUrl(platformConfig);
1173
- if (userKey !== user && (opts.allowLegacyUserKey === false || !canUseLegacyUserKey(platformUrl))) return {
1174
- userKey,
1175
- userEntry
1176
- };
1177
- const legacyEntry = config.users[user];
1178
- return legacyEntry ? {
1179
- userKey: user,
1180
- userEntry: legacyEntry
1181
- } : {
1182
- userKey,
1183
- userEntry
1184
- };
1185
- }
1186
- /**
1187
- * Resolve the config user key that would be used for a user on the selected platform.
1188
- * @param config - Platform config
1189
- * @param user - User name
1190
- * @param platformConfig - Optional platform connection settings
1191
- * @param opts - Token lookup options
1192
- * @returns Resolved config user key
1193
- */
1194
- function resolveUserTokenKey(config, user, platformConfig, opts) {
1195
- return findUserEntry(config, user, platformConfig, opts).userKey;
1196
- }
1197
- function resolveConfigUser(config, user, platformConfig, opts) {
1198
- const { userKey, userEntry } = findUserEntry(config, user, platformConfig, opts);
1199
- return userEntry ? userFromPlatformUserKey(userKey, platformConfig) : void 0;
1200
- }
1201
- /**
1202
- * Check whether tokens are registered for a user on the selected platform.
1203
- * @param config - Platform config
1204
- * @param user - User name
1205
- * @param platformConfig - Optional platform connection settings
1206
- * @param opts - Token lookup options
1207
- * @returns True when the user has a registered token entry
1208
- */
1209
- function hasUserTokenEntry(config, user, platformConfig, opts) {
1210
- return findUserEntry(config, user, platformConfig, opts).userEntry !== void 0;
1211
- }
1212
- function hasUserKeyForName(users, user) {
1213
- return users[user] !== void 0 || Object.keys(users).some((key) => key.endsWith(`|${user}`));
1214
- }
1215
- function hasUserEmailEntry(users, user) {
1216
- return Object.values(users).some((entry) => entry?.email === user);
1217
- }
1218
- /**
1219
- * Check whether any platform has tokens registered for a user.
1220
- * @param config - Platform config
1221
- * @param user - User name
1222
- * @returns True when the user has a token entry for any platform
1223
- */
1224
- function hasAnyUserTokenEntry(config, user) {
1225
- return hasUserKeyForName(config.users, user) || hasUserEmailEntry(config.users, user);
1226
- }
1227
- function hasCurrentUserEntry(users, currentUser) {
1228
- return hasUserKeyForName(users, currentUser);
1229
- }
1230
- /**
1231
- * Migrate a v1 config to v2.
1232
- * Tokens are kept in the config file (storage: "file") during migration.
1233
- * They will be moved to the OS keyring on next login or token refresh.
1234
- * @param v1Config - v1 configuration to migrate
1235
- * @returns Migrated v2 configuration
1236
- */
1237
- function migrateV1ToV2(v1Config) {
1238
- const users = {};
1239
- for (const [name, v1User] of Object.entries(v1Config.users)) {
1240
- if (!v1User) continue;
1241
- users[name] = {
1242
- access_token: v1User.access_token,
1243
- refresh_token: v1User.refresh_token,
1244
- token_expires_at: v1User.token_expires_at,
1245
- storage: "file"
1246
- };
1247
- }
1248
- return {
1249
- version: V2_CONFIG_VERSION,
1250
- min_sdk_version: V2_MIN_SDK_VERSION,
1251
- users,
1252
- profiles: v1Config.profiles,
1253
- current_user: v1Config.current_user
1254
- };
1255
- }
1256
- function inferEmailFromUserId(user) {
1257
- return z.email().safeParse(user).success ? user : void 0;
1258
- }
1259
- function migrateV2ToV3(v2Config) {
1260
- const users = {};
1261
- for (const [user, entry] of Object.entries(v2Config.users)) {
1262
- if (!entry) continue;
1263
- const email = inferEmailFromUserId(user);
1264
- users[user] = {
1265
- ...entry,
1266
- ...email ? { email } : {}
1267
- };
1268
- }
1269
- return {
1270
- version: LATEST_CONFIG_VERSION,
1271
- min_sdk_version: V3_MIN_SDK_VERSION,
1272
- users,
1273
- profiles: v2Config.profiles,
1274
- current_user: v2Config.current_user
1275
- };
1276
- }
1277
- function migrateV1ToV3(v1Config) {
1278
- return migrateV2ToV3(migrateV1ToV2(v1Config));
1279
- }
1280
- function formatUnknownError(error) {
1281
- return error instanceof Error ? error.message : String(error);
1282
- }
1283
- async function trySaveTokensInKeyring(user, tokens) {
1284
- if (!await isKeyringAvailable()) return false;
1285
- try {
1286
- await saveKeyringTokens(user, tokens);
1287
- return true;
1288
- } catch (error) {
1289
- logger.warn(`System keyring failed to store credentials. Tokens will be stored in the config file. ${formatUnknownError(error)}`);
1290
- return false;
1291
- }
1292
- }
1293
- async function warnIfNewerConfigAvailable(config) {
1294
- if (!config.latest_min_sdk_version) return;
1295
- if (lt((await readPackageJson()).version ?? "0.0.0", config.latest_min_sdk_version)) logger.warn(multiline`
1296
- A newer config version (${String(config.latest_version)}) is available.
1297
- Please update your SDK to >= ${config.latest_min_sdk_version}: pnpm update @tailor-platform/sdk
1298
- `);
1299
- }
1300
- /**
1301
- * Read Tailor Platform CLI configuration, migrating from v1 if necessary.
1302
- * @returns Parsed platform configuration
1303
- */
1304
- async function readPlatformConfig() {
1305
- const configPath = platformConfigPath();
1306
- if (!fs$1.existsSync(configPath)) {
1307
- const config = {
1308
- version: LATEST_CONFIG_VERSION,
1309
- min_sdk_version: V3_MIN_SDK_VERSION,
1310
- users: {},
1311
- profiles: {},
1312
- current_user: null
1313
- };
1314
- writePlatformConfig(config);
1315
- return config;
1316
- }
1317
- const rawConfig = parseYAML(fs$1.readFileSync(configPath, "utf-8"));
1318
- tightenSecretFilePermissions(configPath);
1319
- const version = rawConfig != null && typeof rawConfig === "object" && "version" in rawConfig ? rawConfig.version : void 0;
1320
- if (typeof version === "number" && version > LATEST_CONFIG_VERSION) {
1321
- const minSdk = "min_sdk_version" in rawConfig ? String(rawConfig.min_sdk_version) : void 0;
1322
- const updateHint = minSdk ? `Please update your SDK to >= ${minSdk}: pnpm update @tailor-platform/sdk` : "Please update your SDK: pnpm update @tailor-platform/sdk";
1323
- throw new Error(multiline`
1324
- Config file uses version ${String(version)}, but this SDK only supports up to version ${String(LATEST_CONFIG_VERSION)}.
1325
- ${updateHint}
1326
- `);
1327
- }
1328
- const v3Result = pfConfigSchemaV3.safeParse(rawConfig);
1329
- if (v3Result.success) {
1330
- await warnIfNewerConfigAvailable(v3Result.data);
1331
- return v3Result.data;
1332
- }
1333
- const v2Result = pfConfigSchemaV2.safeParse(rawConfig);
1334
- if (v2Result.success) {
1335
- await warnIfNewerConfigAvailable(v2Result.data);
1336
- return migrateV2ToV3(v2Result.data);
1337
- }
1338
- const v1Result = pfConfigSchemaV1.safeParse(rawConfig);
1339
- if (v1Result.success) return migrateV1ToV3(v1Result.data);
1340
- throw new Error(multiline`
1341
- Failed to parse config file at ${configPath}.
1342
- The file may be corrupted or created by an incompatible SDK version.
1343
- `);
1344
- }
1345
- function toV1ForDisk(config) {
1346
- const users = {};
1347
- for (const [name, entry] of Object.entries(config.users)) {
1348
- if (!entry || entry.storage === "keyring") continue;
1349
- users[name] = {
1350
- access_token: entry.access_token,
1351
- refresh_token: entry.refresh_token,
1352
- token_expires_at: entry.token_expires_at
1353
- };
1354
- }
1355
- const currentUser = config.current_user && hasCurrentUserEntry(users, config.current_user) ? config.current_user : null;
1356
- return {
1357
- version: 1,
1358
- users,
1359
- profiles: config.profiles,
1360
- current_user: currentUser
1361
- };
1362
- }
1363
- function hasProfilePlatformSettings(config) {
1364
- return Object.values(config.profiles).some((profile) => profile?.platform_url !== void 0 || profile?.oauth2_client_id !== void 0 || profile?.console_url !== void 0);
1365
- }
1366
- function hasScopedUserKeys(config) {
1367
- return Object.keys(config.users).some((userKey) => userKey.includes("|"));
1368
- }
1369
- function hasUserEmailMetadata(config) {
1370
- return Object.values(config.users).some((user) => user != null && "email" in user && user.email !== void 0);
1371
- }
1372
- function toLatestForDisk(config) {
1373
- return {
1374
- ...config.version === 1 ? migrateV1ToV2(config) : config,
1375
- version: LATEST_CONFIG_VERSION,
1376
- min_sdk_version: V3_MIN_SDK_VERSION
1377
- };
1378
- }
1379
- /**
1380
- * Write Tailor Platform CLI configuration to disk.
1381
- * By default, file-backed configs without newer fields are converted to V1 for
1382
- * backward compatibility, so an older SDK can still read the file. Configs
1383
- * containing a keyring user are kept in V2 or later because the keyring storage
1384
- * variant is not representable in V1. Configs containing profile-level Platform
1385
- * settings, platform-scoped user tokens, canonical user IDs, or email metadata
1386
- * are written in the latest min-SDK-gated format because older SDKs would
1387
- * silently drop or misread those settings.
1388
- *
1389
- * The config file may contain access/refresh tokens when the OS keyring is
1390
- * unavailable, so it is written via {@link writeSecretFile} so other users
1391
- * on the host cannot read it.
1392
- * @param config - Platform configuration to write
1393
- */
1394
- function writePlatformConfig(config) {
1395
- const configPath = platformConfigPath();
1396
- const hasKeyringUser = config.version !== 1 && Object.values(config.users).some((u) => u?.storage === "keyring");
1397
- writeSecretFile(configPath, stringifyYAML(config.version === LATEST_CONFIG_VERSION || hasProfilePlatformSettings(config) || hasScopedUserKeys(config) || hasUserEmailMetadata(config) ? toLatestForDisk(config) : config.version === V2_CONFIG_VERSION && !hasKeyringUser ? toV1ForDisk(config) : config));
1398
- }
1399
- function validateUUID(value, source) {
1400
- const result = z.uuid().safeParse(value);
1401
- if (!result.success) throw new Error(`Invalid value from ${source}: must be a valid UUID`);
1402
- return result.data;
1403
- }
1404
- /**
1405
- * Load workspace ID from command options, environment variables, or platform config.
1406
- * In CLI context, env fallback is also handled by politty's arg env option.
1407
- * Priority: opts/workspaceId > env/workspaceId > opts/profile > error
1408
- * @param opts - Workspace and profile options
1409
- * @returns Resolved workspace ID
1410
- */
1411
- async function loadWorkspaceId(opts) {
1412
- const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;
1413
- if (opts?.workspaceId) return validateUUID(opts.workspaceId, "--workspace-id option");
1414
- if (process.env.TAILOR_PLATFORM_WORKSPACE_ID) return validateUUID(process.env.TAILOR_PLATFORM_WORKSPACE_ID, "TAILOR_PLATFORM_WORKSPACE_ID environment variable");
1415
- if (profile) {
1416
- const wsId = (await readPlatformConfig()).profiles[profile]?.workspace_id;
1417
- if (!wsId) throw new Error(`Profile "${profile}" not found`);
1418
- return validateUUID(wsId, `profile "${profile}"`);
1419
- }
1420
- throw new Error(multiline`
1421
- Workspace ID not found.
1422
- Please specify workspace ID via --workspace-id option or TAILOR_PLATFORM_WORKSPACE_ID environment variable.
1423
- `);
1424
- }
1425
- /**
1426
- * Load machine user name from command options, environment variables, or platform config.
1427
- * In CLI context, env fallback is also handled by politty's arg env option.
1428
- * Priority: opts/machineUser > env/TAILOR_PLATFORM_MACHINE_USER_NAME > opts/profile (profile default) > undefined.
1429
- * An explicitly empty `opts.machineUser` is rejected with a CLIError (`MACHINE_USER_NAME_EMPTY`) rather than falling back to the env var or profile default.
1430
- * When the active profile has `machine_user_override: "deny"`, an explicit value that differs from the profile's machine user throws a CLIError with code `PROFILE_MACHINE_USER_OVERRIDE_DENIED`.
1431
- * @param opts - Machine user and profile options
1432
- * @returns Resolved machine user name, or undefined if not set
1433
- */
1434
- async function loadMachineUserName(opts) {
1435
- if (opts?.machineUser === "") throw createCLIError({
1436
- code: "MACHINE_USER_NAME_EMPTY",
1437
- message: "Machine user name cannot be empty.",
1438
- suggestion: "Pass a non-empty machine user name, or omit the option to use the environment variable or profile default."
1439
- });
1440
- const envMachineUser = process.env.TAILOR_PLATFORM_MACHINE_USER_NAME || void 0;
1441
- const explicitMachineUser = opts?.machineUser ? {
1442
- source: opts.machineUserSource ?? "option",
1443
- value: opts.machineUser
1444
- } : envMachineUser ? {
1445
- source: "env",
1446
- value: envMachineUser
1447
- } : void 0;
1448
- const explicit = explicitMachineUser?.value;
1449
- const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;
1450
- if (!profile) return explicit;
1451
- const entry = (await readPlatformConfig()).profiles[profile];
1452
- if (!entry) {
1453
- if (explicit) return explicit;
1454
- throw new Error(`Profile "${profile}" not found`);
1455
- }
1456
- if (entry.machine_user && entry.machine_user_override === "deny") {
1457
- if (explicit && explicit !== entry.machine_user) {
1458
- const details = explicitMachineUser.source === "env" ? `The machine user is being set to "${explicit}" via the TAILOR_PLATFORM_MACHINE_USER_NAME environment variable, which conflicts with this profile's pinned machine user "${entry.machine_user}".` : `This profile fixes the machine user to "${entry.machine_user}" for application-data commands.`;
1459
- throw createCLIError({
1460
- code: "PROFILE_MACHINE_USER_OVERRIDE_DENIED",
1461
- message: `Profile "${profile}" denies overriding the machine user.`,
1462
- details,
1463
- suggestion: `Omit the machine user option, unset TAILOR_PLATFORM_MACHINE_USER_NAME, or run 'tailor profile update ${profile} --machine-user-override allow'.`
1464
- });
1465
- }
1466
- return entry.machine_user;
1467
- }
1468
- return explicit || entry.machine_user;
1469
- }
1470
- /**
1471
- * Load access token from environment variables, command options, or platform config.
1472
- * In CLI context, profile env fallback is also handled by politty's arg env option.
1473
- * Priority: env/TAILOR_PLATFORM_TOKEN > env/TAILOR_TOKEN (deprecated) > opts/profile > env/profile > config/currentUser > error
1474
- * @param opts - Profile options
1475
- * @returns Resolved access token
1476
- */
1477
- async function loadAccessToken(opts) {
1478
- const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;
1479
- const envToken = process.env.TAILOR_PLATFORM_TOKEN ?? process.env.TAILOR_TOKEN;
1480
- if (envToken && !process.env.TAILOR_PLATFORM_TOKEN) logger.warn("TAILOR_TOKEN is deprecated. Please use TAILOR_PLATFORM_TOKEN instead.");
1481
- if (envToken) {
1482
- rememberPlatformConfigForToken(envToken, await loadPlatformClientConfig({
1483
- profile,
1484
- allowMissingProfile: true
1485
- }));
1486
- return envToken;
1487
- }
1488
- const pfConfig = await readPlatformConfig();
1489
- const profileEntry = profile ? pfConfig.profiles[profile] : void 0;
1490
- if (profile && !profileEntry) throw new Error(`Profile "${profile}" not found`);
1491
- const user = profileEntry?.user ?? pfConfig.current_user;
1492
- if (!user) throw new Error(multiline`
1493
- Tailor Platform token not found.
1494
- Please specify token via TAILOR_PLATFORM_TOKEN environment variable or login using 'tailor login' command.
1495
- `);
1496
- return (await fetchLatestToken(pfConfig, user, profileEntry ? platformConfigFromProfile(profileEntry) : void 0)).accessToken;
1497
- }
1498
- /**
1499
- * Load platform connection settings from the active profile.
1500
- * @param opts - Profile options
1501
- * @returns Resolved platform connection settings, or undefined for the default environment
1502
- */
1503
- async function loadPlatformClientConfig(opts) {
1504
- const profile = opts?.profile || process.env.TAILOR_PLATFORM_PROFILE;
1505
- if (!profile) return;
1506
- let pfConfig;
1507
- try {
1508
- pfConfig = await readPlatformConfig();
1509
- } catch (error) {
1510
- if (opts?.allowMissingProfile) return;
1511
- throw error;
1512
- }
1513
- const profileEntry = pfConfig.profiles[profile];
1514
- if (!profileEntry) {
1515
- if (opts?.allowMissingProfile) return;
1516
- throw new Error(`Profile "${profile}" not found`);
1517
- }
1518
- return platformConfigFromProfile(profileEntry);
1519
- }
1520
- /**
1521
- * Load the Tailor Platform Console base URL from environment variables or the active profile.
1522
- * @param opts - Profile options
1523
- * @returns Resolved Console base URL
1524
- */
1525
- async function loadConsoleBaseUrl(opts) {
1526
- return getConsoleBaseUrl(await loadPlatformClientConfig(opts));
1527
- }
1528
- /**
1529
- * Resolve the actual token values for a user, reading from keyring or config as appropriate.
1530
- * @param userEntry - User entry from the config
1531
- * @param user - User identifier
1532
- * @param label - User-facing identifier used in error messages
1533
- * @returns Access token and optional refresh token
1534
- */
1535
- async function resolveTokens(userEntry, user, label = user) {
1536
- if (userEntry.storage === "keyring") {
1537
- const tokens = await loadKeyringTokens(user);
1538
- if (!tokens) throw new Error(multiline`
1539
- Credentials not found in OS keyring for "${label}".
1540
- Please run 'tailor login' and try again.
1541
- `);
1542
- return tokens;
1543
- }
1544
- return {
1545
- accessToken: userEntry.access_token,
1546
- refreshToken: userEntry.refresh_token
1547
- };
1548
- }
1549
- /**
1550
- * Save tokens for a user, writing to keyring by default when available.
1551
- * @param config - Platform config
1552
- * @param user - User identifier
1553
- * @param tokens - Token data to save
1554
- * @param tokens.accessToken - Access token to save
1555
- * @param tokens.refreshToken - Optional refresh token to save
1556
- * @param expiresAt - Token expiration date
1557
- * @param opts - Optional platform and user metadata
1558
- */
1559
- async function saveUserTokens(config, user, tokens, expiresAt, opts = {}) {
1560
- const userKey = platformUserKey(user, opts.platformConfig);
1561
- const email = opts.email ?? config.users[userKey]?.email;
1562
- if (await trySaveTokensInKeyring(userKey, tokens)) config.users[userKey] = {
1563
- token_expires_at: expiresAt,
1564
- storage: "keyring",
1565
- ...email ? { email } : {}
1566
- };
1567
- else {
1568
- if (config.users[userKey]?.storage === "keyring") await deleteKeyringTokens(userKey);
1569
- config.users[userKey] = {
1570
- access_token: tokens.accessToken,
1571
- refresh_token: tokens.refreshToken,
1572
- token_expires_at: expiresAt,
1573
- storage: "file",
1574
- ...email ? { email } : {}
1575
- };
1576
- }
1577
- }
1578
- /**
1579
- * Delete tokens for a user from keyring if applicable.
1580
- * @param config - Platform config
1581
- * @param user - User identifier
1582
- * @param platformConfig - Optional platform connection settings
1583
- * @param opts - Token lookup options
1584
- */
1585
- async function deleteUserTokens(config, user, platformConfig, opts) {
1586
- const { userKey, userEntry } = findUserEntry(config, user, platformConfig, opts);
1587
- if (userEntry?.storage === "keyring") await deleteKeyringTokens(userKey);
1588
- delete config.users[userKey];
1589
- }
1590
- /**
1591
- * Resolve stored tokens for a user on the selected platform.
1592
- * @param config - Platform config
1593
- * @param user - User name
1594
- * @param platformConfig - Optional platform connection settings
1595
- * @param opts - Token lookup options
1596
- * @returns Stored user entry and token values, or undefined when the user is not logged in
1597
- */
1598
- async function loadStoredUserTokens(config, user, platformConfig, opts) {
1599
- const { userKey, userEntry } = findUserEntry(config, user, platformConfig, opts);
1600
- if (!userEntry) return void 0;
1601
- return {
1602
- userEntry,
1603
- ...await resolveTokens(userEntry, userKey, user)
1604
- };
1605
- }
1606
- function updateUserReferences(config, fromUser, toUser) {
1607
- if (fromUser === toUser) return;
1608
- if (config.current_user === fromUser) config.current_user = toUser;
1609
- for (const profile of Object.values(config.profiles)) if (profile?.user === fromUser) profile.user = toUser;
1610
- }
1611
- /**
1612
- * Remove a legacy alias after a canonical user ID has been written.
1613
- * @param config - Platform config
1614
- * @param legacyUser - Previous user key
1615
- * @param canonicalUser - Canonical user key
1616
- * @param platformConfig - Platform settings for scoped token storage
1617
- */
1618
- async function removeLegacyUserAlias(config, legacyUser, canonicalUser, platformConfig) {
1619
- if (legacyUser === canonicalUser) return;
1620
- updateUserReferences(config, legacyUser, canonicalUser);
1621
- const canonicalKey = platformUserKey(canonicalUser, platformConfig);
1622
- const legacyKeys = /* @__PURE__ */ new Set([legacyUser, platformUserKey(legacyUser, platformConfig)]);
1623
- for (const legacyKey of legacyKeys) {
1624
- if (legacyKey === canonicalKey) continue;
1625
- if (config.users[legacyKey]?.storage === "keyring") await deleteKeyringTokens(legacyKey);
1626
- delete config.users[legacyKey];
1627
- }
1628
- }
1629
- function shouldResolveSubjectOnRefresh(user, userEntry) {
1630
- return Boolean(userEntry.email || inferEmailFromUserId(user));
1631
- }
1632
- /**
1633
- * Fetch the latest access token, refreshing if necessary.
1634
- * @param config - Platform config
1635
- * @param user - User identifier
1636
- * @param platformConfig - Optional platform connection settings
1637
- * @returns Latest access token and the canonical user ID it is stored under
1638
- * (the resolved subject when a legacy email key was migrated during refresh,
1639
- * otherwise the matching config user)
1640
- */
1641
- async function fetchLatestToken(config, user, platformConfig) {
1642
- const { userKey: storedUser, userEntry } = findUserEntry(config, user, platformConfig);
1643
- if (!userEntry) throw new Error(multiline`
1644
- User "${user}" not found.
1645
- Please verify your user name and login using 'tailor login' command.
1646
- `);
1647
- const storedConfigUser = userFromPlatformUserKey(storedUser, platformConfig);
1648
- const tokens = await resolveTokens(userEntry, storedUser, user);
1649
- if (new Date(userEntry.token_expires_at) > /* @__PURE__ */ new Date()) {
1650
- rememberPlatformConfigForToken(tokens.accessToken, platformConfig);
1651
- return {
1652
- accessToken: tokens.accessToken,
1653
- user: storedConfigUser
1654
- };
1655
- }
1656
- if (!tokens.refreshToken) throw new Error(multiline`
1657
- Token expired.
1658
- Please run 'tailor login' and try again.
1659
- `);
1660
- const client = initOAuth2Client(platformConfig);
1661
- let resp;
1662
- try {
1663
- resp = await client.refreshToken({
1664
- accessToken: tokens.accessToken,
1665
- refreshToken: tokens.refreshToken,
1666
- expiresAt: Date.parse(userEntry.token_expires_at)
1667
- });
1668
- } catch {
1669
- throw new Error(multiline`
1670
- Failed to refresh token. Your session may have expired.
1671
- Please run 'tailor login' and try again.
1672
- `);
1673
- }
1674
- const newExpiresAt = new Date(assertDefined(resp.expiresAt, "token refresh response missing expiresAt")).toISOString();
1675
- let resolvedUser = storedConfigUser;
1676
- const previousEmail = userEntry.email ?? inferEmailFromUserId(user) ?? inferEmailFromUserId(storedConfigUser);
1677
- let email = previousEmail;
1678
- if (shouldResolveSubjectOnRefresh(user, userEntry) || shouldResolveSubjectOnRefresh(storedConfigUser, userEntry)) try {
1679
- const userInfo = await fetchUserInfo(resp.accessToken, platformConfig);
1680
- resolvedUser = userInfo.sub;
1681
- email = userInfo.email;
1682
- } catch (error) {
1683
- logger.debug(`Failed to resolve refreshed token user info: ${String(error)}`);
1684
- }
1685
- await saveUserTokens(config, resolvedUser, {
1686
- accessToken: resp.accessToken,
1687
- refreshToken: resp.refreshToken ?? void 0
1688
- }, newExpiresAt, {
1689
- platformConfig,
1690
- email
1691
- });
1692
- await removeLegacyUserAlias(config, user, resolvedUser, platformConfig);
1693
- if (storedUser !== platformUserKey(resolvedUser, platformConfig)) {
1694
- if (config.users[storedUser]?.storage === "keyring") await deleteKeyringTokens(storedUser);
1695
- delete config.users[storedUser];
1696
- }
1697
- if (previousEmail && email && previousEmail !== email) logger.info(`Updated local user email from "${previousEmail}" to "${email}".`);
1698
- writePlatformConfig(config);
1699
- rememberPlatformConfigForToken(resp.accessToken, platformConfig);
1700
- return {
1701
- accessToken: resp.accessToken,
1702
- user: resolvedUser
1703
- };
1704
- }
1705
- const DEFAULT_CONFIG_FILENAME = "tailor.config.ts";
1706
- /**
1707
- * Load config path from command options, environment variables, or search parent directories.
1708
- * In CLI context, env fallback is also handled by politty's arg env option.
1709
- * Priority: opts/config > env/config > search parent directories
1710
- * @param configPath - Optional explicit config path
1711
- * @returns Resolved config path or undefined
1712
- */
1713
- function loadConfigPath(configPath) {
1714
- if (configPath) return configPath;
1715
- if (process.env.TAILOR_CONFIG_PATH) return process.env.TAILOR_CONFIG_PATH;
1716
- return findUpSync(DEFAULT_CONFIG_FILENAME);
1717
- }
1718
-
1719
- //#endregion
1720
- //#region src/cli/shared/mock.ts
1721
- /**
1722
- * Install a stub `globalThis.tailordb` so that user code loaded by the CLI
1723
- * (e.g. via `createGetDB` in `@tailor-platform/sdk/kysely`) can reference
1724
- * `tailordb.Client` without hitting a `ReferenceError`. The CLI never
1725
- * actually executes the user code paths that issue queries, so a no-op
1726
- * client suffices.
1727
- *
1728
- * Exposed as a function (rather than a top-level statement) so that
1729
- * `package.json#sideEffects` can keep the file marked side-effect-free
1730
- * without bundlers eliminating the install step.
1731
- */
1732
- function installCliTailordbStub() {
1733
- globalThis.tailordb = { Client: class {
1734
- constructor(_config) {}
1735
- async connect() {}
1736
- async end() {}
1737
- async queryObject() {
1738
- return {};
1739
- }
1740
- } };
1741
- }
1742
-
1743
- //#endregion
1744
- //#region src/cli/shared/config-loader.ts
1745
- /**
1746
- * Load Tailor configuration file and associated plugins.
1747
- * @param configPath - Optional explicit config path
1748
- * @param options - Optional module import behavior.
1749
- * @returns Loaded config, plugins, and config path
1750
- */
1751
- async function loadConfig(configPath, options = {}) {
1752
- installCliTailordbStub();
1753
- const foundPath = loadConfigPath(configPath);
1754
- if (!foundPath) throw new Error("Configuration file not found: tailor.config.ts not found in current or parent directories");
1755
- const resolvedPath = path.resolve(process.cwd(), foundPath);
1756
- if (!fs$1.existsSync(resolvedPath)) throw new Error(`Configuration file not found: ${configPath}`);
1757
- const configUrl = pathToFileURL(resolvedPath);
1758
- if (options.importNonce) configUrl.searchParams.set("tailorImportNonce", options.importNonce);
1759
- const configModule = await import(configUrl.href);
1760
- if (!configModule || !configModule.default) throw new Error("Invalid Tailor config module: default export not found");
1761
- const validated = AppConfigSchema.safeParse(configModule.default);
1762
- if (!validated.success) {
1763
- const issues = validated.error.issues.map((i) => ` - ${i.path.join(".") || "(root)"}: ${i.message}`).join("\n");
1764
- throw new Error(`Invalid Tailor config in ${resolvedPath}:\n${issues}`);
1765
- }
1766
- const allPlugins = [];
1767
- for (const value of Object.values(configModule)) if (Array.isArray(value)) {
1768
- const pluginParsed = value.reduce((acc, item) => {
1769
- if (!acc.success) return acc;
1770
- const result = PluginConfigSchema.safeParse(item);
1771
- if (result.success) acc.items.push(result.data);
1772
- else acc.success = false;
1773
- return acc;
1774
- }, {
1775
- success: true,
1776
- items: []
1777
- });
1778
- if (pluginParsed.success && pluginParsed.items.length > 0) allPlugins.push(...pluginParsed.items);
1779
- }
1780
- return {
1781
- config: {
1782
- ...configModule.default,
1783
- path: resolvedPath
1784
- },
1785
- plugins: allPlugins
1786
- };
1787
- }
1788
-
1789
671
  //#endregion
1790
672
  //#region src/cli/cache/hasher.ts
1791
673
  /**
@@ -1802,7 +684,7 @@ function hashContent(content) {
1802
684
  * @returns Hex-encoded SHA-256 hash of the file content
1803
685
  */
1804
686
  function hashFile(filePath) {
1805
- const content = fs$1.readFileSync(filePath);
687
+ const content = fs.readFileSync(filePath);
1806
688
  return crypto.createHash("sha256").update(content).digest("hex");
1807
689
  }
1808
690
  /**
@@ -1871,15 +753,16 @@ function combineHash(fileHash, contextHash) {
1871
753
  /**
1872
754
  * Compute a context hash for cache invalidation across bundlers.
1873
755
  *
1874
- * Combines the source file path, serialized trigger context, tsconfig hash,
1875
- * sourcemap mode, bundle log level, and an optional prefix (e.g., serialized
1876
- * env variables) into a single SHA-256 hash.
756
+ * Combines the source file path, a caller-supplied extra context string
757
+ * (e.g. serialized workflow start-call bindings, or an HTTP adapter's method
758
+ * list), tsconfig hash, sourcemap mode, bundle log level, and an optional
759
+ * prefix (e.g., serialized env variables) into a single SHA-256 hash.
1877
760
  * @param params - Context hash computation parameters
1878
761
  * @returns SHA-256 hex digest of the combined context
1879
762
  */
1880
763
  function computeBundlerContextHash(params) {
1881
- const { sourceFile, serializedTriggerContext, tsconfig, inlineSourcemap, bundleLogLevel, prefix } = params;
1882
- return hashContent((prefix ?? "") + path.resolve(sourceFile) + serializedTriggerContext + (tsconfig ? hashFile(tsconfig) : "") + String(inlineSourcemap ?? false) + (bundleLogLevel ?? ""));
764
+ const { sourceFile, extraContext, tsconfig, inlineSourcemap, bundleLogLevel, prefix } = params;
765
+ return hashContent((prefix ?? "") + path.resolve(sourceFile) + extraContext + (tsconfig ? hashFile(tsconfig) : "") + String(inlineSourcemap ?? false) + (bundleLogLevel ?? ""));
1883
766
  }
1884
767
  /**
1885
768
  * Run a build with optional cache restore/save around it.
@@ -1931,7 +814,10 @@ function createBundleCache(store) {
1931
814
  return;
1932
815
  }
1933
816
  if (currentHash !== entry.inputHash) return;
1934
- return store.restoreBundleContent(cacheKey);
817
+ const content = store.restoreBundleContent(cacheKey);
818
+ const output = entry.outputFiles.find((file) => file.outputPath === cacheKey);
819
+ if (content === void 0 || !output || hashContent(content) !== output.contentHash) return;
820
+ return content;
1935
821
  }
1936
822
  function save(params) {
1937
823
  const { kind, namespace, name, sourceFile, content, dependencyPaths, contextHash } = params;
@@ -1978,7 +864,7 @@ function resolveRelativePluginImportPath(pluginImportPath, baseDirs) {
1978
864
  if (!pluginImportPath.startsWith(".")) return null;
1979
865
  for (const baseDir of baseDirs) {
1980
866
  const absolutePath = path.resolve(baseDir, pluginImportPath);
1981
- if (fs$1.existsSync(absolutePath)) return absolutePath;
867
+ if (fs.existsSync(absolutePath)) return absolutePath;
1982
868
  }
1983
869
  return null;
1984
870
  }
@@ -2062,13 +948,13 @@ function generatePluginExecutorFiles(executors, outputDir, typeGenerationResult,
2062
948
  function generateSingleExecutorFile(info, outputDir, typeGenerationResult, sourceTypeInfoMap, baseDirs = []) {
2063
949
  const pluginDir = sanitizePluginId$1(info.pluginId);
2064
950
  const executorOutputDir = path.join(outputDir, pluginDir, "executors");
2065
- fs$1.mkdirSync(executorOutputDir, { recursive: true });
951
+ fs.mkdirSync(executorOutputDir, { recursive: true });
2066
952
  const fileName = sanitizeExecutorFileName(info.executor.name);
2067
953
  const filePath = path.join(executorOutputDir, `${fileName}.ts`);
2068
954
  let content;
2069
955
  if (isPluginExecutorWithFile(info.executor)) content = generateExecutorFileContentNew(info, info.executor, outputDir, typeGenerationResult, sourceTypeInfoMap, baseDirs);
2070
956
  else content = generateExecutorFileContentLegacy(info.executor);
2071
- fs$1.writeFileSync(filePath, content);
957
+ fs.writeFileSync(filePath, content);
2072
958
  return filePath;
2073
959
  }
2074
960
  /**
@@ -2300,7 +1186,7 @@ function extractDynamicImportSpecifier(resolve) {
2300
1186
  function resolvePluginBaseDir(pluginImportPath, baseDirs) {
2301
1187
  if (pluginImportPath.startsWith(".")) {
2302
1188
  const resolvedPath = resolveRelativePluginImportPath(pluginImportPath, baseDirs) ?? path.resolve(baseDirs[0] ?? process.cwd(), pluginImportPath);
2303
- if (fs$1.existsSync(resolvedPath)) return fs$1.statSync(resolvedPath).isDirectory() ? resolvedPath : path.dirname(resolvedPath);
1189
+ if (fs.existsSync(resolvedPath)) return fs.statSync(resolvedPath).isDirectory() ? resolvedPath : path.dirname(resolvedPath);
2304
1190
  return path.extname(resolvedPath) ? path.dirname(resolvedPath) : resolvedPath;
2305
1191
  }
2306
1192
  for (const baseDir of baseDirs) try {
@@ -2387,11 +1273,11 @@ function generatePluginTypeFiles(types, outputDir) {
2387
1273
  seenTypeNames.set(info.type.name, info);
2388
1274
  const pluginDir = sanitizePluginId(info.pluginId);
2389
1275
  const typeOutputDir = path.join(outputDir, pluginDir, "types");
2390
- fs$1.mkdirSync(typeOutputDir, { recursive: true });
1276
+ fs.mkdirSync(typeOutputDir, { recursive: true });
2391
1277
  const fileName = `${toKebabCase(info.type.name)}.ts`;
2392
1278
  const filePath = path.join(typeOutputDir, fileName);
2393
1279
  const content = generateTypeFileContent(info);
2394
- fs$1.writeFileSync(filePath, content);
1280
+ fs.writeFileSync(filePath, content);
2395
1281
  generatedFiles.push(filePath);
2396
1282
  const relativePath = path.relative(outputDir, filePath);
2397
1283
  typeFilePaths.set(info.type.name, relativePath);
@@ -2512,20 +1398,6 @@ function toCamelCase(str) {
2512
1398
  return result.charAt(0).toLowerCase() + result.slice(1);
2513
1399
  }
2514
1400
 
2515
- //#endregion
2516
- //#region src/cli/services/stale-cleanup.ts
2517
- /**
2518
- * Remove stale `.entry.js` files from the output directory.
2519
- *
2520
- * Must be called before parallel bundling; concurrent builds
2521
- * sharing the same output directory would otherwise conflict.
2522
- * @param outputDir - Directory to clean
2523
- */
2524
- async function removeStaleEntryFiles(outputDir) {
2525
- const files = await fs.readdir(outputDir);
2526
- await Promise.all(files.filter((file) => file.endsWith(".entry.js")).map((file) => fs.rm(path.join(outputDir, file), { force: true })));
2527
- }
2528
-
2529
1401
  //#endregion
2530
1402
  //#region src/cli/services/workflow/ast-utils.ts
2531
1403
  /**
@@ -2571,18 +1443,18 @@ function argumentSourceText(arg, sourceText) {
2571
1443
  if (arg && typeof arg === "object" && "start" in arg && "end" in arg) return sourceText.slice(arg.start, arg.end);
2572
1444
  }
2573
1445
  /**
2574
- * Get metadata for a static `identifier.trigger(...)` call.
1446
+ * Get metadata for a static `identifier.start(...)` call.
2575
1447
  * @param node - AST node to inspect
2576
1448
  * @param sourceText - Source code text
2577
- * @returns Trigger call metadata, or null when the node is not a trigger call
1449
+ * @returns Start call metadata, or null when the node is not a start call
2578
1450
  */
2579
- function getTriggerCallInfo(node, sourceText) {
1451
+ function getStartCallInfo(node, sourceText) {
2580
1452
  if (!node || typeof node !== "object" || node.type !== "CallExpression") return null;
2581
1453
  const callExpr = node;
2582
1454
  const callee = callExpr.callee;
2583
1455
  if (callee.type !== "MemberExpression") return null;
2584
1456
  const memberExpr = callee;
2585
- if (memberExpr.computed || memberExpr.property.name !== "trigger" || memberExpr.object.type !== "Identifier") return null;
1457
+ if (memberExpr.computed || memberExpr.property.name !== "start" || memberExpr.object.type !== "Identifier") return null;
2586
1458
  return {
2587
1459
  identifierName: memberExpr.object.name,
2588
1460
  callRange: {
@@ -2865,9 +1737,9 @@ function findAllWorkflows(program, _sourceText) {
2865
1737
  }
2866
1738
 
2867
1739
  //#endregion
2868
- //#region src/cli/shared/trigger-context.ts
1740
+ //#region src/cli/shared/start-context.ts
2869
1741
  /**
2870
- * Normalize a source module path for trigger binding lookup.
1742
+ * Normalize a source module path for start-call binding lookup.
2871
1743
  * @param filePath - Source file path or extensionless relative import path
2872
1744
  * @returns Absolute path without a JavaScript or TypeScript extension
2873
1745
  */
@@ -2922,19 +1794,20 @@ function createModuleBindings(program, source) {
2922
1794
  };
2923
1795
  }
2924
1796
  /**
2925
- * Build trigger context from configured workflow source files.
1797
+ * Build start-call context from configured workflow source files.
2926
1798
  * @param workflowConfig - Workflow file loading configuration
2927
1799
  * @param authNamespace - Auth service namespace (optional, used for string-literal invoker expansion)
1800
+ * @param baseDir - Directory the workflow config's file patterns are resolved against (defaults to process.cwd())
2928
1801
  * @returns Module-local workflow and job binding metadata
2929
1802
  */
2930
- async function buildTriggerContext(workflowConfig, authNamespace) {
1803
+ async function buildStartContext(workflowConfig, authNamespace, baseDir = process.cwd()) {
2931
1804
  const modules = /* @__PURE__ */ new Map();
2932
1805
  if (!workflowConfig) return {
2933
1806
  modules,
2934
1807
  authNamespace
2935
1808
  };
2936
- for (const file of loadFilesWithIgnores(workflowConfig)) try {
2937
- const source = await fs$1.promises.readFile(file, "utf-8");
1809
+ for (const file of loadFilesWithIgnores(workflowConfig, baseDir)) try {
1810
+ const source = await fs.promises.readFile(file, "utf-8");
2938
1811
  const { program } = parseSync("input.ts", source);
2939
1812
  modules.set(normalizeFilePath(file), createModuleBindings(program, source));
2940
1813
  } catch (error) {
@@ -2954,11 +1827,11 @@ function sortedTargets(bindings) {
2954
1827
  ]);
2955
1828
  }
2956
1829
  /**
2957
- * Serialize trigger context to a deterministic cache input.
2958
- * @param context - Trigger context to serialize
1830
+ * Serialize start-call context to a deterministic cache input.
1831
+ * @param context - Start-call context to serialize
2959
1832
  * @returns Deterministic string, or an empty string when context is absent
2960
1833
  */
2961
- function serializeTriggerContext(context) {
1834
+ function serializeStartContext(context) {
2962
1835
  if (!context) return "";
2963
1836
  const modules = [...context.modules].toSorted(([a], [b]) => a.localeCompare(b)).map(([file, bindings]) => [
2964
1837
  file,
@@ -2969,12 +1842,23 @@ function serializeTriggerContext(context) {
2969
1842
  }
2970
1843
 
2971
1844
  //#endregion
2972
- //#region src/cli/services/workflow/trigger-transformer.ts
2973
- const NORMALIZER_IDENTIFIER = "__tailor_normalizeTriggerOptions";
1845
+ //#region src/cli/services/workflow/start-transformer.ts
1846
+ const START_CALL_RE = /\.start(?:\s|\/\*[\s\S]*?\*\/|\/\/[^\n]*\n)*\(/;
1847
+ /**
1848
+ * Fast pre-check for whether `code` contains a `.start(` call, tolerating
1849
+ * whitespace, newlines, and comments between `.start` and `(` that a plain
1850
+ * substring check would miss.
1851
+ * @param code - Source text to scan
1852
+ * @returns Whether `code` contains a `.start(` call
1853
+ */
1854
+ function hasStartCall(code) {
1855
+ return START_CALL_RE.test(code);
1856
+ }
1857
+ const NORMALIZER_IDENTIFIER = "__tailor_normalizeStartOptions";
2974
1858
  /**
2975
1859
  * Build the source text of the injected normalizer helper.
2976
1860
  *
2977
- * Renames an `invoker` in the trigger options to the `authInvoker` form the
1861
+ * Renames an `invoker` in the start options to the `authInvoker` form the
2978
1862
  * platform RPC expects: a plain string (machine user name) becomes
2979
1863
  * `{ namespace, machineUserName }`, while an object form passes through
2980
1864
  * as-is. Any other options value is unchanged. The auth namespace is baked
@@ -3102,42 +1986,42 @@ function collectLocalTargets(program, context, currentFilePath) {
3102
1986
  }
3103
1987
  return targets;
3104
1988
  }
3105
- function detectTriggerCallsWithTargets(program, sourceText, targets) {
1989
+ function detectStartCallsWithTargets(program, sourceText, targets) {
3106
1990
  const calls = [];
3107
1991
  walkBindingAware(program, new Set(targets.keys()), (node, shadowedNames) => {
3108
- const triggerCall = getTriggerCallInfo(node, sourceText);
3109
- if (!triggerCall || shadowedNames.has(triggerCall.identifierName)) return;
3110
- const target = targets.get(triggerCall.identifierName);
1992
+ const startCall = getStartCallInfo(node, sourceText);
1993
+ if (!startCall || shadowedNames.has(startCall.identifierName)) return;
1994
+ const target = targets.get(startCall.identifierName);
3111
1995
  if (target) calls.push({
3112
- ...triggerCall,
1996
+ ...startCall,
3113
1997
  kind: target.kind,
3114
1998
  targetName: target.name
3115
1999
  });
3116
2000
  });
3117
2001
  return calls;
3118
2002
  }
3119
- function detectResolvedTriggerCalls(program, sourceText, context, currentFilePath) {
3120
- return detectTriggerCallsWithTargets(program, sourceText, collectLocalTargets(program, context, currentFilePath));
2003
+ function detectResolvedStartCalls(program, sourceText, context, currentFilePath) {
2004
+ return detectStartCallsWithTargets(program, sourceText, collectLocalTargets(program, context, currentFilePath));
3121
2005
  }
3122
- function transformFunctionTriggers(source, triggerContext, currentFilePath) {
2006
+ function transformStartCalls(source, startContext, currentFilePath) {
3123
2007
  const { program } = parseSync("input.ts", source);
3124
- const localTargets = collectLocalTargets(program, triggerContext, currentFilePath);
3125
- const { authNamespace } = triggerContext;
3126
- const allTriggerCalls = detectTriggerCallsWithTargets(program, source, localTargets);
3127
- const nestedTriggerCalls = [];
3128
- const triggerCalls = allTriggerCalls.filter((call) => {
3129
- const parent = allTriggerCalls.find((other) => other !== call && other.callRange.start <= call.callRange.start && call.callRange.end <= other.callRange.end);
2008
+ const localTargets = collectLocalTargets(program, startContext, currentFilePath);
2009
+ const { authNamespace } = startContext;
2010
+ const allStartCalls = detectStartCallsWithTargets(program, source, localTargets);
2011
+ const nestedStartCalls = [];
2012
+ const startCalls = allStartCalls.filter((call) => {
2013
+ const parent = allStartCalls.find((other) => other !== call && other.callRange.start <= call.callRange.start && call.callRange.end <= other.callRange.end);
3130
2014
  if (!parent) return true;
3131
- nestedTriggerCalls.push({
2015
+ nestedStartCalls.push({
3132
2016
  call,
3133
2017
  parent
3134
2018
  });
3135
2019
  return false;
3136
2020
  });
3137
- for (const { call, parent } of nestedTriggerCalls) logger.warn(`Nested trigger call "${call.identifierName}.trigger(...)" inside "${parent.identifierName}.trigger(...)" cannot be converted. Move it to a separate statement and pass the result instead.`);
2021
+ for (const { call, parent } of nestedStartCalls) logger.warn(`Nested start call "${call.identifierName}.start(...)" inside "${parent.identifierName}.start(...)" cannot be converted. Move it to a separate statement and pass the result instead.`);
3138
2022
  const replacements = [];
3139
2023
  let needsNormalizerHelper = false;
3140
- for (const call of triggerCalls) {
2024
+ for (const call of startCalls) {
3141
2025
  let transformedCall;
3142
2026
  if (call.kind === "workflow") {
3143
2027
  let optionsPart = "";
@@ -3145,10 +2029,10 @@ function transformFunctionTriggers(source, triggerContext, currentFilePath) {
3145
2029
  optionsPart = `, ${NORMALIZER_IDENTIFIER}(${call.optionsText})`;
3146
2030
  needsNormalizerHelper = true;
3147
2031
  } else optionsPart = `, ${call.optionsText}`;
3148
- transformedCall = `tailor.workflow.triggerWorkflow(${JSON.stringify(call.targetName)}, ${call.argsText || "undefined"}${optionsPart})`;
2032
+ transformedCall = `tailor.workflow.startWorkflow(${JSON.stringify(call.targetName)}, ${call.argsText || "undefined"}${optionsPart})`;
3149
2033
  } else {
3150
2034
  const optionsPart = call.optionsText !== void 0 ? `, ${call.optionsText}` : "";
3151
- transformedCall = `tailor.workflow.triggerJobFunction(${JSON.stringify(call.targetName)}, ${call.argsText || "undefined"}${optionsPart})`;
2035
+ transformedCall = `tailor.workflow.startJobFunction(${JSON.stringify(call.targetName)}, ${call.argsText || "undefined"}${optionsPart})`;
3152
2036
  }
3153
2037
  replacements.push({
3154
2038
  start: call.callRange.start,
@@ -3159,15 +2043,15 @@ function transformFunctionTriggers(source, triggerContext, currentFilePath) {
3159
2043
  const transformed = applyReplacements(source, replacements);
3160
2044
  return needsNormalizerHelper && authNamespace ? buildNormalizerHelperSource(authNamespace) + transformed : transformed;
3161
2045
  }
3162
- function createTriggerTransformPlugin(triggerContext) {
3163
- if (!triggerContext) return void 0;
2046
+ function createStartTransformPlugin(startContext) {
2047
+ if (!startContext) return void 0;
3164
2048
  return {
3165
- name: "trigger-transform",
2049
+ name: "start-transform",
3166
2050
  transform: {
3167
2051
  filter: { id: { include: [/\.(ts|mts|cts|js|mjs|cjs)$/] } },
3168
2052
  handler(code, id) {
3169
- if (!code.includes(".trigger(")) return null;
3170
- return { code: transformFunctionTriggers(code, triggerContext, id) };
2053
+ if (!hasStartCall(code)) return null;
2054
+ return { code: transformStartCalls(code, startContext, id) };
3171
2055
  }
3172
2056
  }
3173
2057
  };
@@ -3264,34 +2148,77 @@ const platformBundleDefinePlugin = {
3264
2148
  }
3265
2149
  };
3266
2150
 
2151
+ //#endregion
2152
+ //#region src/cli/shared/resolve-tsconfig.ts
2153
+ const warnedBaseDirs = /* @__PURE__ */ new Set();
2154
+ /**
2155
+ * Resolve the nearest tsconfig.json for baseDir, falling back to the tsconfig
2156
+ * resolved from the invocation cwd when baseDir's own ancestry has none.
2157
+ * @param baseDir - Directory to resolve the tsconfig against
2158
+ * @returns Absolute path to the resolved tsconfig.json, or undefined if none was found
2159
+ */
2160
+ async function resolveTSConfigWithFallback(baseDir) {
2161
+ const tsconfig = await tryResolve(baseDir);
2162
+ if (tsconfig || baseDir === process.cwd()) return tsconfig;
2163
+ const fallback = await tryResolve(process.cwd());
2164
+ if (fallback && !warnedBaseDirs.has(baseDir)) {
2165
+ 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.`);
2167
+ }
2168
+ return fallback;
2169
+ }
2170
+ async function tryResolve(dir) {
2171
+ try {
2172
+ return await resolveTSConfig(dir);
2173
+ } catch {
2174
+ return;
2175
+ }
2176
+ }
2177
+
2178
+ //#endregion
2179
+ //#region src/cli/shared/virtual-entry.ts
2180
+ /**
2181
+ * Create an in-memory rolldown entry module with a deterministic ID.
2182
+ * @param name - Logical entry name
2183
+ * @param code - Entry module source
2184
+ * @param sourceType - Parser type for the generated module
2185
+ * @returns Rolldown input and plugin for loading the entry
2186
+ */
2187
+ function createVirtualEntry(name, code, sourceType = "js") {
2188
+ const input = `tailor-sdk-entry:${name}.${sourceType}`;
2189
+ const resolvedId = `\0${input}`;
2190
+ return {
2191
+ input,
2192
+ plugin: {
2193
+ name: "tailor-sdk-virtual-entry",
2194
+ resolveId(source, importer) {
2195
+ return source === input && importer === void 0 ? resolvedId : null;
2196
+ },
2197
+ load(id) {
2198
+ return id === resolvedId ? code : null;
2199
+ }
2200
+ }
2201
+ };
2202
+ }
2203
+
3267
2204
  //#endregion
3268
2205
  //#region src/cli/services/auth/bundler.ts
3269
2206
  /**
3270
2207
  * Bundle a single auth hook handler.
3271
2208
  *
3272
2209
  * Follows the same pattern as the executor bundler:
3273
- * 1. Generate an entry file that re-exports the handler as `main`
2210
+ * 1. Generate an in-memory entry module that re-exports the handler as `main`
3274
2211
  * 2. Bundle with rolldown + tree-shaking
3275
2212
  * @param options - Bundle options
3276
2213
  * @returns Map of function name to bundled code
3277
2214
  */
3278
2215
  async function bundleAuthHooks(options) {
3279
- const { configPath, authName, handlerAccessPath, env = {}, triggerContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG" } = options;
2216
+ const { configPath, authName, handlerAccessPath, env = {}, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG", baseDir } = options;
3280
2217
  logger.newline();
3281
2218
  logger.log(`Bundling auth hook for ${styles.info(`"${authName}"`)}`);
3282
- const outputDir = path.resolve(getDistDir(), "auth-hooks");
3283
- fs$1.mkdirSync(outputDir, { recursive: true });
3284
- await removeStaleEntryFiles(outputDir);
3285
- let tsconfig;
3286
- try {
3287
- tsconfig = await resolveTSConfig();
3288
- } catch {
3289
- tsconfig = void 0;
3290
- }
3291
- const functionName = `auth-hook--${authName}--before-login`;
3292
2219
  const absoluteConfigPath = path.resolve(configPath);
3293
- const serializedTriggerContext = serializeTriggerContext(triggerContext);
3294
- const sortedEnvPrefix = JSON.stringify(Object.fromEntries(Object.entries(env).toSorted(([a], [b]) => a.localeCompare(b))));
2220
+ const tsconfig = await resolveTSConfigWithFallback(baseDir);
2221
+ const functionName = `auth-hook--${authName}--before-login`;
3295
2222
  const code = await withCache({
3296
2223
  cache,
3297
2224
  kind: "auth-hook",
@@ -3299,14 +2226,13 @@ async function bundleAuthHooks(options) {
3299
2226
  sourceFile: absoluteConfigPath,
3300
2227
  contextHash: computeBundlerContextHash({
3301
2228
  sourceFile: absoluteConfigPath,
3302
- serializedTriggerContext,
2229
+ extraContext: serializeStartContext(startContext),
3303
2230
  tsconfig,
3304
2231
  inlineSourcemap,
3305
2232
  bundleLogLevel,
3306
- prefix: sortedEnvPrefix
2233
+ prefix: JSON.stringify(Object.fromEntries(Object.entries(env).toSorted(([a], [b]) => a.localeCompare(b))))
3307
2234
  }),
3308
2235
  async build(cachePlugins) {
3309
- const entryPath = path.join(outputDir, `${functionName}.entry.js`);
3310
2236
  const entryContent = multiline`
3311
2237
  import _config from "${absoluteConfigPath}";
3312
2238
  const __auth_hook_function = _config.${handlerAccessPath};
@@ -3315,12 +2241,13 @@ async function bundleAuthHooks(options) {
3315
2241
  return await __auth_hook_function({ ...args, env });
3316
2242
  }
3317
2243
  `;
3318
- fs$1.writeFileSync(entryPath, entryContent);
3319
- const triggerPlugin = createTriggerTransformPlugin(triggerContext);
3320
- const plugins = triggerPlugin ? [triggerPlugin] : [];
2244
+ const entry = createVirtualEntry(`auth-hook:${functionName}`, entryContent);
2245
+ const startPlugin = createStartTransformPlugin(startContext);
2246
+ const plugins = [entry.plugin];
2247
+ if (startPlugin) plugins.push(startPlugin);
3321
2248
  plugins.push(platformBundleDefinePlugin, ...cachePlugins);
3322
2249
  return (await rolldown.build({
3323
- input: entryPath,
2250
+ input: entry.input,
3324
2251
  write: false,
3325
2252
  output: {
3326
2253
  format: "esm",
@@ -3685,6 +2612,36 @@ function findOmittedPermitRules(rawPermissions) {
3685
2612
  });
3686
2613
  return locations;
3687
2614
  }
2615
+ /**
2616
+ * Check whether GraphQL exposure is fully disabled for a type, given its
2617
+ * effective gqlOperations (the type's own setting, falling back to the
2618
+ * TailorDB namespace default). `undefined` means the default of all
2619
+ * operations enabled, so it is never considered fully disabled.
2620
+ * @param gqlOperations - Effective, normalized gqlOperations configuration
2621
+ * @returns Whether create, update, delete, and read are all explicitly disabled
2622
+ */
2623
+ function isGqlOperationsFullyDisabled(gqlOperations) {
2624
+ if (!gqlOperations) return false;
2625
+ return gqlOperations.create === false && gqlOperations.update === false && gqlOperations.delete === false && gqlOperations.read === false;
2626
+ }
2627
+ /**
2628
+ * Find missing permission configuration for a TailorDB type.
2629
+ *
2630
+ * Record-level permission is always required: TailorDB denies all record
2631
+ * operations for a type without it, regardless of whether the type is
2632
+ * exposed via GraphQL. GraphQL permission is required whenever GraphQL
2633
+ * exposure is enabled for the type (the default, unless every operation is
2634
+ * explicitly disabled via `gqlOperations`).
2635
+ * @param rawPermissions - Raw permissions definition for the type
2636
+ * @param effectiveGqlOperations - The type's own gqlOperations, falling back to the namespace default
2637
+ * @returns Which permission configuration, if any, is missing
2638
+ */
2639
+ function findMissingPermissionConfig(rawPermissions, effectiveGqlOperations) {
2640
+ return {
2641
+ missingPermission: !rawPermissions.record,
2642
+ missingGqlPermission: !rawPermissions.gql && !isGqlOperationsFullyDisabled(effectiveGqlOperations)
2643
+ };
2644
+ }
3688
2645
 
3689
2646
  //#endregion
3690
2647
  //#region src/parser/service/tailordb/type-parser.ts
@@ -4221,7 +3178,7 @@ function buildMinimalEntryFromResolved(imports, declarations, fnSource, sourceFi
4221
3178
  ].join("\n");
4222
3179
  }
4223
3180
  async function bundleScriptTarget(args) {
4224
- const { fn, kind, sourceFilePath, sourceBindings, tempDir, targetIndex, tsconfig } = args;
3181
+ const { fn, kind, sourceFilePath, sourceBindings, typeName, targetIndex, tsconfig } = args;
4225
3182
  const context = `${kind} in ${sourceFilePath}`;
4226
3183
  const fnSource = stringifyFunction(fn);
4227
3184
  if ((kind === "typeValidate" || kind === "validate") && fn.constructor.name === "AsyncFunction") throw new Error(`${context} must be synchronous — the generated validator runs synchronously, so issues reported after an await are silently lost. Remove the async keyword.`);
@@ -4233,11 +3190,10 @@ async function bundleScriptTarget(args) {
4233
3190
  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.
4234
3191
  ${kind}: ${fnSource}`);
4235
3192
  const entryContent = buildMinimalEntryFromResolved(imports, declarations, fnSource, sourceFilePath, kind === "typeValidate");
4236
- const entryPath = join(tempDir, `tailordb-script-${targetIndex}.entry.ts`);
4237
- writeFileSync(entryPath, entryContent);
3193
+ const entry = createVirtualEntry(`tailordb-script:${typeName}:${targetIndex}`, entryContent, "ts");
4238
3194
  const bundledCode = (await rolldown.build({
4239
- plugins: [platformBundleDefinePlugin],
4240
- input: entryPath,
3195
+ plugins: [entry.plugin, platformBundleDefinePlugin],
3196
+ input: entry.input,
4241
3197
  write: false,
4242
3198
  output: {
4243
3199
  format: "cjs",
@@ -4267,27 +3223,18 @@ async function precompileTailorDBTypeScripts(type, sourceFilePath, tsconfig) {
4267
3223
  const targets = collectScriptTargets(type);
4268
3224
  if (targets.length === 0) return;
4269
3225
  const sourceBindings = collectSourceBindings(sourceFilePath);
4270
- const tempDir = resolve(getDistDir(), "hooks-validate-scripts", type.name);
4271
- mkdirSync(tempDir, { recursive: true });
4272
- try {
4273
- const results = await Promise.allSettled(targets.map((target, index) => bundleScriptTarget({
4274
- fn: target.fn,
4275
- kind: target.kind,
4276
- sourceFilePath,
4277
- sourceBindings,
4278
- tempDir,
4279
- targetIndex: index,
4280
- tsconfig
4281
- })));
4282
- const firstError = results.find((r) => r.status === "rejected");
4283
- if (firstError) throw firstError.reason;
4284
- for (const [index, result] of results.entries()) if (result.status === "fulfilled") setPrecompiledScriptExpr(assertDefined(targets[index], `bundle target at index ${index} missing`).fn, result.value);
4285
- } finally {
4286
- rmSync(tempDir, {
4287
- recursive: true,
4288
- force: true
4289
- });
4290
- }
3226
+ const results = await Promise.allSettled(targets.map((target, index) => bundleScriptTarget({
3227
+ fn: target.fn,
3228
+ kind: target.kind,
3229
+ sourceFilePath,
3230
+ sourceBindings,
3231
+ typeName: type.name,
3232
+ targetIndex: index,
3233
+ tsconfig
3234
+ })));
3235
+ const firstError = results.find((r) => r.status === "rejected");
3236
+ if (firstError) throw firstError.reason;
3237
+ for (const [index, result] of results.entries()) if (result.status === "fulfilled") setPrecompiledScriptExpr(assertDefined(targets[index], `bundle target at index ${index} missing`).fn, result.value);
4291
3238
  }
4292
3239
 
4293
3240
  //#endregion
@@ -4417,7 +3364,7 @@ function formatTailorDBTypeNameSource(source) {
4417
3364
  * @returns A new TailorDBService instance
4418
3365
  */
4419
3366
  function createTailorDBService(params) {
4420
- const { namespace, config, pluginManager } = params;
3367
+ const { namespace, config, pluginManager, baseDir } = params;
4421
3368
  const createRawTypesByName = () => Object.create(null);
4422
3369
  const rawTypes = Object.create(null);
4423
3370
  let types = {};
@@ -4445,6 +3392,19 @@ function createTailorDBService(params) {
4445
3392
  if (locations.length > 0) logger.warn(`TailorDB type "${typeName}" has permission rule(s) ${locations.join(", ")} in object form without an explicit "permit"; they default to "deny". Set permit: true (allow) or permit: false (deny) to silence this warning.`);
4446
3393
  }
4447
3394
  };
3395
+ const validateRequiredPermissions = () => {
3396
+ const errors = [];
3397
+ for (const fileTypes of Object.values(rawTypes)) for (const [typeName, type] of Object.entries(fileTypes)) {
3398
+ const effectiveGqlOperations = type.metadata.settings?.gqlOperations ?? config.gqlOperations;
3399
+ const { missingPermission, missingGqlPermission } = findMissingPermissionConfig(type.metadata.permissions, effectiveGqlOperations);
3400
+ if (!missingPermission && !missingGqlPermission) continue;
3401
+ const source = formatTailorDBTypeSourceInfo(typeSourceInfo[typeName]);
3402
+ const location = source ? ` (${source})` : "";
3403
+ if (missingPermission) errors.push(`TailorDB type "${typeName}"${location} has no .permission() configured. TailorDB denies all record operations for types without permission; call .permission(...) to grant access explicitly.`);
3404
+ if (missingGqlPermission) errors.push(`TailorDB type "${typeName}"${location} has no .gqlPermission() configured, but GraphQL operations are enabled for it. Call .gqlPermission(...) to grant GraphQL access explicitly, or disable GraphQL exposure with .features({ gqlOperations: { create: false, update: false, delete: false, read: false } }).`);
3405
+ }
3406
+ if (errors.length > 0) throw new Error(`TailorDB permission configuration errors in service "${namespace}":\n${errors.map((e) => ` - ${e}`).join("\n")}`);
3407
+ };
4448
3408
  /**
4449
3409
  * Process plugins for a type and add generated types to rawTypes
4450
3410
  * @param rawType - The raw TailorDB type being processed
@@ -4524,19 +3484,15 @@ function createTailorDBService(params) {
4524
3484
  loadTypes: async () => {
4525
3485
  if (!loadPromise) loadPromise = (async () => {
4526
3486
  if (config.files.length === 0) return;
4527
- const typeFiles = [...new Set(loadFilesWithIgnores(config))];
4528
- let tsconfig;
4529
- try {
4530
- tsconfig = await resolveTSConfig();
4531
- } catch {
4532
- tsconfig = void 0;
4533
- }
3487
+ const typeFiles = [...new Set(loadFilesWithIgnores(config, baseDir))];
3488
+ const tsconfig = await resolveTSConfigWithFallback(baseDir);
4534
3489
  logger.newline();
4535
3490
  logger.log(`Found ${styles.highlight(typeFiles.length.toString())} type files for TailorDB service ${styles.highlight(`"${namespace}"`)}`);
4536
3491
  if (pluginManager) for (const typeFile of typeFiles) await loadTypeFile(typeFile, tsconfig);
4537
3492
  else await Promise.all(typeFiles.map((typeFile) => loadTypeFile(typeFile, tsconfig)));
4538
3493
  doParseTypes();
4539
3494
  warnOmittedPermit();
3495
+ validateRequiredPermissions();
4540
3496
  return types;
4541
3497
  })();
4542
3498
  return loadPromise;
@@ -4578,7 +3534,10 @@ function createTailorDBService(params) {
4578
3534
  hasGeneratedTypes = true;
4579
3535
  logger.log(` Generated: ${styles.success(generatedType.name)} by namespace plugin ${styles.info(pluginId)}`);
4580
3536
  }
4581
- if (hasGeneratedTypes || hadPreviousGeneratedTypes) doParseTypes();
3537
+ if (hasGeneratedTypes || hadPreviousGeneratedTypes) {
3538
+ doParseTypes();
3539
+ validateRequiredPermissions();
3540
+ }
4582
3541
  }
4583
3542
  };
4584
3543
  }
@@ -4665,9 +3624,31 @@ function resolveBundleConcurrency() {
4665
3624
  * @param worker - Async worker function
4666
3625
  * @returns Worker results in input order
4667
3626
  */
4668
- function withBundleConcurrency(items, worker) {
4669
- const limit = pLimit(resolveBundleConcurrency());
4670
- return Promise.all(items.map((item) => limit(() => worker(item))));
3627
+ async function withBundleConcurrency(items, worker) {
3628
+ const resultCount = items.length;
3629
+ const workItems = items.flatMap((item, index) => [{
3630
+ index,
3631
+ item
3632
+ }]);
3633
+ const results = [];
3634
+ results.length = resultCount;
3635
+ let nextWorkIndex = 0;
3636
+ let rejection;
3637
+ const runWorker = async () => {
3638
+ while (!rejection) {
3639
+ const workItem = workItems[nextWorkIndex++];
3640
+ if (workItem === void 0) return;
3641
+ try {
3642
+ results[workItem.index] = await worker(workItem.item);
3643
+ } catch (reason) {
3644
+ rejection ??= { reason };
3645
+ }
3646
+ }
3647
+ };
3648
+ const workerCount = Math.min(resolveBundleConcurrency(), workItems.length);
3649
+ await Promise.all(Array.from({ length: workerCount }, runWorker));
3650
+ if (rejection) throw rejection.reason;
3651
+ return results;
4671
3652
  }
4672
3653
 
4673
3654
  //#endregion
@@ -4678,7 +3659,7 @@ function withBundleConcurrency(items, worker) {
4678
3659
  * Two delivery paths:
4679
3660
  * - Apply config: shipped with apply and evaluated by the platform before
4680
3661
  * invoking user code.
4681
- * - Bundle inline: interpolated into the generated `.entry.js` wrapper and
3662
+ * - Bundle inline: interpolated into the generated entry module and
4682
3663
  * evaluated inside the bundled script at function entry.
4683
3664
  *
4684
3665
  * The principal field mapping (server → SDK) shared across services is built by
@@ -4768,15 +3749,15 @@ function buildResolverOperationHookExpr(env) {
4768
3749
  * Bundle executors from the specified configuration
4769
3750
  *
4770
3751
  * This function:
4771
- * 1. Creates entry file that extracts operation.body
3752
+ * 1. Creates an in-memory entry module that extracts operation.body
4772
3753
  * 2. Bundles in a single step with tree-shaking
4773
3754
  * @param options - Bundle executor options
4774
3755
  * @returns Map of executor name to bundled code
4775
3756
  */
4776
3757
  async function bundleExecutors(options) {
4777
3758
  const bundledCode = /* @__PURE__ */ new Map();
4778
- const { config, triggerContext, additionalFiles = [], cache, inlineSourcemap, bundleLogLevel = "DEBUG" } = options;
4779
- const files = [...loadFilesWithIgnores(config), ...additionalFiles];
3759
+ const { config, startContext, additionalFiles = [], cache, inlineSourcemap, bundleLogLevel = "DEBUG", baseDir } = options;
3760
+ const files = [...loadFilesWithIgnores(config, baseDir), ...additionalFiles];
4780
3761
  if (files.length === 0) {
4781
3762
  logger.warn(`No executor files found for patterns: ${config.files.join(", ")}`);
4782
3763
  return bundledCode;
@@ -4803,25 +3784,17 @@ async function bundleExecutors(options) {
4803
3784
  logger.debug(" No function executors to bundle");
4804
3785
  return bundledCode;
4805
3786
  }
4806
- const outputDir = path.resolve(getDistDir(), "executors");
4807
- fs$1.mkdirSync(outputDir, { recursive: true });
4808
- await removeStaleEntryFiles(outputDir);
4809
- let tsconfig;
4810
- try {
4811
- tsconfig = await resolveTSConfig();
4812
- } catch {
4813
- tsconfig = void 0;
4814
- }
4815
- const results = await withBundleConcurrency(executors, (executor) => bundleSingleExecutor(executor, outputDir, tsconfig, triggerContext, cache, inlineSourcemap, bundleLogLevel));
3787
+ const tsconfig = await resolveTSConfigWithFallback(baseDir);
3788
+ const results = await withBundleConcurrency(executors, (executor) => bundleSingleExecutor(executor, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel));
4816
3789
  for (const [name, code] of results) bundledCode.set(name, code);
4817
3790
  logger.log(`${styles.success("Bundled")} ${styles.info("\"executor\"")}`);
4818
3791
  return bundledCode;
4819
3792
  }
4820
- async function bundleSingleExecutor(executor, outputDir, tsconfig, triggerContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
4821
- const serializedTriggerContext = serializeTriggerContext(triggerContext);
3793
+ async function bundleSingleExecutor(executor, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
3794
+ const serializedStartContext = serializeStartContext(startContext);
4822
3795
  const contextHash = computeBundlerContextHash({
4823
3796
  sourceFile: executor.sourceFile,
4824
- serializedTriggerContext,
3797
+ extraContext: serializedStartContext,
4825
3798
  tsconfig,
4826
3799
  inlineSourcemap,
4827
3800
  bundleLogLevel
@@ -4833,7 +3806,6 @@ async function bundleSingleExecutor(executor, outputDir, tsconfig, triggerContex
4833
3806
  sourceFile: executor.sourceFile,
4834
3807
  contextHash,
4835
3808
  async build(cachePlugins) {
4836
- const entryPath = path.join(outputDir, `${executor.name}.entry.js`);
4837
3809
  const entryContent = multiline`
4838
3810
  import _internalExecutor from "${path.resolve(executor.sourceFile)}";
4839
3811
 
@@ -4844,12 +3816,13 @@ async function bundleSingleExecutor(executor, outputDir, tsconfig, triggerContex
4844
3816
 
4845
3817
  export { __executor_function as main };
4846
3818
  `;
4847
- fs$1.writeFileSync(entryPath, entryContent);
4848
- const triggerPlugin = createTriggerTransformPlugin(triggerContext);
4849
- const plugins = triggerPlugin ? [triggerPlugin] : [];
3819
+ const entry = createVirtualEntry(`executor:${executor.name}`, entryContent);
3820
+ const startPlugin = createStartTransformPlugin(startContext);
3821
+ const plugins = [entry.plugin];
3822
+ if (startPlugin) plugins.push(startPlugin);
4850
3823
  plugins.push(platformBundleDefinePlugin, ...cachePlugins);
4851
3824
  return (await rolldown.build({
4852
- input: entryPath,
3825
+ input: entry.input,
4853
3826
  write: false,
4854
3827
  output: {
4855
3828
  format: "esm",
@@ -4921,31 +3894,25 @@ const GRAPHQL_WEB_MODULE = createRequire(import.meta.url).resolve("@0no-co/graph
4921
3894
  * IIFE defining a global `transform(input)` entry point. `input` gets a
4922
3895
  * generated dispatcher that routes by `req.method`; `output` is used as is.
4923
3896
  * @param adapters - Detected adapters to bundle
3897
+ * @param baseDir - Directory the owning config's tsconfig is resolved against
4924
3898
  * @param cache - Optional bundle cache for skipping unchanged builds
4925
3899
  * @param bundleLogLevel - Controls which console calls are kept in bundled code
4926
3900
  * @returns Bundled scripts keyed by adapter name
4927
3901
  */
4928
- async function bundleHttpAdapters(adapters, cache, bundleLogLevel = "DEBUG") {
3902
+ async function bundleHttpAdapters(adapters, baseDir, cache, bundleLogLevel = "DEBUG") {
4929
3903
  if (adapters.length === 0) return {
4930
3904
  bundledInputs: /* @__PURE__ */ new Map(),
4931
3905
  bundledOutputs: /* @__PURE__ */ new Map()
4932
3906
  };
4933
3907
  logger.newline();
4934
3908
  logger.log(`Bundling ${styles.highlight(adapters.length.toString())} files for ${styles.info("\"http-adapter\"")}`);
4935
- const outputDir = path.resolve(getDistDir(), "http-adapters");
4936
- fs$1.mkdirSync(outputDir, { recursive: true });
4937
- let tsconfig;
4938
- try {
4939
- tsconfig = await resolveTSConfig();
4940
- } catch {
4941
- tsconfig = void 0;
4942
- }
3909
+ const tsconfig = await resolveTSConfigWithFallback(baseDir);
4943
3910
  const results = await withBundleConcurrency(adapters.flatMap((adapter) => {
4944
3911
  return (adapter.hasOutput ? ["input", "output"] : ["input"]).map((kind) => ({
4945
3912
  adapter,
4946
3913
  kind
4947
3914
  }));
4948
- }), ({ adapter, kind }) => bundleAdapterScript(adapter, kind, outputDir, tsconfig, cache, bundleLogLevel));
3915
+ }), ({ adapter, kind }) => bundleAdapterScript(adapter, kind, tsconfig, cache, bundleLogLevel));
4949
3916
  const bundledInputs = /* @__PURE__ */ new Map();
4950
3917
  const bundledOutputs = /* @__PURE__ */ new Map();
4951
3918
  for (const [name, kind, code] of results) if (kind === "input") bundledInputs.set(name, code);
@@ -4956,10 +3923,10 @@ async function bundleHttpAdapters(adapters, cache, bundleLogLevel = "DEBUG") {
4956
3923
  bundledOutputs
4957
3924
  };
4958
3925
  }
4959
- async function bundleAdapterScript(adapter, kind, outputDir, tsconfig, cache, bundleLogLevel = "DEBUG") {
3926
+ async function bundleAdapterScript(adapter, kind, tsconfig, cache, bundleLogLevel = "DEBUG") {
4960
3927
  const contextHash = computeBundlerContextHash({
4961
3928
  sourceFile: adapter.sourceFile,
4962
- serializedTriggerContext: kind === "input" ? adapter.methods.join(",") : "",
3929
+ extraContext: kind === "input" ? adapter.methods.join(",") : "",
4963
3930
  tsconfig,
4964
3931
  inlineSourcemap: false,
4965
3932
  bundleLogLevel,
@@ -4972,9 +3939,11 @@ async function bundleAdapterScript(adapter, kind, outputDir, tsconfig, cache, bu
4972
3939
  sourceFile: adapter.sourceFile,
4973
3940
  contextHash,
4974
3941
  async build(cachePlugins) {
4975
- const entryPath = path.join(outputDir, `${adapter.name}.${kind}.entry.js`);
4976
3942
  const absoluteSourcePath = path.resolve(adapter.sourceFile);
3943
+ const entryContent = kind === "input" ? buildInputEntry(absoluteSourcePath, adapter.methods, GRAPHQL_WEB_MODULE) : buildOutputEntry(absoluteSourcePath);
3944
+ const entry = createVirtualEntry(`http-adapter:${adapter.name}:${kind}`, entryContent);
4977
3945
  const plugins = [
3946
+ entry.plugin,
4978
3947
  {
4979
3948
  name: "http-adapter-reject-node-imports",
4980
3949
  resolveId(source) {
@@ -4998,30 +3967,21 @@ async function bundleAdapterScript(adapter, kind, outputDir, tsconfig, cache, bu
4998
3967
  },
4999
3968
  ...cachePlugins
5000
3969
  ];
5001
- let bundled;
5002
- try {
5003
- const entryContent = kind === "input" ? buildInputEntry(absoluteSourcePath, adapter.methods, GRAPHQL_WEB_MODULE) : buildOutputEntry(absoluteSourcePath);
5004
- fs$1.writeFileSync(entryPath, entryContent);
5005
- bundled = (await rolldown.build({
5006
- input: entryPath,
5007
- write: false,
5008
- output: {
5009
- format: "iife",
5010
- sourcemap: false,
5011
- minify: true,
5012
- codeSplitting: false
5013
- },
5014
- tsconfig,
5015
- plugins,
5016
- transform: { target: "es2017" },
5017
- treeshake: composeFunctionTreeshakeOptions([createLogLevelTreeshakeOptions(bundleLogLevel)]),
5018
- logLevel: "silent"
5019
- })).output[0].code;
5020
- } finally {
5021
- try {
5022
- fs$1.rmSync(entryPath, { force: true });
5023
- } catch {}
5024
- }
3970
+ const bundled = (await rolldown.build({
3971
+ input: entry.input,
3972
+ write: false,
3973
+ output: {
3974
+ format: "iife",
3975
+ sourcemap: false,
3976
+ minify: true,
3977
+ codeSplitting: false
3978
+ },
3979
+ tsconfig,
3980
+ plugins,
3981
+ transform: { target: "es2017" },
3982
+ treeshake: composeFunctionTreeshakeOptions([createLogLevelTreeshakeOptions(bundleLogLevel)]),
3983
+ logLevel: "silent"
3984
+ })).output[0].code;
5025
3985
  const byteLength = Buffer.byteLength(bundled, "utf8");
5026
3986
  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`);
5027
3987
  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`);
@@ -5095,7 +4055,7 @@ function rejectAsyncInBundle(code, adapterName, kind) {
5095
4055
  //#endregion
5096
4056
  //#region src/cli/services/http-adapter/service.ts
5097
4057
  function createHttpAdapterService(params) {
5098
- const { config } = params;
4058
+ const { config, baseDir } = params;
5099
4059
  let adapters = [];
5100
4060
  let fileCount = 0;
5101
4061
  let loaded = false;
@@ -5109,7 +4069,7 @@ function createHttpAdapterService(params) {
5109
4069
  },
5110
4070
  loadAdapters: async () => {
5111
4071
  if (loaded) return;
5112
- const result = await loadAdapterFiles(config);
4072
+ const result = await loadAdapterFiles(config, baseDir);
5113
4073
  adapters = result.adapters;
5114
4074
  fileCount = result.fileCount;
5115
4075
  loaded = true;
@@ -5125,12 +4085,12 @@ function createHttpAdapterService(params) {
5125
4085
  }
5126
4086
  };
5127
4087
  }
5128
- async function loadAdapterFiles(config) {
4088
+ async function loadAdapterFiles(config, baseDir) {
5129
4089
  if (config.files.length === 0) return {
5130
4090
  adapters: [],
5131
4091
  fileCount: 0
5132
4092
  };
5133
- const files = loadFilesWithIgnores(config);
4093
+ const files = loadFilesWithIgnores(config, baseDir);
5134
4094
  const loadResults = await Promise.all(files.map(loadAdapterFromFile));
5135
4095
  const adapters = [];
5136
4096
  const seenNames = /* @__PURE__ */ new Map();
@@ -5220,19 +4180,20 @@ async function loadResolver(resolverFilePath) {
5220
4180
  *
5221
4181
  * This function:
5222
4182
  * 1. Uses a transform plugin to add validation wrapper during bundling
5223
- * 2. Creates entry file
4183
+ * 2. Creates an in-memory entry module
5224
4184
  * 3. Bundles in a single step with tree-shaking
5225
4185
  * @param namespace - Resolver namespace name
5226
4186
  * @param config - Resolver file loading configuration
5227
- * @param triggerContext - Trigger context for workflow/job transformations
4187
+ * @param baseDir - Directory the config's file patterns are resolved against
4188
+ * @param startContext - Start context for workflow/job transformations
5228
4189
  * @param cache - Optional bundle cache for skipping unchanged builds
5229
4190
  * @param inlineSourcemap - Whether to enable inline sourcemaps
5230
4191
  * @param bundleLogLevel - Controls which console calls are kept in bundled code
5231
4192
  * @returns Map of resolver name to bundled code
5232
4193
  */
5233
- async function bundleResolvers(namespace, config, triggerContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
4194
+ async function bundleResolvers(namespace, config, baseDir, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
5234
4195
  const bundledCode = /* @__PURE__ */ new Map();
5235
- const files = loadFilesWithIgnores(config);
4196
+ const files = loadFilesWithIgnores(config, baseDir);
5236
4197
  if (files.length === 0) {
5237
4198
  logger.warn(`No resolver files found for patterns: ${config.files.join(", ")}`);
5238
4199
  return bundledCode;
@@ -5251,25 +4212,17 @@ async function bundleResolvers(namespace, config, triggerContext, cache, inlineS
5251
4212
  sourceFile: file
5252
4213
  });
5253
4214
  }
5254
- const outputDir = path.resolve(getDistDir(), "resolvers");
5255
- fs$1.mkdirSync(outputDir, { recursive: true });
5256
- await removeStaleEntryFiles(outputDir);
5257
- let tsconfig;
5258
- try {
5259
- tsconfig = await resolveTSConfig();
5260
- } catch {
5261
- tsconfig = void 0;
5262
- }
5263
- const results = await withBundleConcurrency(resolvers, (resolver) => bundleSingleResolver(namespace, resolver, outputDir, tsconfig, triggerContext, cache, inlineSourcemap, bundleLogLevel));
4215
+ const tsconfig = await resolveTSConfigWithFallback(baseDir);
4216
+ const results = await withBundleConcurrency(resolvers, (resolver) => bundleSingleResolver(namespace, resolver, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel));
5264
4217
  for (const [name, code] of results) bundledCode.set(name, code);
5265
4218
  logger.log(`${styles.success("Bundled")} ${styles.info(`"${namespace}"`)}`);
5266
4219
  return bundledCode;
5267
4220
  }
5268
- async function bundleSingleResolver(namespace, resolver, outputDir, tsconfig, triggerContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
5269
- const serializedTriggerContext = serializeTriggerContext(triggerContext);
4221
+ async function bundleSingleResolver(namespace, resolver, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
4222
+ const serializedStartContext = serializeStartContext(startContext);
5270
4223
  const contextHash = computeBundlerContextHash({
5271
4224
  sourceFile: resolver.sourceFile,
5272
- serializedTriggerContext,
4225
+ extraContext: serializedStartContext,
5273
4226
  tsconfig,
5274
4227
  inlineSourcemap,
5275
4228
  bundleLogLevel
@@ -5282,7 +4235,6 @@ async function bundleSingleResolver(namespace, resolver, outputDir, tsconfig, tr
5282
4235
  sourceFile: resolver.sourceFile,
5283
4236
  contextHash,
5284
4237
  async build(cachePlugins) {
5285
- const entryPath = path.join(outputDir, `${resolver.name}.entry.js`);
5286
4238
  const entryContent = multiline`
5287
4239
  import _internalResolver from "${path.resolve(resolver.sourceFile)}";
5288
4240
  import { t } from "@tailor-platform/sdk";
@@ -5309,12 +4261,13 @@ async function bundleSingleResolver(namespace, resolver, outputDir, tsconfig, tr
5309
4261
 
5310
4262
  export { $tailor_resolver_body as main };
5311
4263
  `;
5312
- fs$1.writeFileSync(entryPath, entryContent);
5313
- const triggerPlugin = createTriggerTransformPlugin(triggerContext);
5314
- const plugins = triggerPlugin ? [triggerPlugin] : [];
4264
+ const entry = createVirtualEntry(`resolver:${resolver.name}`, entryContent);
4265
+ const startPlugin = createStartTransformPlugin(startContext);
4266
+ const plugins = [entry.plugin];
4267
+ if (startPlugin) plugins.push(startPlugin);
5315
4268
  plugins.push(platformBundleDefinePlugin, ...cachePlugins);
5316
4269
  return (await rolldown.build({
5317
- input: entryPath,
4270
+ input: entry.input,
5318
4271
  write: false,
5319
4272
  output: {
5320
4273
  format: "esm",
@@ -5338,9 +4291,10 @@ async function bundleSingleResolver(namespace, resolver, outputDir, tsconfig, tr
5338
4291
  * Creates a new ResolverService instance.
5339
4292
  * @param namespace - The namespace for this resolver service
5340
4293
  * @param config - The resolver service configuration
4294
+ * @param baseDir - Directory the config's file patterns are resolved against
5341
4295
  * @returns A new ResolverService instance
5342
4296
  */
5343
- function createResolverService(namespace, config) {
4297
+ function createResolverService(namespace, config, baseDir) {
5344
4298
  const resolvers = {};
5345
4299
  const loadResolverForFile = async (resolverFile) => {
5346
4300
  try {
@@ -5369,7 +4323,7 @@ function createResolverService(namespace, config) {
5369
4323
  loadResolvers: async () => {
5370
4324
  if (Object.keys(resolvers).length > 0) return;
5371
4325
  if (config.files.length === 0) return;
5372
- const resolverFiles = loadFilesWithIgnores(config);
4326
+ const resolverFiles = loadFilesWithIgnores(config, baseDir);
5373
4327
  logger.log(`Found ${styles.highlight(resolverFiles.length.toString())} resolver files for service ${styles.highlight(`"${namespace}"`)}`);
5374
4328
  await Promise.all(resolverFiles.map((resolverFile) => loadResolverForFile(resolverFile)));
5375
4329
  assertUniqueResolverNames(resolvers, namespace);
@@ -5502,7 +4456,7 @@ function transformWorkflowSource(source, targetJobName, targetJobExportName, oth
5502
4456
  function safeRealpath(p) {
5503
4457
  const resolved = path.resolve(p);
5504
4458
  try {
5505
- return fs$1.realpathSync(resolved);
4459
+ return fs.realpathSync(resolved);
5506
4460
  } catch (e) {
5507
4461
  logger.debug(`realpathSync failed for ${resolved}: ${e instanceof Error ? e.message : e}`);
5508
4462
  return resolved;
@@ -5513,20 +4467,21 @@ function safeRealpath(p) {
5513
4467
  *
5514
4468
  * This function:
5515
4469
  * 1. Detects which jobs are actually used (mainJobs + their dependencies)
5516
- * 2. Uses a transform plugin to transform trigger calls during bundling
5517
- * 3. Creates entry file and bundles with tree-shaking
4470
+ * 2. Uses a transform plugin to transform start calls during bundling
4471
+ * 3. Creates an in-memory entry module and bundles with tree-shaking
5518
4472
  *
5519
4473
  * Returns metadata about which jobs each workflow uses.
5520
4474
  * @param allJobs - All available job infos
5521
4475
  * @param mainJobNames - Names of main jobs
5522
4476
  * @param env - Environment variables to inject
5523
- * @param triggerContext - Trigger context for transformations
4477
+ * @param startContext - Start context for transformations
4478
+ * @param baseDir - Directory the owning config's tsconfig is resolved against
5524
4479
  * @param cache - Optional bundle cache for skipping unchanged builds
5525
4480
  * @param inlineSourcemap - Whether to enable inline sourcemaps
5526
4481
  * @param bundleLogLevel - Controls which console calls are kept in bundled code
5527
4482
  * @returns Workflow job bundling result
5528
4483
  */
5529
- async function bundleWorkflowJobs(allJobs, mainJobNames, env = {}, triggerContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
4484
+ async function bundleWorkflowJobs(allJobs, mainJobNames, env = {}, startContext, baseDir, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
5530
4485
  if (allJobs.length === 0) {
5531
4486
  logger.warn("No workflow jobs to bundle");
5532
4487
  return {
@@ -5535,22 +4490,11 @@ async function bundleWorkflowJobs(allJobs, mainJobNames, env = {}, triggerContex
5535
4490
  bundledCode: /* @__PURE__ */ new Map()
5536
4491
  };
5537
4492
  }
5538
- const { usedJobs, mainJobDeps } = await filterUsedJobs(allJobs, mainJobNames, triggerContext);
4493
+ const { usedJobs, mainJobDeps } = await filterUsedJobs(allJobs, mainJobNames, startContext);
5539
4494
  logger.newline();
5540
4495
  logger.log(`Bundling ${styles.highlight(usedJobs.length.toString())} files for ${styles.info("\"workflow-job\"")}`);
5541
- const outputDir = path.resolve(getDistDir(), "workflow-jobs");
5542
- fs$1.mkdirSync(outputDir, { recursive: true });
5543
- const currentJobNames = new Set(usedJobs.map((j) => j.name));
5544
- const existingFiles = fs$1.readdirSync(outputDir);
5545
- for (const file of existingFiles) if (file.endsWith(".js") && !currentJobNames.has(path.basename(file, ".js"))) fs$1.rmSync(path.join(outputDir, file), { force: true });
5546
- else if (file.endsWith(".js.map") && !currentJobNames.has(path.basename(file, ".js.map"))) fs$1.rmSync(path.join(outputDir, file), { force: true });
5547
- let tsconfig;
5548
- try {
5549
- tsconfig = await resolveTSConfig();
5550
- } catch {
5551
- tsconfig = void 0;
5552
- }
5553
- const results = await withBundleConcurrency(usedJobs, (job) => bundleSingleJob(job, usedJobs, outputDir, tsconfig, env, triggerContext, cache, inlineSourcemap, bundleLogLevel));
4496
+ const tsconfig = await resolveTSConfigWithFallback(baseDir);
4497
+ const results = await withBundleConcurrency(usedJobs, (job) => bundleSingleJob(job, usedJobs, tsconfig, env, startContext, cache, inlineSourcemap, bundleLogLevel));
5554
4498
  const bundledCode = /* @__PURE__ */ new Map();
5555
4499
  for (const [name, code] of results) bundledCode.set(name, code);
5556
4500
  logger.log(`${styles.success("Bundled")} ${styles.info("\"workflow-job\"")}`);
@@ -5564,15 +4508,15 @@ async function bundleWorkflowJobs(allJobs, mainJobNames, env = {}, triggerContex
5564
4508
  * Filter jobs to only include those that are actually used.
5565
4509
  * A job is "used" if:
5566
4510
  * - It's a mainJob of a workflow
5567
- * - It's called via .trigger() from another used job (transitively)
4511
+ * - It's called via .start() from another used job (transitively)
5568
4512
  *
5569
4513
  * Also returns a map of mainJob -> all jobs it depends on (for metadata).
5570
4514
  * @param allJobs - All available job infos
5571
4515
  * @param mainJobNames - Names of main jobs
5572
- * @param triggerContext - Module binding metadata for resolving trigger targets
4516
+ * @param startContext - Module binding metadata for resolving start targets
5573
4517
  * @returns Used jobs and main job dependency map
5574
4518
  */
5575
- async function filterUsedJobs(allJobs, mainJobNames, triggerContext) {
4519
+ async function filterUsedJobs(allJobs, mainJobNames, startContext) {
5576
4520
  if (allJobs.length === 0 || mainJobNames.length === 0) return {
5577
4521
  usedJobs: [],
5578
4522
  mainJobDeps: {}
@@ -5586,16 +4530,16 @@ async function filterUsedJobs(allJobs, mainJobNames, triggerContext) {
5586
4530
  const dependencies = /* @__PURE__ */ new Map();
5587
4531
  const fileResults = await Promise.all(Array.from(jobsBySourceFile.entries()).map(async ([sourceFile, jobs]) => {
5588
4532
  try {
5589
- const source = await fs$1.promises.readFile(sourceFile, "utf-8");
4533
+ const source = await fs.promises.readFile(sourceFile, "utf-8");
5590
4534
  const { program } = parseSync("input.ts", source);
5591
4535
  const detectedJobs = findAllJobs(program, source);
5592
- const triggerCalls = detectResolvedTriggerCalls(program, source, triggerContext, sourceFile);
4536
+ const startCalls = detectResolvedStartCalls(program, source, startContext, sourceFile);
5593
4537
  const jobDependencies = [];
5594
4538
  for (const job of jobs) {
5595
4539
  const detectedJob = detectedJobs.find((d) => d.name === job.name);
5596
4540
  if (!detectedJob) continue;
5597
4541
  const jobDeps = /* @__PURE__ */ new Set();
5598
- for (const call of triggerCalls) if (call.kind === "job" && call.callRange.start >= detectedJob.bodyValueRange.start && call.callRange.end <= detectedJob.bodyValueRange.end) jobDeps.add(call.targetName);
4542
+ for (const call of startCalls) if (call.kind === "job" && call.callRange.start >= detectedJob.bodyValueRange.start && call.callRange.end <= detectedJob.bodyValueRange.end) jobDeps.add(call.targetName);
5599
4543
  if (jobDeps.size > 0) jobDependencies.push({
5600
4544
  jobName: job.name,
5601
4545
  deps: jobDeps
@@ -5626,12 +4570,12 @@ async function filterUsedJobs(allJobs, mainJobNames, triggerContext) {
5626
4570
  mainJobDeps
5627
4571
  };
5628
4572
  }
5629
- async function bundleSingleJob(job, allJobs, outputDir, tsconfig, env, triggerContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
5630
- const serializedTriggerContext = serializeTriggerContext(triggerContext);
4573
+ async function bundleSingleJob(job, allJobs, tsconfig, env, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG") {
4574
+ const serializedStartContext = serializeStartContext(startContext);
5631
4575
  const sortedEnvPrefix = JSON.stringify(Object.fromEntries(Object.entries(env).toSorted(([a], [b]) => a.localeCompare(b))));
5632
4576
  const contextHash = computeBundlerContextHash({
5633
4577
  sourceFile: job.sourceFile,
5634
- serializedTriggerContext,
4578
+ extraContext: serializedStartContext,
5635
4579
  tsconfig,
5636
4580
  inlineSourcemap,
5637
4581
  bundleLogLevel,
@@ -5644,7 +4588,6 @@ async function bundleSingleJob(job, allJobs, outputDir, tsconfig, env, triggerCo
5644
4588
  sourceFile: job.sourceFile,
5645
4589
  contextHash,
5646
4590
  async build(cachePlugins) {
5647
- const entryPath = path.join(outputDir, `${job.name}.entry.js`);
5648
4591
  const absoluteSourcePath = path.resolve(job.sourceFile);
5649
4592
  const entryContent = multiline`
5650
4593
  import { ${job.exportName} } from "${absoluteSourcePath}";
@@ -5655,19 +4598,20 @@ async function bundleSingleJob(job, allJobs, outputDir, tsconfig, env, triggerCo
5655
4598
  return await ${job.exportName}.body(input, { env, invoker });
5656
4599
  }
5657
4600
  `;
5658
- fs$1.writeFileSync(entryPath, entryContent);
4601
+ const entry = createVirtualEntry(`workflow-job:${job.name}`, entryContent);
5659
4602
  const resolvedSourceFile = safeRealpath(job.sourceFile);
5660
4603
  const otherJobExportNames = allJobs.filter((candidate) => candidate.name !== job.name && safeRealpath(candidate.sourceFile) === resolvedSourceFile).map((j) => j.exportName);
5661
4604
  const plugins = [
4605
+ entry.plugin,
5662
4606
  {
5663
4607
  name: "workflow-transform",
5664
4608
  transform: {
5665
4609
  filter: { id: { include: [/\.(ts|mts|cts|js|mjs|cjs)$/] } },
5666
4610
  handler(code, id) {
5667
- if (!code.includes("createWorkflowJob") && !code.includes("createWorkflow") && !code.includes(".trigger(")) return null;
4611
+ if (!code.includes("createWorkflowJob") && !code.includes("createWorkflow") && !hasStartCall(code)) return null;
5668
4612
  let transformed = code;
5669
4613
  if (safeRealpath(id) === resolvedSourceFile) transformed = transformWorkflowSource(code, job.name, job.exportName, otherJobExportNames);
5670
- if (transformed.includes(".trigger(")) transformed = transformFunctionTriggers(transformed, triggerContext, id);
4614
+ if (hasStartCall(transformed)) transformed = transformStartCalls(transformed, startContext, id);
5671
4615
  if (transformed === code) return null;
5672
4616
  return { code: transformed };
5673
4617
  }
@@ -5677,7 +4621,7 @@ async function bundleSingleJob(job, allJobs, outputDir, tsconfig, env, triggerCo
5677
4621
  ...cachePlugins
5678
4622
  ];
5679
4623
  return (await rolldown.build({
5680
- input: entryPath,
4624
+ input: entry.input,
5681
4625
  write: false,
5682
4626
  output: {
5683
4627
  format: "esm",
@@ -5699,7 +4643,7 @@ async function bundleSingleJob(job, allJobs, outputDir, tsconfig, env, triggerCo
5699
4643
  //#region src/parser/service/workflow/schema.ts
5700
4644
  const WorkflowJobSchema = z.strictObject({
5701
4645
  name: z.string().describe("Job name (must be unique across the project)"),
5702
- trigger: functionSchema.describe("Trigger function that initiates the job"),
4646
+ start: functionSchema.describe("Start function that initiates the job"),
5703
4647
  body: functionSchema.describe("Job implementation function")
5704
4648
  });
5705
4649
  const durationUnits = [
@@ -5736,7 +4680,7 @@ const RetryPolicySchema = z.strictObject({
5736
4680
  });
5737
4681
  const ConcurrencyPolicySchema = z.strictObject({ maxConcurrentExecutions: z.number().int().min(1).max(1e3).describe("Maximum number of concurrent executions (1-1000)") });
5738
4682
  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");
5739
- 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 triggerJobFunction's executionPolicyKey option");
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");
5740
4684
  const WorkflowJobFunctionExecutionPolicySchema = z.strictObject({
5741
4685
  name: ExecutionPolicyNameSchema,
5742
4686
  key: ExecutionPolicyKeySchema,
@@ -5751,9 +4695,9 @@ const WorkflowSchema = z.strictObject({
5751
4695
 
5752
4696
  //#endregion
5753
4697
  //#region src/cli/services/workflow/service.ts
5754
- function stripRuntimeTrigger(workflow) {
5755
- if (!isSdkBranded(workflow, "workflow") || workflow === null || typeof workflow !== "object" || !("trigger" in workflow)) return workflow;
5756
- const { trigger: _trigger, ...rest } = workflow;
4698
+ function stripRuntimeStart(workflow) {
4699
+ if (!isSdkBranded(workflow, "workflow") || workflow === null || typeof workflow !== "object" || !("start" in workflow)) return workflow;
4700
+ const { start: _start, ...rest } = workflow;
5757
4701
  return rest;
5758
4702
  }
5759
4703
  /**
@@ -5762,7 +4706,7 @@ function stripRuntimeTrigger(workflow) {
5762
4706
  * @returns A new WorkflowService instance
5763
4707
  */
5764
4708
  function createWorkflowService(params) {
5765
- const { config } = params;
4709
+ const { config, baseDir } = params;
5766
4710
  let workflows = {};
5767
4711
  let workflowSources = [];
5768
4712
  let jobs = [];
@@ -5784,7 +4728,7 @@ function createWorkflowService(params) {
5784
4728
  },
5785
4729
  loadWorkflows: async () => {
5786
4730
  if (loaded) return;
5787
- const result = await loadAndCollectJobs(config);
4731
+ const result = await loadAndCollectJobs(config, baseDir);
5788
4732
  workflows = result.workflows;
5789
4733
  workflowSources = result.workflowSources;
5790
4734
  jobs = result.jobs;
@@ -5806,9 +4750,10 @@ function createWorkflowService(params) {
5806
4750
  * Load workflow files and collect all jobs in a single pass.
5807
4751
  * Dependencies are detected at bundle time via AST analysis.
5808
4752
  * @param config - Workflow service configuration
4753
+ * @param baseDir - Directory the config's file patterns are resolved against
5809
4754
  * @returns Loaded workflows and collected jobs
5810
4755
  */
5811
- async function loadAndCollectJobs(config) {
4756
+ async function loadAndCollectJobs(config, baseDir) {
5812
4757
  const workflows = {};
5813
4758
  const workflowSources = [];
5814
4759
  const collectedJobs = [];
@@ -5818,7 +4763,7 @@ async function loadAndCollectJobs(config) {
5818
4763
  jobs: collectedJobs,
5819
4764
  fileCount: 0
5820
4765
  };
5821
- const workflowFiles = loadFilesWithIgnores(config);
4766
+ const workflowFiles = loadFilesWithIgnores(config, baseDir);
5822
4767
  const fileCount = workflowFiles.length;
5823
4768
  const allJobsMap = /* @__PURE__ */ new Map();
5824
4769
  const loadResults = await Promise.all(workflowFiles.map(async (workflowFile) => {
@@ -5863,7 +4808,7 @@ async function loadFileContent(filePath) {
5863
4808
  const module = await import(pathToFileURL(filePath).href);
5864
4809
  for (const [exportName, exportValue] of Object.entries(module)) {
5865
4810
  if (exportName === "default") {
5866
- const workflowResult = WorkflowSchema.safeParse(stripRuntimeTrigger(exportValue));
4811
+ const workflowResult = WorkflowSchema.safeParse(stripRuntimeStart(exportValue));
5867
4812
  if (workflowResult.success) workflow = workflowResult.data;
5868
4813
  else if (isSdkBranded(exportValue, ["workflow", "workflow-job"])) throw workflowResult.error;
5869
4814
  continue;
@@ -6131,7 +5076,7 @@ const StaticWebsiteSchema = z.strictObject({
6131
5076
 
6132
5077
  //#endregion
6133
5078
  //#region src/cli/services/application.ts
6134
- function defineTailorDB(config, pluginManager) {
5079
+ function defineTailorDB(config, baseDir, pluginManager) {
6135
5080
  const tailorDBServices = [];
6136
5081
  const externalTailorDBNamespaces = [];
6137
5082
  const subgraphs = [];
@@ -6146,7 +5091,8 @@ function defineTailorDB(config, pluginManager) {
6146
5091
  const tailorDB = createTailorDBService({
6147
5092
  namespace,
6148
5093
  config: TailorDBServiceConfigSchema.parse(serviceConfig),
6149
- pluginManager
5094
+ pluginManager,
5095
+ baseDir
6150
5096
  });
6151
5097
  tailorDBServices.push(tailorDB);
6152
5098
  }
@@ -6161,7 +5107,7 @@ function defineTailorDB(config, pluginManager) {
6161
5107
  subgraphs
6162
5108
  };
6163
5109
  }
6164
- function defineResolver(config) {
5110
+ function defineResolver(config, baseDir) {
6165
5111
  const resolverServices = [];
6166
5112
  const subgraphs = [];
6167
5113
  if (!config) return {
@@ -6170,7 +5116,7 @@ function defineResolver(config) {
6170
5116
  };
6171
5117
  for (const [namespace, serviceConfig] of Object.entries(config)) {
6172
5118
  if (!("external" in serviceConfig)) {
6173
- const resolverService = createResolverService(namespace, serviceConfig);
5119
+ const resolverService = createResolverService(namespace, serviceConfig, baseDir);
6174
5120
  resolverServices.push(resolverService);
6175
5121
  }
6176
5122
  subgraphs.push({
@@ -6232,17 +5178,26 @@ function defineAuth(config, tailorDBServices, externalTailorDBNamespaces) {
6232
5178
  subgraphs
6233
5179
  };
6234
5180
  }
6235
- function defineExecutor(config, hasPluginExecutors) {
5181
+ function defineExecutor(config, baseDir, hasPluginExecutors) {
6236
5182
  if (!config && !hasPluginExecutors) return;
6237
- return createExecutorService({ config: config ?? { files: [] } });
5183
+ return createExecutorService({
5184
+ config: config ?? { files: [] },
5185
+ baseDir
5186
+ });
6238
5187
  }
6239
- function defineWorkflow(config) {
5188
+ function defineWorkflow(config, baseDir) {
6240
5189
  if (!config) return;
6241
- return createWorkflowService({ config });
5190
+ return createWorkflowService({
5191
+ config,
5192
+ baseDir
5193
+ });
6242
5194
  }
6243
- function defineHttpAdapterService(config) {
5195
+ function defineHttpAdapterService(config, baseDir) {
6244
5196
  if (!config) return;
6245
- return createHttpAdapterService({ config });
5197
+ return createHttpAdapterService({
5198
+ config,
5199
+ baseDir
5200
+ });
6246
5201
  }
6247
5202
  function stripStaticWebsiteUrlHelper(config) {
6248
5203
  const configWithUrl = config;
@@ -6294,9 +5249,9 @@ function parseSecretManager(config) {
6294
5249
  ignoreNullishValues
6295
5250
  };
6296
5251
  }
6297
- function defineServices(config, pluginManager) {
6298
- const tailordbResult = defineTailorDB(config.db, pluginManager);
6299
- const resolverResult = defineResolver(config.resolver);
5252
+ function defineServices(config, baseDir, pluginManager) {
5253
+ const tailordbResult = defineTailorDB(config.db, baseDir, pluginManager);
5254
+ const resolverResult = defineResolver(config.resolver, baseDir);
6300
5255
  const idpResult = defineIdp(config.idp);
6301
5256
  const authResult = defineAuth(config.auth, tailordbResult.tailorDBServices, tailordbResult.externalTailorDBNamespaces);
6302
5257
  const staticWebsiteServices = defineStaticWebsites(config.staticWebsites);
@@ -6352,10 +5307,11 @@ function buildApplication(params) {
6352
5307
  */
6353
5308
  function defineApplication(params) {
6354
5309
  const { config, pluginManager } = params;
6355
- const services = defineServices(config, pluginManager);
6356
- const executorService = defineExecutor(config.executor, false);
6357
- const workflowService = defineWorkflow(config.workflow);
6358
- const httpAdapterService = defineHttpAdapterService(config.httpAdapter);
5310
+ const baseDir = path.dirname(config.path);
5311
+ const services = defineServices(config, baseDir, pluginManager);
5312
+ const executorService = defineExecutor(config.executor, baseDir, false);
5313
+ const workflowService = defineWorkflow(config.workflow, baseDir);
5314
+ const httpAdapterService = defineHttpAdapterService(config.httpAdapter, baseDir);
6359
5315
  return buildApplication({
6360
5316
  config,
6361
5317
  ...services,
@@ -6400,22 +5356,23 @@ function generatePluginFilesIfNeeded(pluginManager, tailorDBServices, configPath
6400
5356
  */
6401
5357
  async function loadApplication(params) {
6402
5358
  const { config, pluginManager, bundleCache } = params;
6403
- const { tailordbResult, resolverResult, idpResult, authResult, staticWebsiteServices, aiGatewayServices, secrets, ignoreNullishValues } = defineServices(config, pluginManager);
5359
+ const baseDir = path.dirname(config.path);
5360
+ const { tailordbResult, resolverResult, idpResult, authResult, staticWebsiteServices, aiGatewayServices, secrets, ignoreNullishValues } = defineServices(config, baseDir, pluginManager);
6404
5361
  for (const tailordb of tailordbResult.tailorDBServices) {
6405
5362
  await tailordb.loadTypes();
6406
5363
  await tailordb.processNamespacePlugins();
6407
5364
  }
6408
5365
  assertUniqueLocalTailorDBTypeNames({ tailorDBServices: tailordbResult.tailorDBServices });
6409
5366
  const pluginExecutorFiles = generatePluginFilesIfNeeded(pluginManager, tailordbResult.tailorDBServices, config.path);
6410
- const executorService = defineExecutor(config.executor, pluginExecutorFiles.length > 0);
6411
- const workflowService = defineWorkflow(config.workflow);
5367
+ const executorService = defineExecutor(config.executor, baseDir, pluginExecutorFiles.length > 0);
5368
+ const workflowService = defineWorkflow(config.workflow, baseDir);
6412
5369
  if (workflowService) await workflowService.loadWorkflows();
6413
- const httpAdapterService = defineHttpAdapterService(config.httpAdapter);
5370
+ const httpAdapterService = defineHttpAdapterService(config.httpAdapter, baseDir);
6414
5371
  if (httpAdapterService) await httpAdapterService.loadAdapters();
6415
- const triggerContext = await buildTriggerContext(config.workflow, getApplicationAuthNamespace({
5372
+ const startContext = await buildStartContext(config.workflow, getApplicationAuthNamespace({
6416
5373
  authService: authResult.authService,
6417
5374
  config
6418
- }));
5375
+ }), baseDir);
6419
5376
  const inlineSourcemap = resolveInlineSourcemap(config.inlineSourcemap);
6420
5377
  const bundleLogLevel = resolveBundleLogLevel(config.logLevel);
6421
5378
  const bundledScripts = {
@@ -6425,21 +5382,22 @@ async function loadApplication(params) {
6425
5382
  authHooks: /* @__PURE__ */ new Map()
6426
5383
  };
6427
5384
  for (const pipeline of resolverResult.resolverServices) {
6428
- const resolverBundles = await bundleResolvers(pipeline.namespace, pipeline.config, triggerContext, bundleCache, inlineSourcemap, bundleLogLevel);
5385
+ const resolverBundles = await bundleResolvers(pipeline.namespace, pipeline.config, baseDir, startContext, bundleCache, inlineSourcemap, bundleLogLevel);
6429
5386
  for (const [name, code] of resolverBundles) bundledScripts.resolvers.set(resolverBundleKey(pipeline.namespace, name), code);
6430
5387
  }
6431
5388
  if (executorService) bundledScripts.executors = await bundleExecutors({
6432
5389
  config: executorService.config,
6433
- triggerContext,
5390
+ startContext,
6434
5391
  additionalFiles: [...pluginExecutorFiles],
6435
5392
  cache: bundleCache,
6436
5393
  inlineSourcemap,
6437
- bundleLogLevel
5394
+ bundleLogLevel,
5395
+ baseDir
6438
5396
  });
6439
5397
  let workflowBuildResult;
6440
5398
  if (workflowService && workflowService.jobs.length > 0) {
6441
5399
  const mainJobNames = workflowService.workflowSources.map((ws) => ws.workflow.mainJob.name);
6442
- workflowBuildResult = await bundleWorkflowJobs(workflowService.jobs, mainJobNames, config.env ?? {}, triggerContext, bundleCache, inlineSourcemap, bundleLogLevel);
5400
+ workflowBuildResult = await bundleWorkflowJobs(workflowService.jobs, mainJobNames, config.env ?? {}, startContext, baseDir, bundleCache, inlineSourcemap, bundleLogLevel);
6443
5401
  bundledScripts.workflowJobs = workflowBuildResult.bundledCode;
6444
5402
  }
6445
5403
  let httpAdapterBuildResult;
@@ -6448,7 +5406,7 @@ async function loadApplication(params) {
6448
5406
  sourceFile: a.sourceFile,
6449
5407
  methods: a.methods,
6450
5408
  hasOutput: a.hasOutput
6451
- })), bundleCache, bundleLogLevel);
5409
+ })), baseDir, bundleCache, bundleLogLevel);
6452
5410
  if (authResult.authService?.config.hooks?.beforeLogin) {
6453
5411
  const authName = authResult.authService.config.name;
6454
5412
  bundledScripts.authHooks = await bundleAuthHooks({
@@ -6456,10 +5414,11 @@ async function loadApplication(params) {
6456
5414
  authName,
6457
5415
  handlerAccessPath: `auth.hooks.beforeLogin.handler`,
6458
5416
  env: config.env ?? {},
6459
- triggerContext,
5417
+ startContext,
6460
5418
  cache: bundleCache,
6461
5419
  inlineSourcemap,
6462
- bundleLogLevel
5420
+ bundleLogLevel,
5421
+ baseDir
6463
5422
  });
6464
5423
  }
6465
5424
  for (const pipeline of resolverResult.resolverServices) await pipeline.loadResolvers();
@@ -6493,5 +5452,5 @@ async function loadApplication(params) {
6493
5452
  }
6494
5453
 
6495
5454
  //#endregion
6496
- export { fetchUserInfo as $, hasAnyUserTokenEntry as A, readPlatformConfig as B, createBundleCache as C, positiveIntArg as Ct, loadConfig as D, hashFile as E, workspaceArgs as Et, loadMachineUserName as F, writePlatformConfig as G, resolveConfigUser as H, loadPlatformClientConfig as I, fetchAll as J, closeConnectionPool as K, loadStoredUserTokens as L, loadAccessToken as M, loadConfigPath as N, deleteUserTokens as O, loadConsoleBaseUrl as P, fetchPlatformMachineUserToken as Q, loadWorkspaceId as R, hasGenerationHooks as S, parseDuration as St, hashContent as T, toPageDirection as Tt, resolveUserTokenKey as U, removeLegacyUserAlias as V, saveUserTokens as W, fetchMachineUserToken as X, fetchAllTolerant as Y, fetchPaged as Z, platformBundleDefinePlugin as _, nonNegativeIntArg as _t, resolveInlineSourcemap as a, initOperatorClient as at, resolveBundleLogLevel as b, pagedLogArgs as bt, WorkflowJobSchema as c, byName as ct, INVOKER_EXPR as d, confirmationArgs as dt, getConsoleBaseUrl as et, buildExecutorArgsExpr as f, deploymentArgs as ft, stringifyFunction as g, multiConfigArg as gt, assertUniqueTailorDBTypeNamesWithExternal as h, isVerbose as ht, resolverBundleKey as i, initOAuth2Client as it, hasUserTokenEntry as j, fetchLatestToken as k, ResolverSchema as l, commonArgs as lt, assertUniqueLocalTailorDBTypeNames as m, folderArgs as mt, generatePluginFilesIfNeeded as n, getOrNull as nt, getApplicationAuthNamespace as o, isDefaultPlatform as ot, buildResolverOperationHookExpr as p, durationArg as pt, defaultPlatformBaseUrl as q, loadApplication as r, getPlatformBaseUrl as rt, WorkflowJobFunctionExecutionPolicySchema as s, resolveStaticWebsiteUrls as st, defineApplication as t, getOAuth2ClientId as tt, HTTP_METHODS as u, configArg as ut, composeFunctionTreeshakeOptions as v, orderArg as vt, getDistDir as w, resolveMachineUserInputSource as wt, getPluginGenerationDependencies as x, paginationArgs as xt, createLogLevelTreeshakeOptions as y, organizationArgs as yt, platformConfigFromProfile as z };
6497
- //# sourceMappingURL=application-Bf8wxOi6.mjs.map
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-GzW98_Xr.mjs.map