@tailor-platform/sdk 0.13.0 → 0.14.1

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.
@@ -1,4 +1,4 @@
1
- import { WORKFLOW_JOB_BRAND, getDistDir, tailorUserMap } from "./job-vYIg6hFf.mjs";
1
+ import { WORKFLOW_JOB_BRAND, getDistDir, tailorUserMap } from "./job-BGBMNqRW.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { defineCommand } from "citty";
4
4
  import * as path from "node:path";
@@ -115,16 +115,180 @@ function loadFilesWithIgnores(config) {
115
115
  return files;
116
116
  }
117
117
 
118
+ //#endregion
119
+ //#region src/parser/service/auth/schema.ts
120
+ const AuthInvokerSchema = z.object({
121
+ namespace: z.string(),
122
+ machineUserName: z.string()
123
+ });
124
+ const secretValueSchema = z.object({
125
+ vaultName: z.string(),
126
+ secretKey: z.string()
127
+ });
128
+ const samlBaseSchema = z.object({
129
+ name: z.string(),
130
+ kind: z.literal("SAML"),
131
+ spCertBase64: secretValueSchema.optional(),
132
+ spKeyBase64: secretValueSchema.optional()
133
+ });
134
+ const OIDCSchema = z.object({
135
+ name: z.string(),
136
+ kind: z.literal("OIDC"),
137
+ clientID: z.string(),
138
+ clientSecret: secretValueSchema,
139
+ providerURL: z.string(),
140
+ issuerURL: z.string().optional(),
141
+ usernameClaim: z.string().optional()
142
+ });
143
+ const SAMLSchema = samlBaseSchema.extend({
144
+ metadataURL: z.string().optional(),
145
+ rawMetadata: z.string().optional()
146
+ }).refine((value) => {
147
+ const hasMetadata = value.metadataURL !== void 0;
148
+ const hasRaw = value.rawMetadata !== void 0;
149
+ return hasMetadata !== hasRaw;
150
+ }, "Provide either metadataURL or rawMetadata");
151
+ const IDTokenSchema = z.object({
152
+ name: z.string(),
153
+ kind: z.literal("IDToken"),
154
+ providerURL: z.string(),
155
+ issuerURL: z.string().optional(),
156
+ clientID: z.string(),
157
+ usernameClaim: z.string().optional()
158
+ });
159
+ const BuiltinIdPSchema = z.object({
160
+ name: z.string(),
161
+ kind: z.literal("BuiltInIdP"),
162
+ namespace: z.string(),
163
+ clientName: z.string()
164
+ });
165
+ const IdProviderSchema = z.discriminatedUnion("kind", [
166
+ OIDCSchema,
167
+ SAMLSchema,
168
+ IDTokenSchema,
169
+ BuiltinIdPSchema
170
+ ]);
171
+ const OAuth2ClientGrantTypeSchema = z.union([z.literal("authorization_code"), z.literal("refresh_token")]);
172
+ const OAuth2ClientSchema = z.object({
173
+ description: z.string().optional(),
174
+ grantTypes: z.array(OAuth2ClientGrantTypeSchema).default(["authorization_code", "refresh_token"]),
175
+ redirectURIs: z.array(z.union([
176
+ z.templateLiteral(["https://", z.string()]),
177
+ z.templateLiteral(["http://", z.string()]),
178
+ z.templateLiteral([z.string(), ":url"]),
179
+ z.templateLiteral([
180
+ z.string(),
181
+ ":url/",
182
+ z.string()
183
+ ])
184
+ ])),
185
+ clientType: z.union([
186
+ z.literal("confidential"),
187
+ z.literal("public"),
188
+ z.literal("browser")
189
+ ]).optional()
190
+ });
191
+ const SCIMAuthorizationSchema = z.object({
192
+ type: z.union([z.literal("oauth2"), z.literal("bearer")]),
193
+ bearerSecret: secretValueSchema.optional()
194
+ });
195
+ const SCIMAttributeTypeSchema = z.union([
196
+ z.literal("string"),
197
+ z.literal("number"),
198
+ z.literal("boolean"),
199
+ z.literal("datetime"),
200
+ z.literal("complex")
201
+ ]);
202
+ const SCIMAttributeSchema = z.object({
203
+ type: SCIMAttributeTypeSchema,
204
+ name: z.string(),
205
+ description: z.string().optional(),
206
+ mutability: z.union([
207
+ z.literal("readOnly"),
208
+ z.literal("readWrite"),
209
+ z.literal("writeOnly")
210
+ ]).optional(),
211
+ required: z.boolean().optional(),
212
+ multiValued: z.boolean().optional(),
213
+ uniqueness: z.union([
214
+ z.literal("none"),
215
+ z.literal("server"),
216
+ z.literal("global")
217
+ ]).optional(),
218
+ canonicalValues: z.array(z.string()).nullable().optional(),
219
+ get subAttributes() {
220
+ return z.array(SCIMAttributeSchema).nullable().optional();
221
+ }
222
+ });
223
+ const SCIMSchemaSchema = z.object({
224
+ name: z.string(),
225
+ attributes: z.array(SCIMAttributeSchema)
226
+ });
227
+ const SCIMAttributeMappingSchema = z.object({
228
+ tailorDBField: z.string(),
229
+ scimPath: z.string()
230
+ });
231
+ const SCIMResourceSchema = z.object({
232
+ name: z.string(),
233
+ tailorDBNamespace: z.string(),
234
+ tailorDBType: z.string(),
235
+ coreSchema: SCIMSchemaSchema,
236
+ attributeMapping: z.array(SCIMAttributeMappingSchema)
237
+ });
238
+ const SCIMSchema = z.object({
239
+ machineUserName: z.string(),
240
+ authorization: SCIMAuthorizationSchema,
241
+ resources: z.array(SCIMResourceSchema)
242
+ });
243
+ const TenantProviderSchema = z.object({
244
+ namespace: z.string(),
245
+ type: z.string(),
246
+ signatureField: z.string()
247
+ });
248
+ const UserProfileSchema = z.object({
249
+ type: z.object({
250
+ name: z.string(),
251
+ fields: z.any(),
252
+ metadata: z.any(),
253
+ hooks: z.any(),
254
+ validate: z.any(),
255
+ features: z.any(),
256
+ indexes: z.any(),
257
+ files: z.any(),
258
+ permission: z.any(),
259
+ gqlPermission: z.any(),
260
+ _output: z.any()
261
+ }),
262
+ usernameField: z.string(),
263
+ attributes: z.record(z.string(), z.literal(true)).optional(),
264
+ attributeList: z.array(z.string()).optional()
265
+ });
266
+ const ValueOperandSchema = z.union([
267
+ z.string(),
268
+ z.boolean(),
269
+ z.array(z.string()),
270
+ z.array(z.boolean())
271
+ ]);
272
+ const MachineUserSchema = z.object({
273
+ attributes: z.record(z.string(), ValueOperandSchema).optional(),
274
+ attributeList: z.array(z.uuid()).optional()
275
+ });
276
+ const AuthConfigSchema = z.object({
277
+ name: z.string(),
278
+ userProfile: UserProfileSchema.optional(),
279
+ machineUsers: z.record(z.string(), MachineUserSchema).optional(),
280
+ oauth2Clients: z.record(z.string(), OAuth2ClientSchema).optional(),
281
+ idProvider: IdProviderSchema.optional(),
282
+ scim: SCIMSchema.optional(),
283
+ tenantProvider: TenantProviderSchema.optional()
284
+ }).brand("AuthConfig");
285
+
118
286
  //#endregion
119
287
  //#region src/parser/service/common.ts
120
288
  const functionSchema = z.custom((val) => typeof val === "function");
121
289
 
122
290
  //#endregion
123
291
  //#region src/parser/service/executor/schema.ts
124
- const InvokerSchema = z.object({
125
- authName: z.string(),
126
- machineUser: z.string()
127
- });
128
292
  const RecordTriggerSchema = z.object({
129
293
  kind: z.enum([
130
294
  "recordCreated",
@@ -154,14 +318,14 @@ const TriggerSchema = z.discriminatedUnion("kind", [
154
318
  const FunctionOperationSchema = z.object({
155
319
  kind: z.enum(["function", "jobFunction"]),
156
320
  body: functionSchema,
157
- invoker: InvokerSchema.optional()
321
+ authInvoker: AuthInvokerSchema.optional()
158
322
  });
159
323
  const GqlOperationSchema = z.object({
160
324
  kind: z.literal("graphql"),
161
325
  appName: z.string().optional(),
162
326
  query: z.string(),
163
327
  variables: functionSchema.optional(),
164
- invoker: InvokerSchema.optional()
328
+ authInvoker: AuthInvokerSchema.optional()
165
329
  });
166
330
  const WebhookOperationSchema = z.object({
167
331
  kind: z.literal("webhook"),
@@ -690,6 +854,568 @@ function isWorkflowJob(value) {
690
854
  return value != null && typeof value === "object" && WORKFLOW_JOB_BRAND in value && value[WORKFLOW_JOB_BRAND] === true;
691
855
  }
692
856
 
857
+ //#endregion
858
+ //#region src/cli/bundler/workflow/ast-utils.ts
859
+ /**
860
+ * Check if a module source is from \@tailor-platform/sdk (including subpaths)
861
+ */
862
+ function isTailorSdkSource(source) {
863
+ return /^@tailor-platform\/sdk(\/|$)/.test(source);
864
+ }
865
+ /**
866
+ * Get the source string from a dynamic import or require call
867
+ */
868
+ function getImportSource(node) {
869
+ if (!node) return null;
870
+ if (node.type === "ImportExpression") {
871
+ const source = node.source;
872
+ if (source.type === "Literal" && typeof source.value === "string") return source.value;
873
+ }
874
+ if (node.type === "CallExpression") {
875
+ const callExpr = node;
876
+ if (callExpr.callee.type === "Identifier" && callExpr.callee.name === "require") {
877
+ const arg = callExpr.arguments[0];
878
+ if (arg && "type" in arg && arg.type === "Literal" && "value" in arg && typeof arg.value === "string") return arg.value;
879
+ }
880
+ }
881
+ return null;
882
+ }
883
+ /**
884
+ * Unwrap AwaitExpression to get the inner expression
885
+ */
886
+ function unwrapAwait(node) {
887
+ if (node?.type === "AwaitExpression") return node.argument;
888
+ return node;
889
+ }
890
+ /**
891
+ * Check if a node is a string literal
892
+ */
893
+ function isStringLiteral(node) {
894
+ return node?.type === "Literal" && typeof node.value === "string";
895
+ }
896
+ /**
897
+ * Check if a node is a function expression (arrow or regular)
898
+ */
899
+ function isFunctionExpression(node) {
900
+ return node?.type === "ArrowFunctionExpression" || node?.type === "FunctionExpression";
901
+ }
902
+ /**
903
+ * Find a property in an object expression
904
+ */
905
+ function findProperty(properties, name) {
906
+ for (const prop of properties) if (prop.type === "Property") {
907
+ const objProp = prop;
908
+ if ((objProp.key.type === "Identifier" ? objProp.key.name : objProp.key.type === "Literal" ? objProp.key.value : null) === name) return {
909
+ key: objProp.key,
910
+ value: objProp.value,
911
+ start: objProp.start,
912
+ end: objProp.end
913
+ };
914
+ }
915
+ return null;
916
+ }
917
+ /**
918
+ * Apply string replacements to source code
919
+ * Replacements are applied from end to start to maintain positions
920
+ */
921
+ function applyReplacements(source, replacements) {
922
+ const sorted = [...replacements].sort((a, b) => b.start - a.start);
923
+ let result = source;
924
+ for (const r of sorted) result = result.slice(0, r.start) + r.text + result.slice(r.end);
925
+ return result;
926
+ }
927
+ /**
928
+ * Find the end of a statement including any trailing newline
929
+ */
930
+ function findStatementEnd(source, position) {
931
+ let i = position;
932
+ while (i < source.length && (source[i] === ";" || source[i] === " " || source[i] === " ")) i++;
933
+ if (i < source.length && source[i] === "\n") i++;
934
+ return i;
935
+ }
936
+ /**
937
+ * Resolve a relative path from a base directory
938
+ * Simple implementation that handles ./ and ../ prefixes
939
+ */
940
+ function resolvePath(baseDir, relativePath) {
941
+ const parts = relativePath.replace(/\\/g, "/").split("/");
942
+ const baseParts = baseDir.replace(/\\/g, "/").split("/");
943
+ for (const part of parts) if (part === ".") {} else if (part === "..") baseParts.pop();
944
+ else baseParts.push(part);
945
+ return baseParts.join("/");
946
+ }
947
+
948
+ //#endregion
949
+ //#region src/cli/bundler/workflow/sdk-binding-collector.ts
950
+ /**
951
+ * Collect all import bindings for a specific function from \@tailor-platform/sdk
952
+ * Returns a Set of local names that refer to the function
953
+ */
954
+ function collectSdkBindings(program, functionName) {
955
+ const bindings = /* @__PURE__ */ new Set();
956
+ function walk(node) {
957
+ if (!node || typeof node !== "object") return;
958
+ const nodeType = node.type;
959
+ if (nodeType === "ImportDeclaration") {
960
+ const importDecl = node;
961
+ const source = importDecl.source?.value;
962
+ if (typeof source === "string" && isTailorSdkSource(source)) {
963
+ for (const specifier of importDecl.specifiers || []) if (specifier.type === "ImportSpecifier") {
964
+ const importSpec = specifier;
965
+ const imported = importSpec.imported.type === "Identifier" ? importSpec.imported.name : importSpec.imported.value;
966
+ if (imported === functionName) bindings.add(importSpec.local?.name || imported);
967
+ } else if (specifier.type === "ImportDefaultSpecifier" || specifier.type === "ImportNamespaceSpecifier") {
968
+ const spec = specifier;
969
+ bindings.add(`__namespace__:${spec.local?.name}`);
970
+ }
971
+ }
972
+ }
973
+ if (nodeType === "VariableDeclaration") {
974
+ const varDecl = node;
975
+ for (const decl of varDecl.declarations || []) {
976
+ const init = unwrapAwait(decl.init);
977
+ const source = getImportSource(init);
978
+ if (source && isTailorSdkSource(source)) {
979
+ const id = decl.id;
980
+ if (id?.type === "Identifier") bindings.add(`__namespace__:${id.name}`);
981
+ else if (id?.type === "ObjectPattern") {
982
+ const objPattern = id;
983
+ for (const prop of objPattern.properties || []) if (prop.type === "Property") {
984
+ const bindingProp = prop;
985
+ const keyName = bindingProp.key.type === "Identifier" ? bindingProp.key.name : bindingProp.key.value;
986
+ if (keyName === functionName) {
987
+ const localName = bindingProp.value.type === "Identifier" ? bindingProp.value.name : keyName;
988
+ bindings.add(localName ?? "");
989
+ }
990
+ }
991
+ }
992
+ }
993
+ }
994
+ }
995
+ for (const key of Object.keys(node)) {
996
+ const child = node[key];
997
+ if (Array.isArray(child)) child.forEach((c) => walk(c));
998
+ else if (child && typeof child === "object") walk(child);
999
+ }
1000
+ }
1001
+ walk(program);
1002
+ return bindings;
1003
+ }
1004
+ /**
1005
+ * Check if a CallExpression is a call to a specific SDK function
1006
+ */
1007
+ function isSdkFunctionCall(node, bindings, functionName) {
1008
+ if (node.type !== "CallExpression") return false;
1009
+ const callee = node.callee;
1010
+ if (callee.type === "Identifier") {
1011
+ const identifier = callee;
1012
+ return bindings.has(identifier.name);
1013
+ }
1014
+ if (callee.type === "MemberExpression") {
1015
+ const memberExpr = callee;
1016
+ if (!memberExpr.computed) {
1017
+ const object = memberExpr.object;
1018
+ const property = memberExpr.property;
1019
+ if (object.type === "Identifier" && bindings.has(`__namespace__:${object.name}`) && property.name === functionName) return true;
1020
+ }
1021
+ }
1022
+ return false;
1023
+ }
1024
+
1025
+ //#endregion
1026
+ //#region src/cli/bundler/workflow/job-detector.ts
1027
+ /**
1028
+ * Find all workflow jobs by detecting createWorkflowJob calls from \@tailor-platform/sdk
1029
+ */
1030
+ function findAllJobs(program, _sourceText) {
1031
+ const jobs = [];
1032
+ const bindings = collectSdkBindings(program, "createWorkflowJob");
1033
+ function walk(node, parents = []) {
1034
+ if (!node || typeof node !== "object") return;
1035
+ if (isSdkFunctionCall(node, bindings, "createWorkflowJob")) {
1036
+ const args = node.arguments;
1037
+ if (args?.length >= 1 && args[0]?.type === "ObjectExpression") {
1038
+ const configObj = args[0];
1039
+ const nameProp = findProperty(configObj.properties, "name");
1040
+ const bodyProp = findProperty(configObj.properties, "body");
1041
+ if (nameProp && isStringLiteral(nameProp.value) && bodyProp && isFunctionExpression(bodyProp.value)) {
1042
+ let statementRange;
1043
+ let exportName;
1044
+ for (let i = parents.length - 1; i >= 0; i--) {
1045
+ const parent = parents[i];
1046
+ if (parent.type === "VariableDeclarator") {
1047
+ const declarator = parent;
1048
+ if (declarator.id?.type === "Identifier") exportName = declarator.id.name;
1049
+ }
1050
+ if (parent.type === "ExportNamedDeclaration" || parent.type === "VariableDeclaration") statementRange = {
1051
+ start: parent.start,
1052
+ end: parent.end
1053
+ };
1054
+ }
1055
+ jobs.push({
1056
+ name: nameProp.value.value,
1057
+ exportName,
1058
+ nameRange: {
1059
+ start: nameProp.start,
1060
+ end: nameProp.end
1061
+ },
1062
+ bodyValueRange: {
1063
+ start: bodyProp.value.start,
1064
+ end: bodyProp.value.end
1065
+ },
1066
+ statementRange
1067
+ });
1068
+ }
1069
+ }
1070
+ }
1071
+ const newParents = [...parents, node];
1072
+ for (const key of Object.keys(node)) {
1073
+ const child = node[key];
1074
+ if (Array.isArray(child)) child.forEach((c) => walk(c, newParents));
1075
+ else if (child && typeof child === "object") walk(child, newParents);
1076
+ }
1077
+ }
1078
+ walk(program);
1079
+ return jobs;
1080
+ }
1081
+ /**
1082
+ * Build a map from export name to job name from detected jobs
1083
+ */
1084
+ function buildJobNameMap(jobs) {
1085
+ const map = /* @__PURE__ */ new Map();
1086
+ for (const job of jobs) if (job.exportName) map.set(job.exportName, job.name);
1087
+ return map;
1088
+ }
1089
+ /**
1090
+ * Detect all .trigger() calls in the source code
1091
+ * Returns information about each trigger call for transformation
1092
+ */
1093
+ function detectTriggerCalls(program, sourceText) {
1094
+ const calls = [];
1095
+ function walk(node) {
1096
+ if (!node || typeof node !== "object") return;
1097
+ if (node.type === "CallExpression") {
1098
+ const callExpr = node;
1099
+ const callee = callExpr.callee;
1100
+ if (callee.type === "MemberExpression") {
1101
+ const memberExpr = callee;
1102
+ if (!memberExpr.computed && memberExpr.object.type === "Identifier" && memberExpr.property.name === "trigger") {
1103
+ const identifierName = memberExpr.object.name;
1104
+ let argsText = "";
1105
+ if (callExpr.arguments.length > 0) {
1106
+ const firstArg = callExpr.arguments[0];
1107
+ const lastArg = callExpr.arguments[callExpr.arguments.length - 1];
1108
+ if (firstArg && lastArg && "start" in firstArg && "end" in lastArg) argsText = sourceText.slice(firstArg.start, lastArg.end);
1109
+ }
1110
+ calls.push({
1111
+ identifierName,
1112
+ callRange: {
1113
+ start: callExpr.start,
1114
+ end: callExpr.end
1115
+ },
1116
+ argsText
1117
+ });
1118
+ }
1119
+ }
1120
+ }
1121
+ for (const key of Object.keys(node)) {
1122
+ const child = node[key];
1123
+ if (Array.isArray(child)) child.forEach((c) => walk(c));
1124
+ else if (child && typeof child === "object") walk(child);
1125
+ }
1126
+ }
1127
+ walk(program);
1128
+ return calls;
1129
+ }
1130
+
1131
+ //#endregion
1132
+ //#region src/cli/bundler/workflow/workflow-detector.ts
1133
+ /**
1134
+ * Find all workflows by detecting createWorkflow calls from \@tailor-platform/sdk
1135
+ */
1136
+ function findAllWorkflows(program, _sourceText) {
1137
+ const workflows = [];
1138
+ const bindings = collectSdkBindings(program, "createWorkflow");
1139
+ function walk(node, parents = []) {
1140
+ if (!node || typeof node !== "object") return;
1141
+ if (isSdkFunctionCall(node, bindings, "createWorkflow")) {
1142
+ const args = node.arguments;
1143
+ if (args?.length >= 1 && args[0]?.type === "ObjectExpression") {
1144
+ const configObj = args[0];
1145
+ const nameProp = findProperty(configObj.properties, "name");
1146
+ if (nameProp && isStringLiteral(nameProp.value)) {
1147
+ let exportName;
1148
+ let isDefaultExport = false;
1149
+ for (let i = parents.length - 1; i >= 0; i--) {
1150
+ const parent = parents[i];
1151
+ if (parent.type === "VariableDeclarator") {
1152
+ const declarator = parent;
1153
+ if (declarator.id?.type === "Identifier") {
1154
+ exportName = declarator.id.name;
1155
+ break;
1156
+ }
1157
+ }
1158
+ if (parent.type === "ExportDefaultDeclaration") isDefaultExport = true;
1159
+ }
1160
+ workflows.push({
1161
+ name: nameProp.value.value,
1162
+ exportName,
1163
+ isDefaultExport
1164
+ });
1165
+ }
1166
+ }
1167
+ }
1168
+ const newParents = [...parents, node];
1169
+ for (const key of Object.keys(node)) {
1170
+ const child = node[key];
1171
+ if (Array.isArray(child)) child.forEach((c) => walk(c, newParents));
1172
+ else if (child && typeof child === "object") walk(child, newParents);
1173
+ }
1174
+ }
1175
+ walk(program);
1176
+ return workflows;
1177
+ }
1178
+ /**
1179
+ * Build a map from export name to workflow name from detected workflows
1180
+ */
1181
+ function buildWorkflowNameMap(workflows) {
1182
+ const map = /* @__PURE__ */ new Map();
1183
+ for (const workflow of workflows) if (workflow.exportName) map.set(workflow.exportName, workflow.name);
1184
+ return map;
1185
+ }
1186
+ /**
1187
+ * Detect default imports in a source file and return a map from local name to import source
1188
+ */
1189
+ function detectDefaultImports(program) {
1190
+ const imports = /* @__PURE__ */ new Map();
1191
+ function walk(node) {
1192
+ if (!node || typeof node !== "object") return;
1193
+ if (node.type === "ImportDeclaration") {
1194
+ const importDecl = node;
1195
+ const source = importDecl.source?.value;
1196
+ if (typeof source === "string") {
1197
+ for (const specifier of importDecl.specifiers || []) if (specifier.type === "ImportDefaultSpecifier") {
1198
+ const spec = specifier;
1199
+ if (spec.local?.name) imports.set(spec.local.name, source);
1200
+ }
1201
+ }
1202
+ }
1203
+ for (const key of Object.keys(node)) {
1204
+ const child = node[key];
1205
+ if (Array.isArray(child)) child.forEach((c) => walk(c));
1206
+ else if (child && typeof child === "object") walk(child);
1207
+ }
1208
+ }
1209
+ walk(program);
1210
+ return imports;
1211
+ }
1212
+
1213
+ //#endregion
1214
+ //#region src/cli/bundler/workflow/trigger-transformer.ts
1215
+ /**
1216
+ * Extract authInvoker info from a config object expression
1217
+ * Returns the authInvoker value text and whether it's a shorthand property
1218
+ */
1219
+ function extractAuthInvokerInfo(configArg, sourceText) {
1220
+ if (!configArg || typeof configArg !== "object") return void 0;
1221
+ if (configArg.type !== "ObjectExpression") return void 0;
1222
+ const objExpr = configArg;
1223
+ for (const prop of objExpr.properties) {
1224
+ if (prop.type !== "Property") continue;
1225
+ const objProp = prop;
1226
+ if ((objProp.key.type === "Identifier" ? objProp.key.name : objProp.key.type === "Literal" ? objProp.key.value : null) === "authInvoker") {
1227
+ if (objProp.shorthand) return {
1228
+ isShorthand: true,
1229
+ valueText: "authInvoker"
1230
+ };
1231
+ return {
1232
+ isShorthand: false,
1233
+ valueText: sourceText.slice(objProp.value.start, objProp.value.end)
1234
+ };
1235
+ }
1236
+ }
1237
+ }
1238
+ /**
1239
+ * Detect .trigger() calls for known workflows and jobs
1240
+ * Only detects calls where the identifier is in workflowNames or jobNames
1241
+ *
1242
+ * @param program - The parsed AST program
1243
+ * @param sourceText - The source code text
1244
+ * @param workflowNames - Set of known workflow identifier names
1245
+ * @param jobNames - Set of known job identifier names
1246
+ */
1247
+ function detectExtendedTriggerCalls(program, sourceText, workflowNames, jobNames) {
1248
+ const calls = [];
1249
+ function walk(node) {
1250
+ if (!node || typeof node !== "object") return;
1251
+ if (node.type === "CallExpression") {
1252
+ const callExpr = node;
1253
+ const callee = callExpr.callee;
1254
+ if (callee.type === "MemberExpression") {
1255
+ const memberExpr = callee;
1256
+ if (!memberExpr.computed && memberExpr.object.type === "Identifier" && memberExpr.property.name === "trigger") {
1257
+ const identifierName = memberExpr.object.name;
1258
+ const isWorkflow = workflowNames.has(identifierName);
1259
+ const isJob = jobNames.has(identifierName);
1260
+ if (!isWorkflow && !isJob) return;
1261
+ const argCount = callExpr.arguments.length;
1262
+ let argsText = "";
1263
+ if (argCount > 0) {
1264
+ const firstArg = callExpr.arguments[0];
1265
+ if (firstArg && "start" in firstArg && "end" in firstArg) argsText = sourceText.slice(firstArg.start, firstArg.end);
1266
+ }
1267
+ if (isWorkflow && argCount >= 2) {
1268
+ const secondArg = callExpr.arguments[1];
1269
+ const authInvoker = extractAuthInvokerInfo(secondArg, sourceText);
1270
+ if (authInvoker) calls.push({
1271
+ kind: "workflow",
1272
+ identifierName,
1273
+ callRange: {
1274
+ start: callExpr.start,
1275
+ end: callExpr.end
1276
+ },
1277
+ argsText,
1278
+ authInvoker
1279
+ });
1280
+ } else if (isJob) calls.push({
1281
+ kind: "job",
1282
+ identifierName,
1283
+ callRange: {
1284
+ start: callExpr.start,
1285
+ end: callExpr.end
1286
+ },
1287
+ argsText
1288
+ });
1289
+ }
1290
+ }
1291
+ }
1292
+ for (const key of Object.keys(node)) {
1293
+ const child = node[key];
1294
+ if (Array.isArray(child)) child.forEach((c) => walk(c));
1295
+ else if (child && typeof child === "object") walk(child);
1296
+ }
1297
+ }
1298
+ walk(program);
1299
+ return calls;
1300
+ }
1301
+ /**
1302
+ * Transform trigger calls for resolver/executor/workflow functions
1303
+ * Handles both job.trigger() and workflow.trigger() calls
1304
+ *
1305
+ * @param source - The source code to transform
1306
+ * @param workflowNameMap - Map from variable name to workflow name
1307
+ * @param jobNameMap - Map from variable name to job name
1308
+ * @param workflowFileMap - Map from file path (without extension) to workflow name for default exports
1309
+ * @param currentFilePath - Path of the current file being transformed (for resolving relative imports)
1310
+ */
1311
+ function transformFunctionTriggers(source, workflowNameMap, jobNameMap, workflowFileMap, currentFilePath) {
1312
+ const { program } = parseSync("input.ts", source);
1313
+ const localWorkflowNameMap = new Map(workflowNameMap);
1314
+ if (workflowFileMap && currentFilePath) {
1315
+ const defaultImports = detectDefaultImports(program);
1316
+ const currentDir = currentFilePath.replace(/[/\\][^/\\]+$/, "");
1317
+ for (const [localName, importSource] of defaultImports) {
1318
+ if (!importSource.startsWith(".")) continue;
1319
+ const resolvedPath = resolvePath(currentDir, importSource);
1320
+ const workflowName = workflowFileMap.get(resolvedPath);
1321
+ if (workflowName) localWorkflowNameMap.set(localName, workflowName);
1322
+ }
1323
+ }
1324
+ const workflowNames = new Set(localWorkflowNameMap.keys());
1325
+ const jobNames = new Set(jobNameMap.keys());
1326
+ const triggerCalls = detectExtendedTriggerCalls(program, source, workflowNames, jobNames);
1327
+ const replacements = [];
1328
+ for (const call of triggerCalls) if (call.kind === "workflow" && call.authInvoker) {
1329
+ const workflowName = localWorkflowNameMap.get(call.identifierName);
1330
+ if (workflowName) {
1331
+ const authInvokerExpr = call.authInvoker.isShorthand ? "authInvoker" : call.authInvoker.valueText;
1332
+ const transformedCall = `tailor.workflow.triggerWorkflow("${workflowName}", ${call.argsText || "undefined"}, { authInvoker: ${authInvokerExpr} })`;
1333
+ replacements.push({
1334
+ start: call.callRange.start,
1335
+ end: call.callRange.end,
1336
+ text: transformedCall
1337
+ });
1338
+ }
1339
+ } else if (call.kind === "job") {
1340
+ const jobName = jobNameMap.get(call.identifierName);
1341
+ if (jobName) {
1342
+ const transformedCall = `tailor.workflow.triggerJobFunction("${jobName}", ${call.argsText || "undefined"})`;
1343
+ replacements.push({
1344
+ start: call.callRange.start,
1345
+ end: call.callRange.end,
1346
+ text: transformedCall
1347
+ });
1348
+ }
1349
+ }
1350
+ return applyReplacements(source, replacements);
1351
+ }
1352
+
1353
+ //#endregion
1354
+ //#region src/cli/bundler/trigger-context.ts
1355
+ /**
1356
+ * Normalize a file path by removing extension and resolving to absolute path
1357
+ */
1358
+ function normalizeFilePath(filePath) {
1359
+ const absolutePath = path.resolve(filePath);
1360
+ const ext = path.extname(absolutePath);
1361
+ return absolutePath.slice(0, -ext.length);
1362
+ }
1363
+ /**
1364
+ * Build trigger context from workflow configuration
1365
+ * Scans workflow files to collect workflow and job mappings
1366
+ */
1367
+ async function buildTriggerContext(workflowConfig) {
1368
+ const workflowNameMap = /* @__PURE__ */ new Map();
1369
+ const jobNameMap = /* @__PURE__ */ new Map();
1370
+ const workflowFileMap = /* @__PURE__ */ new Map();
1371
+ if (!workflowConfig) return {
1372
+ workflowNameMap,
1373
+ jobNameMap,
1374
+ workflowFileMap
1375
+ };
1376
+ const workflowFiles = loadFilesWithIgnores(workflowConfig);
1377
+ for (const file of workflowFiles) try {
1378
+ const source = await fs.promises.readFile(file, "utf-8");
1379
+ const { program } = parseSync("input.ts", source);
1380
+ const workflows = findAllWorkflows(program, source);
1381
+ const workflowMap = buildWorkflowNameMap(workflows);
1382
+ for (const [exportName, workflowName] of workflowMap) workflowNameMap.set(exportName, workflowName);
1383
+ for (const workflow of workflows) if (workflow.isDefaultExport) {
1384
+ const normalizedPath = normalizeFilePath(file);
1385
+ workflowFileMap.set(normalizedPath, workflow.name);
1386
+ }
1387
+ const jobs = findAllJobs(program, source);
1388
+ const jobMap = buildJobNameMap(jobs);
1389
+ for (const [exportName, jobName] of jobMap) jobNameMap.set(exportName, jobName);
1390
+ } catch (error) {
1391
+ const errorMessage = error instanceof Error ? error.message : String(error);
1392
+ console.warn(styleText("yellow", `Warning: Failed to process workflow file ${file}: ${errorMessage}`));
1393
+ continue;
1394
+ }
1395
+ return {
1396
+ workflowNameMap,
1397
+ jobNameMap,
1398
+ workflowFileMap
1399
+ };
1400
+ }
1401
+ /**
1402
+ * Create a rolldown plugin for transforming trigger calls
1403
+ * Returns undefined if no trigger context is provided
1404
+ */
1405
+ function createTriggerTransformPlugin(triggerContext) {
1406
+ if (!triggerContext) return;
1407
+ return {
1408
+ name: "trigger-transform",
1409
+ transform: {
1410
+ filter: { id: { include: [/\.ts$/, /\.js$/] } },
1411
+ handler(code, id) {
1412
+ if (!code.includes(".trigger(")) return null;
1413
+ return { code: transformFunctionTriggers(code, triggerContext.workflowNameMap, triggerContext.jobNameMap, triggerContext.workflowFileMap, id) };
1414
+ }
1415
+ }
1416
+ };
1417
+ }
1418
+
693
1419
  //#endregion
694
1420
  //#region src/cli/bundler/executor/loader.ts
695
1421
  async function loadExecutor(executorFilePath) {
@@ -708,7 +1434,7 @@ async function loadExecutor(executorFilePath) {
708
1434
  * 1. Creates entry file that extracts operation.body
709
1435
  * 2. Bundles in a single step with tree-shaking
710
1436
  */
711
- async function bundleExecutors(config) {
1437
+ async function bundleExecutors(config, triggerContext) {
712
1438
  const files = loadFilesWithIgnores(config);
713
1439
  if (files.length === 0) throw new Error(`No files found matching pattern: ${config.files?.join(", ")}`);
714
1440
  console.log("");
@@ -741,10 +1467,10 @@ async function bundleExecutors(config) {
741
1467
  } catch {
742
1468
  tsconfig = void 0;
743
1469
  }
744
- await Promise.all(executors.map((executor) => bundleSingleExecutor(executor, outputDir, tsconfig)));
1470
+ await Promise.all(executors.map((executor) => bundleSingleExecutor(executor, outputDir, tsconfig, triggerContext)));
745
1471
  console.log(styleText("green", "Bundled"), styleText("cyan", "\"executor\""));
746
1472
  }
747
- async function bundleSingleExecutor(executor, outputDir, tsconfig) {
1473
+ async function bundleSingleExecutor(executor, outputDir, tsconfig, triggerContext) {
748
1474
  const entryPath = path.join(outputDir, `${executor.name}.entry.js`);
749
1475
  const absoluteSourcePath = path.resolve(executor.sourceFile).replace(/\\/g, "/");
750
1476
  const entryContent = ml`
@@ -756,6 +1482,8 @@ async function bundleSingleExecutor(executor, outputDir, tsconfig) {
756
1482
  `;
757
1483
  fs.writeFileSync(entryPath, entryContent);
758
1484
  const outputPath = path.join(outputDir, `${executor.name}.js`);
1485
+ const triggerPlugin = createTriggerTransformPlugin(triggerContext);
1486
+ const plugins = triggerPlugin ? [triggerPlugin] : [];
759
1487
  await rolldown.build(rolldown.defineConfig({
760
1488
  input: entryPath,
761
1489
  output: {
@@ -766,6 +1494,7 @@ async function bundleSingleExecutor(executor, outputDir, tsconfig) {
766
1494
  inlineDynamicImports: true
767
1495
  },
768
1496
  tsconfig,
1497
+ plugins,
769
1498
  treeshake: {
770
1499
  moduleSideEffects: false,
771
1500
  annotations: true,
@@ -794,7 +1523,7 @@ async function loadResolver(resolverFilePath) {
794
1523
  * 2. Creates entry file
795
1524
  * 3. Bundles in a single step with tree-shaking
796
1525
  */
797
- async function bundleResolvers(namespace, config) {
1526
+ async function bundleResolvers(namespace, config, triggerContext) {
798
1527
  const files = loadFilesWithIgnores(config);
799
1528
  if (files.length === 0) throw new Error(`No files found matching pattern: ${config.files?.join(", ")}`);
800
1529
  console.log("");
@@ -819,10 +1548,10 @@ async function bundleResolvers(namespace, config) {
819
1548
  } catch {
820
1549
  tsconfig = void 0;
821
1550
  }
822
- await Promise.all(resolvers.map((resolver) => bundleSingleResolver(resolver, outputDir, tsconfig)));
1551
+ await Promise.all(resolvers.map((resolver) => bundleSingleResolver(resolver, outputDir, tsconfig, triggerContext)));
823
1552
  console.log(styleText("green", "Bundled"), styleText("cyan", `"${namespace}"`));
824
1553
  }
825
- async function bundleSingleResolver(resolver, outputDir, tsconfig) {
1554
+ async function bundleSingleResolver(resolver, outputDir, tsconfig, triggerContext) {
826
1555
  const entryPath = path.join(outputDir, `${resolver.name}.entry.js`);
827
1556
  const absoluteSourcePath = path.resolve(resolver.sourceFile).replace(/\\/g, "/");
828
1557
  const entryContent = ml`
@@ -855,6 +1584,8 @@ async function bundleSingleResolver(resolver, outputDir, tsconfig) {
855
1584
  `;
856
1585
  fs.writeFileSync(entryPath, entryContent);
857
1586
  const outputPath = path.join(outputDir, `${resolver.name}.js`);
1587
+ const triggerPlugin = createTriggerTransformPlugin(triggerContext);
1588
+ const plugins = triggerPlugin ? [triggerPlugin] : [];
858
1589
  await rolldown.build(rolldown.defineConfig({
859
1590
  input: entryPath,
860
1591
  output: {
@@ -865,6 +1596,7 @@ async function bundleSingleResolver(resolver, outputDir, tsconfig) {
865
1596
  inlineDynamicImports: true
866
1597
  },
867
1598
  tsconfig,
1599
+ plugins,
868
1600
  treeshake: {
869
1601
  moduleSideEffects: false,
870
1602
  annotations: true,
@@ -875,261 +1607,7 @@ async function bundleSingleResolver(resolver, outputDir, tsconfig) {
875
1607
  }
876
1608
 
877
1609
  //#endregion
878
- //#region src/cli/bundler/workflow/ast-transformer.ts
879
- /**
880
- * Check if a module source is from \@tailor-platform/sdk (including subpaths)
881
- */
882
- function isTailorSdkSource(source) {
883
- return /^@tailor-platform\/sdk(\/|$)/.test(source);
884
- }
885
- /**
886
- * Get the source string from a dynamic import or require call
887
- */
888
- function getImportSource(node) {
889
- if (!node) return null;
890
- if (node.type === "ImportExpression") {
891
- const source = node.source;
892
- if (source.type === "Literal" && typeof source.value === "string") return source.value;
893
- }
894
- if (node.type === "CallExpression") {
895
- const callExpr = node;
896
- if (callExpr.callee.type === "Identifier" && callExpr.callee.name === "require") {
897
- const arg = callExpr.arguments[0];
898
- if (arg && "type" in arg && arg.type === "Literal" && "value" in arg && typeof arg.value === "string") return arg.value;
899
- }
900
- }
901
- return null;
902
- }
903
- /**
904
- * Unwrap AwaitExpression to get the inner expression
905
- */
906
- function unwrapAwait(node) {
907
- if (node?.type === "AwaitExpression") return node.argument;
908
- return node;
909
- }
910
- /**
911
- * Collect all import bindings for createWorkflowJob from \@tailor-platform/sdk
912
- * Returns a Set of local names that refer to createWorkflowJob
913
- */
914
- function collectCreateWorkflowJobBindings(program) {
915
- const bindings = /* @__PURE__ */ new Set();
916
- function walk(node) {
917
- if (!node || typeof node !== "object") return;
918
- const nodeType = node.type;
919
- if (nodeType === "ImportDeclaration") {
920
- const importDecl = node;
921
- const source = importDecl.source?.value;
922
- if (typeof source === "string" && isTailorSdkSource(source)) {
923
- for (const specifier of importDecl.specifiers || []) if (specifier.type === "ImportSpecifier") {
924
- const importSpec = specifier;
925
- const imported = importSpec.imported.type === "Identifier" ? importSpec.imported.name : importSpec.imported.value;
926
- if (imported === "createWorkflowJob") bindings.add(importSpec.local?.name || imported);
927
- } else if (specifier.type === "ImportDefaultSpecifier" || specifier.type === "ImportNamespaceSpecifier") {
928
- const spec = specifier;
929
- bindings.add(`__namespace__:${spec.local?.name}`);
930
- }
931
- }
932
- }
933
- if (nodeType === "VariableDeclaration") {
934
- const varDecl = node;
935
- for (const decl of varDecl.declarations || []) {
936
- const init = unwrapAwait(decl.init);
937
- const source = getImportSource(init);
938
- if (source && isTailorSdkSource(source)) {
939
- const id = decl.id;
940
- if (id?.type === "Identifier") bindings.add(`__namespace__:${id.name}`);
941
- else if (id?.type === "ObjectPattern") {
942
- const objPattern = id;
943
- for (const prop of objPattern.properties || []) if (prop.type === "Property") {
944
- const bindingProp = prop;
945
- const keyName = bindingProp.key.type === "Identifier" ? bindingProp.key.name : bindingProp.key.value;
946
- if (keyName === "createWorkflowJob") {
947
- const localName = bindingProp.value.type === "Identifier" ? bindingProp.value.name : keyName;
948
- bindings.add(localName ?? "");
949
- }
950
- }
951
- }
952
- }
953
- }
954
- }
955
- for (const key of Object.keys(node)) {
956
- const child = node[key];
957
- if (Array.isArray(child)) child.forEach((c) => walk(c));
958
- else if (child && typeof child === "object") walk(child);
959
- }
960
- }
961
- walk(program);
962
- return bindings;
963
- }
964
- /**
965
- * Check if a CallExpression is a createWorkflowJob call
966
- */
967
- function isCreateWorkflowJobCall(node, bindings) {
968
- if (node.type !== "CallExpression") return false;
969
- const callee = node.callee;
970
- if (callee.type === "Identifier") {
971
- const identifier = callee;
972
- return bindings.has(identifier.name);
973
- }
974
- if (callee.type === "MemberExpression") {
975
- const memberExpr = callee;
976
- if (!memberExpr.computed) {
977
- const object = memberExpr.object;
978
- const property = memberExpr.property;
979
- if (object.type === "Identifier" && bindings.has(`__namespace__:${object.name}`) && property.name === "createWorkflowJob") return true;
980
- }
981
- }
982
- return false;
983
- }
984
- /**
985
- * Check if a node is a string literal
986
- */
987
- function isStringLiteral(node) {
988
- return node?.type === "Literal" && typeof node.value === "string";
989
- }
990
- /**
991
- * Check if a node is a function expression (arrow or regular)
992
- */
993
- function isFunctionExpression(node) {
994
- return node?.type === "ArrowFunctionExpression" || node?.type === "FunctionExpression";
995
- }
996
- /**
997
- * Find a property in an object expression
998
- */
999
- function findProperty(properties, name) {
1000
- for (const prop of properties) if (prop.type === "Property") {
1001
- const objProp = prop;
1002
- if ((objProp.key.type === "Identifier" ? objProp.key.name : objProp.key.type === "Literal" ? objProp.key.value : null) === name) return {
1003
- key: objProp.key,
1004
- value: objProp.value,
1005
- start: objProp.start,
1006
- end: objProp.end
1007
- };
1008
- }
1009
- return null;
1010
- }
1011
- /**
1012
- * Find all workflow jobs by detecting createWorkflowJob calls from \@tailor-platform/sdk
1013
- */
1014
- function findAllJobs(program, _sourceText) {
1015
- const jobs = [];
1016
- const bindings = collectCreateWorkflowJobBindings(program);
1017
- function walk(node, parents = []) {
1018
- if (!node || typeof node !== "object") return;
1019
- if (isCreateWorkflowJobCall(node, bindings)) {
1020
- const args = node.arguments;
1021
- if (args?.length >= 1 && args[0]?.type === "ObjectExpression") {
1022
- const configObj = args[0];
1023
- const nameProp = findProperty(configObj.properties, "name");
1024
- const bodyProp = findProperty(configObj.properties, "body");
1025
- if (nameProp && isStringLiteral(nameProp.value) && bodyProp && isFunctionExpression(bodyProp.value)) {
1026
- let statementRange;
1027
- let exportName;
1028
- for (let i = parents.length - 1; i >= 0; i--) {
1029
- const parent = parents[i];
1030
- if (parent.type === "VariableDeclarator") {
1031
- const declarator = parent;
1032
- if (declarator.id?.type === "Identifier") exportName = declarator.id.name;
1033
- }
1034
- if (parent.type === "ExportNamedDeclaration" || parent.type === "VariableDeclaration") statementRange = {
1035
- start: parent.start,
1036
- end: parent.end
1037
- };
1038
- }
1039
- jobs.push({
1040
- name: nameProp.value.value,
1041
- exportName,
1042
- nameRange: {
1043
- start: nameProp.start,
1044
- end: nameProp.end
1045
- },
1046
- bodyValueRange: {
1047
- start: bodyProp.value.start,
1048
- end: bodyProp.value.end
1049
- },
1050
- statementRange
1051
- });
1052
- }
1053
- }
1054
- }
1055
- const newParents = [...parents, node];
1056
- for (const key of Object.keys(node)) {
1057
- const child = node[key];
1058
- if (Array.isArray(child)) child.forEach((c) => walk(c, newParents));
1059
- else if (child && typeof child === "object") walk(child, newParents);
1060
- }
1061
- }
1062
- walk(program);
1063
- return jobs;
1064
- }
1065
- /**
1066
- * Apply string replacements to source code
1067
- * Replacements are applied from end to start to maintain positions
1068
- */
1069
- function applyReplacements(source, replacements) {
1070
- const sorted = [...replacements].sort((a, b) => b.start - a.start);
1071
- let result = source;
1072
- for (const r of sorted) result = result.slice(0, r.start) + r.text + result.slice(r.end);
1073
- return result;
1074
- }
1075
- /**
1076
- * Find the end of a statement including any trailing newline
1077
- */
1078
- function findStatementEnd(source, position) {
1079
- let i = position;
1080
- while (i < source.length && (source[i] === ";" || source[i] === " " || source[i] === " ")) i++;
1081
- if (i < source.length && source[i] === "\n") i++;
1082
- return i;
1083
- }
1084
- /**
1085
- * Detect all .trigger() calls in the source code
1086
- * Returns information about each trigger call for transformation
1087
- */
1088
- function detectTriggerCalls(program, sourceText) {
1089
- const calls = [];
1090
- function walk(node) {
1091
- if (!node || typeof node !== "object") return;
1092
- if (node.type === "CallExpression") {
1093
- const callExpr = node;
1094
- const callee = callExpr.callee;
1095
- if (callee.type === "MemberExpression") {
1096
- const memberExpr = callee;
1097
- if (!memberExpr.computed && memberExpr.object.type === "Identifier" && memberExpr.property.name === "trigger") {
1098
- const identifierName = memberExpr.object.name;
1099
- let argsText = "";
1100
- if (callExpr.arguments.length > 0) {
1101
- const firstArg = callExpr.arguments[0];
1102
- const lastArg = callExpr.arguments[callExpr.arguments.length - 1];
1103
- if (firstArg && lastArg && "start" in firstArg && "end" in lastArg) argsText = sourceText.slice(firstArg.start, lastArg.end);
1104
- }
1105
- calls.push({
1106
- identifierName,
1107
- callRange: {
1108
- start: callExpr.start,
1109
- end: callExpr.end
1110
- },
1111
- argsText
1112
- });
1113
- }
1114
- }
1115
- }
1116
- for (const key of Object.keys(node)) {
1117
- const child = node[key];
1118
- if (Array.isArray(child)) child.forEach((c) => walk(c));
1119
- else if (child && typeof child === "object") walk(child);
1120
- }
1121
- }
1122
- walk(program);
1123
- return calls;
1124
- }
1125
- /**
1126
- * Build a map from export name to job name from detected jobs
1127
- */
1128
- function buildJobNameMap(jobs) {
1129
- const map = /* @__PURE__ */ new Map();
1130
- for (const job of jobs) if (job.exportName) map.set(job.exportName, job.name);
1131
- return map;
1132
- }
1610
+ //#region src/cli/bundler/workflow/source-transformer.ts
1133
1611
  /**
1134
1612
  * Find variable declarations by export names
1135
1613
  * Returns a map of export name to statement range
@@ -1252,13 +1730,15 @@ function transformWorkflowSource(source, targetJobName, targetJobExportName, oth
1252
1730
  * 1. Detects which jobs are actually used (mainJobs + their dependencies)
1253
1731
  * 2. Uses a transform plugin to transform trigger calls during bundling
1254
1732
  * 3. Creates entry file and bundles with tree-shaking
1733
+ *
1734
+ * Returns metadata about which jobs each workflow uses.
1255
1735
  */
1256
- async function bundleWorkflowJobs(allJobs, mainJobNames, env = {}) {
1736
+ async function bundleWorkflowJobs(allJobs, mainJobNames, env = {}, triggerContext) {
1257
1737
  if (allJobs.length === 0) {
1258
1738
  console.log(styleText("dim", "No workflow jobs to bundle"));
1259
- return;
1739
+ return { mainJobDeps: {} };
1260
1740
  }
1261
- const usedJobs = await filterUsedJobs(allJobs, mainJobNames);
1741
+ const { usedJobs, mainJobDeps } = await filterUsedJobs(allJobs, mainJobNames);
1262
1742
  console.log("");
1263
1743
  console.log("Bundling", styleText("cyanBright", usedJobs.length.toString()), "files for", styleText("cyan", "\"workflow-job\""));
1264
1744
  const outputDir = path.resolve(getDistDir(), "workflow-jobs");
@@ -1270,17 +1750,23 @@ async function bundleWorkflowJobs(allJobs, mainJobNames, env = {}) {
1270
1750
  } catch {
1271
1751
  tsconfig = void 0;
1272
1752
  }
1273
- await Promise.all(usedJobs.map((job) => bundleSingleJob(job, usedJobs, outputDir, tsconfig, env)));
1753
+ await Promise.all(usedJobs.map((job) => bundleSingleJob(job, usedJobs, outputDir, tsconfig, env, triggerContext)));
1274
1754
  console.log(styleText("green", "Bundled"), styleText("cyan", "\"workflow-job\""));
1755
+ return { mainJobDeps };
1275
1756
  }
1276
1757
  /**
1277
1758
  * Filter jobs to only include those that are actually used.
1278
1759
  * A job is "used" if:
1279
1760
  * - It's a mainJob of a workflow
1280
1761
  * - It's called via .trigger() from another used job (transitively)
1762
+ *
1763
+ * Also returns a map of mainJob -> all jobs it depends on (for metadata).
1281
1764
  */
1282
1765
  async function filterUsedJobs(allJobs, mainJobNames) {
1283
- if (allJobs.length === 0 || mainJobNames.length === 0) return [];
1766
+ if (allJobs.length === 0 || mainJobNames.length === 0) return {
1767
+ usedJobs: [],
1768
+ mainJobDeps: {}
1769
+ };
1284
1770
  const jobsBySourceFile = /* @__PURE__ */ new Map();
1285
1771
  for (const job of allJobs) {
1286
1772
  const existing = jobsBySourceFile.get(job.sourceFile) || [];
@@ -1319,16 +1805,25 @@ async function filterUsedJobs(allJobs, mainJobNames) {
1319
1805
  }));
1320
1806
  for (const jobDependencies of fileResults) for (const { jobName, deps } of jobDependencies) dependencies.set(jobName, deps);
1321
1807
  const usedJobNames = /* @__PURE__ */ new Set();
1322
- function markUsed(jobName) {
1323
- if (usedJobNames.has(jobName)) return;
1324
- usedJobNames.add(jobName);
1808
+ const mainJobDeps = {};
1809
+ function collectDeps(jobName, collected) {
1810
+ if (collected.has(jobName)) return;
1811
+ collected.add(jobName);
1325
1812
  const deps = dependencies.get(jobName);
1326
- if (deps) for (const dep of deps) markUsed(dep);
1813
+ if (deps) for (const dep of deps) collectDeps(dep, collected);
1327
1814
  }
1328
- for (const mainJobName of mainJobNames) markUsed(mainJobName);
1329
- return allJobs.filter((job) => usedJobNames.has(job.name));
1815
+ for (const mainJobName of mainJobNames) {
1816
+ const depsForMainJob = /* @__PURE__ */ new Set();
1817
+ collectDeps(mainJobName, depsForMainJob);
1818
+ mainJobDeps[mainJobName] = Array.from(depsForMainJob);
1819
+ for (const dep of depsForMainJob) usedJobNames.add(dep);
1820
+ }
1821
+ return {
1822
+ usedJobs: allJobs.filter((job) => usedJobNames.has(job.name)),
1823
+ mainJobDeps
1824
+ };
1330
1825
  }
1331
- async function bundleSingleJob(job, allJobs, outputDir, tsconfig, env) {
1826
+ async function bundleSingleJob(job, allJobs, outputDir, tsconfig, env, triggerContext) {
1332
1827
  const entryPath = path.join(outputDir, `${job.name}.entry.js`);
1333
1828
  const absoluteSourcePath = path.resolve(job.sourceFile).replace(/\\/g, "/");
1334
1829
  const entryContent = ml`
@@ -1359,9 +1854,11 @@ async function bundleSingleJob(job, allJobs, outputDir, tsconfig, env) {
1359
1854
  name: "workflow-transform",
1360
1855
  transform: {
1361
1856
  filter: { id: { include: [/\.ts$/, /\.js$/] } },
1362
- handler(code) {
1363
- if (!code.includes("createWorkflowJob") && !code.includes(".trigger(")) return null;
1364
- return { code: transformWorkflowSource(code, job.name, job.exportName, otherJobExportNames, allJobsMap) };
1857
+ handler(code, id) {
1858
+ if (!code.includes("createWorkflowJob") && !code.includes("createWorkflow") && !code.includes(".trigger(")) return null;
1859
+ let transformed = transformWorkflowSource(code, job.name, job.exportName, otherJobExportNames, allJobsMap);
1860
+ if (triggerContext && transformed.includes(".trigger(")) transformed = transformFunctionTriggers(transformed, triggerContext.workflowNameMap, triggerContext.jobNameMap, triggerContext.workflowFileMap, id);
1861
+ return { code: transformed };
1365
1862
  }
1366
1863
  }
1367
1864
  }],
@@ -3937,12 +4434,12 @@ function protoIdPConfig(idpConfig) {
3937
4434
  value: {
3938
4435
  ...idpConfig.metadataURL !== void 0 ? { metadataUrl: idpConfig.metadataURL } : { rawMetadata: idpConfig.rawMetadata },
3939
4436
  ...idpConfig.spCertBase64 && { spCertBase64: {
3940
- vaultName: idpConfig.spCertBase64.VaultName,
3941
- secretKey: idpConfig.spCertBase64.SecretKey
4437
+ vaultName: idpConfig.spCertBase64.vaultName,
4438
+ secretKey: idpConfig.spCertBase64.secretKey
3942
4439
  } },
3943
4440
  ...idpConfig.spKeyBase64 && { spKeyBase64: {
3944
- vaultName: idpConfig.spKeyBase64.VaultName,
3945
- secretKey: idpConfig.spKeyBase64.SecretKey
4441
+ vaultName: idpConfig.spKeyBase64.vaultName,
4442
+ secretKey: idpConfig.spKeyBase64.secretKey
3946
4443
  } }
3947
4444
  }
3948
4445
  } }
@@ -3955,8 +4452,8 @@ function protoIdPConfig(idpConfig) {
3955
4452
  value: {
3956
4453
  clientIdKey: idpConfig.clientID,
3957
4454
  clientSecretKey: {
3958
- vaultName: idpConfig.clientSecret.VaultName,
3959
- secretKey: idpConfig.clientSecret.SecretKey
4455
+ vaultName: idpConfig.clientSecret.vaultName,
4456
+ secretKey: idpConfig.clientSecret.secretKey
3960
4457
  },
3961
4458
  providerUrl: idpConfig.providerURL,
3962
4459
  issuerUrl: idpConfig.issuerURL,
@@ -4392,8 +4889,8 @@ function protoSCIMConfig(scimConfig) {
4392
4889
  authorizationConfig: {
4393
4890
  case: "bearerSecret",
4394
4891
  value: {
4395
- vaultName: scimConfig.authorization.bearerSecret?.VaultName,
4396
- secretKey: scimConfig.authorization.bearerSecret?.SecretKey
4892
+ vaultName: scimConfig.authorization.bearerSecret?.vaultName,
4893
+ secretKey: scimConfig.authorization.bearerSecret?.secretKey
4397
4894
  }
4398
4895
  }
4399
4896
  };
@@ -4780,10 +5277,7 @@ function protoExecutor(appName, executor, env) {
4780
5277
  appName: target.appName ?? appName,
4781
5278
  query: target.query,
4782
5279
  variables: target.variables ? { expr: `(${target.variables.toString()})(args)` } : void 0,
4783
- invoker: target.invoker ? {
4784
- namespace: target.invoker.authName,
4785
- machineUserName: target.invoker.machineUser
4786
- } : void 0
5280
+ invoker: target.authInvoker ?? void 0
4787
5281
  }
4788
5282
  } };
4789
5283
  break;
@@ -4799,10 +5293,7 @@ function protoExecutor(appName, executor, env) {
4799
5293
  name: `${executor.name}__target`,
4800
5294
  script,
4801
5295
  variables: { expr: `({ ...args, appNamespace: args.namespaceName, env: ${JSON.stringify(env)} })` },
4802
- invoker: target.invoker ? {
4803
- namespace: target.invoker.authName,
4804
- machineUserName: target.invoker.machineUser
4805
- } : void 0
5296
+ invoker: target.authInvoker ?? void 0
4806
5297
  }
4807
5298
  } };
4808
5299
  break;
@@ -5758,19 +6249,21 @@ async function applyWorkflow(client, result, phase = "create-update") {
5758
6249
  if (phase === "create-update") {
5759
6250
  const jobFunctionVersions = await registerJobFunctions(client, changeSet);
5760
6251
  await Promise.all([...changeSet.creates.map(async (create) => {
6252
+ const filteredVersions = filterJobFunctionVersions(jobFunctionVersions, create.usedJobNames);
5761
6253
  await client.createWorkflow({
5762
6254
  workspaceId: create.workspaceId,
5763
6255
  workflowName: create.workflow.name,
5764
6256
  mainJobFunctionName: create.workflow.mainJob.name,
5765
- jobFunctions: jobFunctionVersions
6257
+ jobFunctions: filteredVersions
5766
6258
  });
5767
6259
  await client.setMetadata(create.metaRequest);
5768
6260
  }), ...changeSet.updates.map(async (update) => {
6261
+ const filteredVersions = filterJobFunctionVersions(jobFunctionVersions, update.usedJobNames);
5769
6262
  await client.updateWorkflow({
5770
6263
  workspaceId: update.workspaceId,
5771
6264
  workflowName: update.workflow.name,
5772
6265
  mainJobFunctionName: update.workflow.mainJob.name,
5773
- jobFunctions: jobFunctionVersions
6266
+ jobFunctions: filteredVersions
5774
6267
  });
5775
6268
  await client.setMetadata(update.metaRequest);
5776
6269
  })]);
@@ -5780,7 +6273,16 @@ async function applyWorkflow(client, result, phase = "create-update") {
5780
6273
  })));
5781
6274
  }
5782
6275
  /**
5783
- * Register all job functions once, returns a map of job name to version.
6276
+ * Filter job function versions to only include those used by a workflow
6277
+ */
6278
+ function filterJobFunctionVersions(allVersions, usedJobNames) {
6279
+ const filtered = {};
6280
+ for (const jobName of usedJobNames) if (allVersions[jobName] !== void 0) filtered[jobName] = allVersions[jobName];
6281
+ return filtered;
6282
+ }
6283
+ /**
6284
+ * Register job functions used by any workflow.
6285
+ * Only registers jobs that are actually used (based on usedJobNames in changeSet).
5784
6286
  * Uses update for existing workflows, create for new workflows.
5785
6287
  */
5786
6288
  async function registerJobFunctions(client, changeSet) {
@@ -5788,8 +6290,12 @@ async function registerJobFunctions(client, changeSet) {
5788
6290
  const firstWorkflow = changeSet.creates[0] || changeSet.updates[0];
5789
6291
  if (!firstWorkflow) return jobFunctionVersions;
5790
6292
  const { workspaceId, scripts } = firstWorkflow;
6293
+ const allUsedJobNames = /* @__PURE__ */ new Set();
6294
+ for (const item of [...changeSet.creates, ...changeSet.updates]) for (const jobName of item.usedJobNames) allUsedJobNames.add(jobName);
5791
6295
  const hasExistingWorkflows = changeSet.updates.length > 0;
5792
- const results = await Promise.all(Array.from(scripts.entries()).map(async ([jobName, script]) => {
6296
+ const results = await Promise.all(Array.from(allUsedJobNames).map(async (jobName) => {
6297
+ const script = scripts.get(jobName);
6298
+ if (!script) throw new Error(`No bundled script found for job "${jobName}". Please run "generate" command before "apply".`);
5793
6299
  const response = hasExistingWorkflows ? await client.updateWorkflowJobFunction({
5794
6300
  workspaceId,
5795
6301
  jobFunctionName: jobName,
@@ -5810,7 +6316,7 @@ async function registerJobFunctions(client, changeSet) {
5810
6316
  function trn(workspaceId, name) {
5811
6317
  return `trn:v1:workspace:${workspaceId}:workflow:${name}`;
5812
6318
  }
5813
- async function planWorkflow(client, workspaceId, appName, workflows) {
6319
+ async function planWorkflow(client, workspaceId, appName, workflows, mainJobDeps) {
5814
6320
  const changeSet = new ChangeSet("Workflows");
5815
6321
  const conflicts = [];
5816
6322
  const unmanaged = [];
@@ -5837,6 +6343,8 @@ async function planWorkflow(client, workspaceId, appName, workflows) {
5837
6343
  for (const workflow of Object.values(workflows)) {
5838
6344
  const existing = existingWorkflows[workflow.name];
5839
6345
  const metaRequest = await buildMetaRequest(trn(workspaceId, workflow.name), appName);
6346
+ const usedJobNames = mainJobDeps[workflow.mainJob.name];
6347
+ if (!usedJobNames) throw new Error(`No dependency info found for mainJob "${workflow.mainJob.name}". Please run "generate" command before "apply".`);
5840
6348
  if (existing) {
5841
6349
  if (!existing.label) unmanaged.push({
5842
6350
  resourceType: "Workflow",
@@ -5852,6 +6360,7 @@ async function planWorkflow(client, workspaceId, appName, workflows) {
5852
6360
  workspaceId,
5853
6361
  workflow,
5854
6362
  scripts: allScripts,
6363
+ usedJobNames,
5855
6364
  metaRequest
5856
6365
  });
5857
6366
  delete existingWorkflows[workflow.name];
@@ -5860,6 +6369,7 @@ async function planWorkflow(client, workspaceId, appName, workflows) {
5860
6369
  workspaceId,
5861
6370
  workflow,
5862
6371
  scripts: allScripts,
6372
+ usedJobNames,
5863
6373
  metaRequest
5864
6374
  });
5865
6375
  }
@@ -5905,11 +6415,13 @@ async function apply(options) {
5905
6415
  const application = defineApplication(config);
5906
6416
  let workflowResult;
5907
6417
  if (application.workflowConfig) workflowResult = await loadAndCollectJobs(application.workflowConfig);
5908
- for (const app$1 of application.applications) for (const pipeline$1 of app$1.resolverServices) await buildPipeline(pipeline$1.namespace, pipeline$1.config);
5909
- if (application.executorService) await buildExecutor(application.executorService.config);
6418
+ const triggerContext = await buildTriggerContext(application.workflowConfig);
6419
+ for (const app$1 of application.applications) for (const pipeline$1 of app$1.resolverServices) await buildPipeline(pipeline$1.namespace, pipeline$1.config, triggerContext);
6420
+ if (application.executorService) await buildExecutor(application.executorService.config, triggerContext);
6421
+ let workflowBuildResult;
5910
6422
  if (workflowResult && workflowResult.jobs.length > 0) {
5911
6423
  const mainJobNames = workflowResult.workflowSources.map((ws) => ws.workflow.mainJob.name);
5912
- await buildWorkflow(workflowResult.jobs, mainJobNames, application.env);
6424
+ workflowBuildResult = await buildWorkflow(workflowResult.jobs, mainJobNames, application.env, triggerContext);
5913
6425
  }
5914
6426
  if (buildOnly) return;
5915
6427
  const accessToken = await loadAccessToken({
@@ -5939,7 +6451,7 @@ async function apply(options) {
5939
6451
  const pipeline = await planPipeline(ctx);
5940
6452
  const app = await planApplication(ctx);
5941
6453
  const executor = await planExecutor(ctx);
5942
- const workflow = await planWorkflow(client, workspaceId, application.name, workflowResult?.workflows ?? {});
6454
+ const workflow = await planWorkflow(client, workspaceId, application.name, workflowResult?.workflows ?? {}, workflowBuildResult?.mainJobDeps ?? {});
5943
6455
  const allConflicts = [
5944
6456
  ...tailorDB.conflicts,
5945
6457
  ...staticWebsite.conflicts,
@@ -6009,14 +6521,14 @@ async function apply(options) {
6009
6521
  await applyTailorDB(client, tailorDB, "delete");
6010
6522
  console.log("Successfully applied changes.");
6011
6523
  }
6012
- async function buildPipeline(namespace, config) {
6013
- await bundleResolvers(namespace, config);
6524
+ async function buildPipeline(namespace, config, triggerContext) {
6525
+ await bundleResolvers(namespace, config, triggerContext);
6014
6526
  }
6015
- async function buildExecutor(config) {
6016
- await bundleExecutors(config);
6527
+ async function buildExecutor(config, triggerContext) {
6528
+ await bundleExecutors(config, triggerContext);
6017
6529
  }
6018
- async function buildWorkflow(collectedJobs, mainJobNames, env) {
6019
- await bundleWorkflowJobs(collectedJobs, mainJobNames, env);
6530
+ async function buildWorkflow(collectedJobs, mainJobNames, env, triggerContext) {
6531
+ return bundleWorkflowJobs(collectedJobs, mainJobNames, env, triggerContext);
6020
6532
  }
6021
6533
  const applyCommand = defineCommand({
6022
6534
  meta: {
@@ -6889,7 +7401,7 @@ async function execRemove(client, workspaceId, application, confirm) {
6889
7401
  const pipeline = await planPipeline(ctx);
6890
7402
  const app = await planApplication(ctx);
6891
7403
  const executor = await planExecutor(ctx);
6892
- const workflow = await planWorkflow(client, workspaceId, application.name, {});
7404
+ const workflow = await planWorkflow(client, workspaceId, application.name, {}, {});
6893
7405
  if (tailorDB.changeSet.service.deletes.length === 0 && staticWebsite.changeSet.deletes.length === 0 && idp.changeSet.service.deletes.length === 0 && auth.changeSet.service.deletes.length === 0 && pipeline.changeSet.service.deletes.length === 0 && app.deletes.length === 0 && executor.changeSet.deletes.length === 0 && workflow.changeSet.deletes.length === 0) return;
6894
7406
  if (confirm) await confirm();
6895
7407
  await applyWorkflow(client, workflow, "delete");
@@ -7448,4 +7960,4 @@ const listCommand = defineCommand({
7448
7960
 
7449
7961
  //#endregion
7450
7962
  export { PATScope, apply, applyCommand, commonArgs, createCommand, deleteCommand, fetchAll, fetchLatestToken, fetchUserInfo, formatArgs, generate, generateCommand, generateUserTypes, getCommand, initOAuth2Client, initOperatorClient, listCommand, listCommand$1, listCommand$2, loadAccessToken, loadConfig, loadWorkspaceId, machineUserList, machineUserToken, oauth2ClientGet, oauth2ClientList, parseFormat, printWithFormat, readPackageJson, readPlatformConfig, remove, removeCommand, show, showCommand, tokenCommand, withCommonArgs, workspaceCreate, workspaceDelete, workspaceList, writePlatformConfig };
7451
- //# sourceMappingURL=list-D-R1mEOM.mjs.map
7963
+ //# sourceMappingURL=list-CCYkqZyi.mjs.map