@tailor-platform/sdk 0.12.4 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +85 -0
- package/dist/cli/api.d.mts +1 -1
- package/dist/cli/api.mjs +2 -2
- package/dist/cli/index.mjs +471 -11
- package/dist/cli/index.mjs.map +1 -1
- package/dist/configure/index.d.mts +3 -3
- package/dist/configure/index.mjs +7 -2
- package/dist/configure/index.mjs.map +1 -1
- package/dist/{index-BjdZmtxR.d.mts → index-zRgZdNLm.d.mts} +31 -28
- package/dist/{job-wYkb6yMl.mjs → job-inTmXxpa.mjs} +5 -5
- package/dist/job-inTmXxpa.mjs.map +1 -0
- package/dist/{list-4T6XN_zi.mjs → list-B8Uv3SPW.mjs} +936 -397
- package/dist/list-B8Uv3SPW.mjs.map +1 -0
- package/dist/{types-CrOeSu4i.d.mts → types-DBHXcgFJ.d.mts} +53 -40
- package/dist/utils/test/index.d.mts +2 -2
- package/docs/cli-reference.md +122 -0
- package/docs/core-concepts.md +2 -2
- package/package.json +2 -2
- package/dist/job-wYkb6yMl.mjs.map +0 -1
- package/dist/list-4T6XN_zi.mjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WORKFLOW_JOB_BRAND, getDistDir, tailorUserMap } from "./job-
|
|
1
|
+
import { WORKFLOW_JOB_BRAND, getDistDir, tailorUserMap } from "./job-inTmXxpa.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
|
-
|
|
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
|
-
|
|
328
|
+
authInvoker: AuthInvokerSchema.optional()
|
|
165
329
|
});
|
|
166
330
|
const WebhookOperationSchema = z.object({
|
|
167
331
|
kind: z.literal("webhook"),
|
|
@@ -587,9 +751,7 @@ function defineApplication(config) {
|
|
|
587
751
|
//#region src/parser/service/workflow/schema.ts
|
|
588
752
|
const WorkflowJobSchema = z.object({
|
|
589
753
|
name: z.string(),
|
|
590
|
-
|
|
591
|
-
return z.array(WorkflowJobSchema).optional();
|
|
592
|
-
},
|
|
754
|
+
trigger: functionSchema,
|
|
593
755
|
body: functionSchema
|
|
594
756
|
});
|
|
595
757
|
const WorkflowSchema = z.object({
|
|
@@ -601,17 +763,16 @@ const WorkflowSchema = z.object({
|
|
|
601
763
|
//#region src/cli/application/workflow/service.ts
|
|
602
764
|
/**
|
|
603
765
|
* Load workflow files and collect all jobs in a single pass.
|
|
766
|
+
* Dependencies are detected at bundle time via AST analysis.
|
|
604
767
|
*/
|
|
605
768
|
async function loadAndCollectJobs(config) {
|
|
606
769
|
const workflows = {};
|
|
607
770
|
const workflowSources = [];
|
|
608
771
|
const collectedJobs = [];
|
|
609
|
-
let unusedJobs = [];
|
|
610
772
|
if (!config.files || config.files.length === 0) return {
|
|
611
773
|
workflows,
|
|
612
774
|
workflowSources,
|
|
613
775
|
jobs: collectedJobs,
|
|
614
|
-
unusedJobs,
|
|
615
776
|
fileCount: 0
|
|
616
777
|
};
|
|
617
778
|
const workflowFiles = loadFilesWithIgnores(config);
|
|
@@ -630,27 +791,13 @@ async function loadAndCollectJobs(config) {
|
|
|
630
791
|
const existing = allJobsMap.get(job.name);
|
|
631
792
|
if (existing) throw new Error(`Duplicate job name "${job.name}" found:\n - ${existing.sourceFile} (export: ${existing.exportName})\n - ${job.sourceFile} (export: ${job.exportName})\nEach job must have a unique name.`);
|
|
632
793
|
allJobsMap.set(job.name, job);
|
|
794
|
+
collectedJobs.push(job);
|
|
633
795
|
}
|
|
634
796
|
}
|
|
635
|
-
const tracedJobs = /* @__PURE__ */ new Map();
|
|
636
|
-
for (const { workflow } of workflowSources) traceJobDependencies(workflow.mainJob, tracedJobs);
|
|
637
|
-
const notExportedJobs = [];
|
|
638
|
-
for (const jobName of tracedJobs.keys()) if (!allJobsMap.has(jobName)) notExportedJobs.push(jobName);
|
|
639
|
-
if (notExportedJobs.length > 0) throw new Error(`The following workflow jobs are used but not exported:\n` + notExportedJobs.map((name) => ` - "${name}"`).join("\n") + "\n\nAll workflow jobs must be named exports. Example:\n export const myJob = createWorkflowJob({ name: \"my-job\", ... });\n\nAlso ensure that files containing job exports are included in the workflow.files glob pattern.");
|
|
640
|
-
unusedJobs = Array.from(allJobsMap.keys()).filter((jobName) => !tracedJobs.has(jobName));
|
|
641
|
-
for (const [jobName, job] of tracedJobs) {
|
|
642
|
-
const exportedMetadata = allJobsMap.get(jobName);
|
|
643
|
-
const depNames = job.deps?.map((dep) => dep.name);
|
|
644
|
-
collectedJobs.push({
|
|
645
|
-
...exportedMetadata,
|
|
646
|
-
deps: depNames
|
|
647
|
-
});
|
|
648
|
-
}
|
|
649
797
|
return {
|
|
650
798
|
workflows,
|
|
651
799
|
workflowSources,
|
|
652
800
|
jobs: collectedJobs,
|
|
653
|
-
unusedJobs,
|
|
654
801
|
fileCount
|
|
655
802
|
};
|
|
656
803
|
}
|
|
@@ -665,7 +812,6 @@ function printLoadedWorkflows(result) {
|
|
|
665
812
|
const relativePath = path.relative(process.cwd(), sourceFile);
|
|
666
813
|
console.log("Workflow:", styleText("greenBright", `"${workflow.name}"`), "loaded from", styleText("cyan", relativePath));
|
|
667
814
|
}
|
|
668
|
-
if (result.unusedJobs.length > 0) console.warn(`⚠️ Warning: Unused workflow jobs found: ${result.unusedJobs.join(", ")}`);
|
|
669
815
|
}
|
|
670
816
|
/**
|
|
671
817
|
* Load a single file and extract jobs and workflow
|
|
@@ -691,29 +837,583 @@ async function loadFileContent(filePath) {
|
|
|
691
837
|
}
|
|
692
838
|
}
|
|
693
839
|
} catch (error) {
|
|
694
|
-
const relativePath = path.relative(process.cwd(), filePath);
|
|
695
|
-
console.error(styleText("red", "Failed to load workflow from"), styleText("redBright", relativePath));
|
|
696
|
-
console.error(error);
|
|
697
|
-
throw error;
|
|
840
|
+
const relativePath = path.relative(process.cwd(), filePath);
|
|
841
|
+
console.error(styleText("red", "Failed to load workflow from"), styleText("redBright", relativePath));
|
|
842
|
+
console.error(error);
|
|
843
|
+
throw error;
|
|
844
|
+
}
|
|
845
|
+
return {
|
|
846
|
+
jobs,
|
|
847
|
+
workflow
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* Check if a value is a WorkflowJob by looking for the brand symbol
|
|
852
|
+
*/
|
|
853
|
+
function isWorkflowJob(value) {
|
|
854
|
+
return value != null && typeof value === "object" && WORKFLOW_JOB_BRAND in value && value[WORKFLOW_JOB_BRAND] === true;
|
|
855
|
+
}
|
|
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;
|
|
698
1394
|
}
|
|
699
1395
|
return {
|
|
700
|
-
|
|
701
|
-
|
|
1396
|
+
workflowNameMap,
|
|
1397
|
+
jobNameMap,
|
|
1398
|
+
workflowFileMap
|
|
702
1399
|
};
|
|
703
1400
|
}
|
|
704
1401
|
/**
|
|
705
|
-
*
|
|
706
|
-
|
|
707
|
-
function isWorkflowJob(value) {
|
|
708
|
-
return value != null && typeof value === "object" && WORKFLOW_JOB_BRAND in value && value[WORKFLOW_JOB_BRAND] === true;
|
|
709
|
-
}
|
|
710
|
-
/**
|
|
711
|
-
* Recursively trace all job dependencies
|
|
1402
|
+
* Create a rolldown plugin for transforming trigger calls
|
|
1403
|
+
* Returns undefined if no trigger context is provided
|
|
712
1404
|
*/
|
|
713
|
-
function
|
|
714
|
-
if (
|
|
715
|
-
|
|
716
|
-
|
|
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
|
+
};
|
|
717
1417
|
}
|
|
718
1418
|
|
|
719
1419
|
//#endregion
|
|
@@ -734,7 +1434,7 @@ async function loadExecutor(executorFilePath) {
|
|
|
734
1434
|
* 1. Creates entry file that extracts operation.body
|
|
735
1435
|
* 2. Bundles in a single step with tree-shaking
|
|
736
1436
|
*/
|
|
737
|
-
async function bundleExecutors(config) {
|
|
1437
|
+
async function bundleExecutors(config, triggerContext) {
|
|
738
1438
|
const files = loadFilesWithIgnores(config);
|
|
739
1439
|
if (files.length === 0) throw new Error(`No files found matching pattern: ${config.files?.join(", ")}`);
|
|
740
1440
|
console.log("");
|
|
@@ -767,10 +1467,10 @@ async function bundleExecutors(config) {
|
|
|
767
1467
|
} catch {
|
|
768
1468
|
tsconfig = void 0;
|
|
769
1469
|
}
|
|
770
|
-
await Promise.all(executors.map((executor) => bundleSingleExecutor(executor, outputDir, tsconfig)));
|
|
1470
|
+
await Promise.all(executors.map((executor) => bundleSingleExecutor(executor, outputDir, tsconfig, triggerContext)));
|
|
771
1471
|
console.log(styleText("green", "Bundled"), styleText("cyan", "\"executor\""));
|
|
772
1472
|
}
|
|
773
|
-
async function bundleSingleExecutor(executor, outputDir, tsconfig) {
|
|
1473
|
+
async function bundleSingleExecutor(executor, outputDir, tsconfig, triggerContext) {
|
|
774
1474
|
const entryPath = path.join(outputDir, `${executor.name}.entry.js`);
|
|
775
1475
|
const absoluteSourcePath = path.resolve(executor.sourceFile).replace(/\\/g, "/");
|
|
776
1476
|
const entryContent = ml`
|
|
@@ -782,6 +1482,8 @@ async function bundleSingleExecutor(executor, outputDir, tsconfig) {
|
|
|
782
1482
|
`;
|
|
783
1483
|
fs.writeFileSync(entryPath, entryContent);
|
|
784
1484
|
const outputPath = path.join(outputDir, `${executor.name}.js`);
|
|
1485
|
+
const triggerPlugin = createTriggerTransformPlugin(triggerContext);
|
|
1486
|
+
const plugins = triggerPlugin ? [triggerPlugin] : [];
|
|
785
1487
|
await rolldown.build(rolldown.defineConfig({
|
|
786
1488
|
input: entryPath,
|
|
787
1489
|
output: {
|
|
@@ -792,6 +1494,7 @@ async function bundleSingleExecutor(executor, outputDir, tsconfig) {
|
|
|
792
1494
|
inlineDynamicImports: true
|
|
793
1495
|
},
|
|
794
1496
|
tsconfig,
|
|
1497
|
+
plugins,
|
|
795
1498
|
treeshake: {
|
|
796
1499
|
moduleSideEffects: false,
|
|
797
1500
|
annotations: true,
|
|
@@ -820,7 +1523,7 @@ async function loadResolver(resolverFilePath) {
|
|
|
820
1523
|
* 2. Creates entry file
|
|
821
1524
|
* 3. Bundles in a single step with tree-shaking
|
|
822
1525
|
*/
|
|
823
|
-
async function bundleResolvers(namespace, config) {
|
|
1526
|
+
async function bundleResolvers(namespace, config, triggerContext) {
|
|
824
1527
|
const files = loadFilesWithIgnores(config);
|
|
825
1528
|
if (files.length === 0) throw new Error(`No files found matching pattern: ${config.files?.join(", ")}`);
|
|
826
1529
|
console.log("");
|
|
@@ -845,10 +1548,10 @@ async function bundleResolvers(namespace, config) {
|
|
|
845
1548
|
} catch {
|
|
846
1549
|
tsconfig = void 0;
|
|
847
1550
|
}
|
|
848
|
-
await Promise.all(resolvers.map((resolver) => bundleSingleResolver(resolver, outputDir, tsconfig)));
|
|
1551
|
+
await Promise.all(resolvers.map((resolver) => bundleSingleResolver(resolver, outputDir, tsconfig, triggerContext)));
|
|
849
1552
|
console.log(styleText("green", "Bundled"), styleText("cyan", `"${namespace}"`));
|
|
850
1553
|
}
|
|
851
|
-
async function bundleSingleResolver(resolver, outputDir, tsconfig) {
|
|
1554
|
+
async function bundleSingleResolver(resolver, outputDir, tsconfig, triggerContext) {
|
|
852
1555
|
const entryPath = path.join(outputDir, `${resolver.name}.entry.js`);
|
|
853
1556
|
const absoluteSourcePath = path.resolve(resolver.sourceFile).replace(/\\/g, "/");
|
|
854
1557
|
const entryContent = ml`
|
|
@@ -881,6 +1584,8 @@ async function bundleSingleResolver(resolver, outputDir, tsconfig) {
|
|
|
881
1584
|
`;
|
|
882
1585
|
fs.writeFileSync(entryPath, entryContent);
|
|
883
1586
|
const outputPath = path.join(outputDir, `${resolver.name}.js`);
|
|
1587
|
+
const triggerPlugin = createTriggerTransformPlugin(triggerContext);
|
|
1588
|
+
const plugins = triggerPlugin ? [triggerPlugin] : [];
|
|
884
1589
|
await rolldown.build(rolldown.defineConfig({
|
|
885
1590
|
input: entryPath,
|
|
886
1591
|
output: {
|
|
@@ -891,6 +1596,7 @@ async function bundleSingleResolver(resolver, outputDir, tsconfig) {
|
|
|
891
1596
|
inlineDynamicImports: true
|
|
892
1597
|
},
|
|
893
1598
|
tsconfig,
|
|
1599
|
+
plugins,
|
|
894
1600
|
treeshake: {
|
|
895
1601
|
moduleSideEffects: false,
|
|
896
1602
|
annotations: true,
|
|
@@ -901,227 +1607,7 @@ async function bundleSingleResolver(resolver, outputDir, tsconfig) {
|
|
|
901
1607
|
}
|
|
902
1608
|
|
|
903
1609
|
//#endregion
|
|
904
|
-
//#region src/cli/bundler/workflow/
|
|
905
|
-
/**
|
|
906
|
-
* Check if a module source is from \@tailor-platform/sdk (including subpaths)
|
|
907
|
-
*/
|
|
908
|
-
function isTailorSdkSource(source) {
|
|
909
|
-
return /^@tailor-platform\/sdk(\/|$)/.test(source);
|
|
910
|
-
}
|
|
911
|
-
/**
|
|
912
|
-
* Get the source string from a dynamic import or require call
|
|
913
|
-
*/
|
|
914
|
-
function getImportSource(node) {
|
|
915
|
-
if (!node) return null;
|
|
916
|
-
if (node.type === "ImportExpression") {
|
|
917
|
-
const source = node.source;
|
|
918
|
-
if (source.type === "Literal" && typeof source.value === "string") return source.value;
|
|
919
|
-
}
|
|
920
|
-
if (node.type === "CallExpression") {
|
|
921
|
-
const callExpr = node;
|
|
922
|
-
if (callExpr.callee.type === "Identifier" && callExpr.callee.name === "require") {
|
|
923
|
-
const arg = callExpr.arguments[0];
|
|
924
|
-
if (arg && "type" in arg && arg.type === "Literal" && "value" in arg && typeof arg.value === "string") return arg.value;
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
return null;
|
|
928
|
-
}
|
|
929
|
-
/**
|
|
930
|
-
* Unwrap AwaitExpression to get the inner expression
|
|
931
|
-
*/
|
|
932
|
-
function unwrapAwait(node) {
|
|
933
|
-
if (node?.type === "AwaitExpression") return node.argument;
|
|
934
|
-
return node;
|
|
935
|
-
}
|
|
936
|
-
/**
|
|
937
|
-
* Collect all import bindings for createWorkflowJob from \@tailor-platform/sdk
|
|
938
|
-
* Returns a Set of local names that refer to createWorkflowJob
|
|
939
|
-
*/
|
|
940
|
-
function collectCreateWorkflowJobBindings(program) {
|
|
941
|
-
const bindings = /* @__PURE__ */ new Set();
|
|
942
|
-
function walk(node) {
|
|
943
|
-
if (!node || typeof node !== "object") return;
|
|
944
|
-
const nodeType = node.type;
|
|
945
|
-
if (nodeType === "ImportDeclaration") {
|
|
946
|
-
const importDecl = node;
|
|
947
|
-
const source = importDecl.source?.value;
|
|
948
|
-
if (typeof source === "string" && isTailorSdkSource(source)) {
|
|
949
|
-
for (const specifier of importDecl.specifiers || []) if (specifier.type === "ImportSpecifier") {
|
|
950
|
-
const importSpec = specifier;
|
|
951
|
-
const imported = importSpec.imported.type === "Identifier" ? importSpec.imported.name : importSpec.imported.value;
|
|
952
|
-
if (imported === "createWorkflowJob") bindings.add(importSpec.local?.name || imported);
|
|
953
|
-
} else if (specifier.type === "ImportDefaultSpecifier" || specifier.type === "ImportNamespaceSpecifier") {
|
|
954
|
-
const spec = specifier;
|
|
955
|
-
bindings.add(`__namespace__:${spec.local?.name}`);
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
if (nodeType === "VariableDeclaration") {
|
|
960
|
-
const varDecl = node;
|
|
961
|
-
for (const decl of varDecl.declarations || []) {
|
|
962
|
-
const init = unwrapAwait(decl.init);
|
|
963
|
-
const source = getImportSource(init);
|
|
964
|
-
if (source && isTailorSdkSource(source)) {
|
|
965
|
-
const id = decl.id;
|
|
966
|
-
if (id?.type === "Identifier") bindings.add(`__namespace__:${id.name}`);
|
|
967
|
-
else if (id?.type === "ObjectPattern") {
|
|
968
|
-
const objPattern = id;
|
|
969
|
-
for (const prop of objPattern.properties || []) if (prop.type === "Property") {
|
|
970
|
-
const bindingProp = prop;
|
|
971
|
-
const keyName = bindingProp.key.type === "Identifier" ? bindingProp.key.name : bindingProp.key.value;
|
|
972
|
-
if (keyName === "createWorkflowJob") {
|
|
973
|
-
const localName = bindingProp.value.type === "Identifier" ? bindingProp.value.name : keyName;
|
|
974
|
-
bindings.add(localName ?? "");
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
for (const key of Object.keys(node)) {
|
|
982
|
-
const child = node[key];
|
|
983
|
-
if (Array.isArray(child)) child.forEach((c) => walk(c));
|
|
984
|
-
else if (child && typeof child === "object") walk(child);
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
walk(program);
|
|
988
|
-
return bindings;
|
|
989
|
-
}
|
|
990
|
-
/**
|
|
991
|
-
* Check if a CallExpression is a createWorkflowJob call
|
|
992
|
-
*/
|
|
993
|
-
function isCreateWorkflowJobCall(node, bindings) {
|
|
994
|
-
if (node.type !== "CallExpression") return false;
|
|
995
|
-
const callee = node.callee;
|
|
996
|
-
if (callee.type === "Identifier") {
|
|
997
|
-
const identifier = callee;
|
|
998
|
-
return bindings.has(identifier.name);
|
|
999
|
-
}
|
|
1000
|
-
if (callee.type === "MemberExpression") {
|
|
1001
|
-
const memberExpr = callee;
|
|
1002
|
-
if (!memberExpr.computed) {
|
|
1003
|
-
const object = memberExpr.object;
|
|
1004
|
-
const property = memberExpr.property;
|
|
1005
|
-
if (object.type === "Identifier" && bindings.has(`__namespace__:${object.name}`) && property.name === "createWorkflowJob") return true;
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
return false;
|
|
1009
|
-
}
|
|
1010
|
-
/**
|
|
1011
|
-
* Check if a node is a string literal
|
|
1012
|
-
*/
|
|
1013
|
-
function isStringLiteral(node) {
|
|
1014
|
-
return node?.type === "Literal" && typeof node.value === "string";
|
|
1015
|
-
}
|
|
1016
|
-
/**
|
|
1017
|
-
* Check if a node is a function expression (arrow or regular)
|
|
1018
|
-
*/
|
|
1019
|
-
function isFunctionExpression(node) {
|
|
1020
|
-
return node?.type === "ArrowFunctionExpression" || node?.type === "FunctionExpression";
|
|
1021
|
-
}
|
|
1022
|
-
/**
|
|
1023
|
-
* Find a property in an object expression
|
|
1024
|
-
*/
|
|
1025
|
-
function findProperty(properties, name) {
|
|
1026
|
-
for (const prop of properties) if (prop.type === "Property") {
|
|
1027
|
-
const objProp = prop;
|
|
1028
|
-
if ((objProp.key.type === "Identifier" ? objProp.key.name : objProp.key.type === "Literal" ? objProp.key.value : null) === name) return {
|
|
1029
|
-
key: objProp.key,
|
|
1030
|
-
value: objProp.value,
|
|
1031
|
-
start: objProp.start,
|
|
1032
|
-
end: objProp.end
|
|
1033
|
-
};
|
|
1034
|
-
}
|
|
1035
|
-
return null;
|
|
1036
|
-
}
|
|
1037
|
-
/**
|
|
1038
|
-
* Find all workflow jobs by detecting createWorkflowJob calls from \@tailor-platform/sdk
|
|
1039
|
-
*/
|
|
1040
|
-
function findAllJobs(program, _sourceText) {
|
|
1041
|
-
const jobs = [];
|
|
1042
|
-
const bindings = collectCreateWorkflowJobBindings(program);
|
|
1043
|
-
function walk(node, parents = []) {
|
|
1044
|
-
if (!node || typeof node !== "object") return;
|
|
1045
|
-
if (isCreateWorkflowJobCall(node, bindings)) {
|
|
1046
|
-
const args = node.arguments;
|
|
1047
|
-
if (args?.length >= 1 && args[0]?.type === "ObjectExpression") {
|
|
1048
|
-
const configObj = args[0];
|
|
1049
|
-
const nameProp = findProperty(configObj.properties, "name");
|
|
1050
|
-
const bodyProp = findProperty(configObj.properties, "body");
|
|
1051
|
-
const depsProp = findProperty(configObj.properties, "deps");
|
|
1052
|
-
if (nameProp && isStringLiteral(nameProp.value) && bodyProp && isFunctionExpression(bodyProp.value)) {
|
|
1053
|
-
let statementRange;
|
|
1054
|
-
for (let i = 0; i < parents.length; i++) {
|
|
1055
|
-
const parent = parents[i];
|
|
1056
|
-
if (parent.type === "ExportNamedDeclaration" || parent.type === "VariableDeclaration") {
|
|
1057
|
-
statementRange = {
|
|
1058
|
-
start: parent.start,
|
|
1059
|
-
end: parent.end
|
|
1060
|
-
};
|
|
1061
|
-
break;
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
jobs.push({
|
|
1065
|
-
name: nameProp.value.value,
|
|
1066
|
-
nameRange: {
|
|
1067
|
-
start: nameProp.start,
|
|
1068
|
-
end: nameProp.end
|
|
1069
|
-
},
|
|
1070
|
-
depsRange: depsProp ? {
|
|
1071
|
-
start: depsProp.start,
|
|
1072
|
-
end: depsProp.end
|
|
1073
|
-
} : void 0,
|
|
1074
|
-
bodyValueRange: {
|
|
1075
|
-
start: bodyProp.value.start,
|
|
1076
|
-
end: bodyProp.value.end
|
|
1077
|
-
},
|
|
1078
|
-
statementRange
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
const newParents = [...parents, node];
|
|
1084
|
-
for (const key of Object.keys(node)) {
|
|
1085
|
-
const child = node[key];
|
|
1086
|
-
if (Array.isArray(child)) child.forEach((c) => walk(c, newParents));
|
|
1087
|
-
else if (child && typeof child === "object") walk(child, newParents);
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
walk(program);
|
|
1091
|
-
return jobs;
|
|
1092
|
-
}
|
|
1093
|
-
/**
|
|
1094
|
-
* Apply string replacements to source code
|
|
1095
|
-
* Replacements are applied from end to start to maintain positions
|
|
1096
|
-
*/
|
|
1097
|
-
function applyReplacements(source, replacements) {
|
|
1098
|
-
const sorted = [...replacements].sort((a, b) => b.start - a.start);
|
|
1099
|
-
let result = source;
|
|
1100
|
-
for (const r of sorted) result = result.slice(0, r.start) + r.text + result.slice(r.end);
|
|
1101
|
-
return result;
|
|
1102
|
-
}
|
|
1103
|
-
/**
|
|
1104
|
-
* Find the end position including trailing comma
|
|
1105
|
-
*/
|
|
1106
|
-
function findTrailingCommaEnd(source, position) {
|
|
1107
|
-
let i = position;
|
|
1108
|
-
while (i < source.length) {
|
|
1109
|
-
const char = source[i];
|
|
1110
|
-
if (char === ",") return i + 1;
|
|
1111
|
-
if (!/\s/.test(char)) break;
|
|
1112
|
-
i++;
|
|
1113
|
-
}
|
|
1114
|
-
return position;
|
|
1115
|
-
}
|
|
1116
|
-
/**
|
|
1117
|
-
* Find the end of a statement including any trailing newline
|
|
1118
|
-
*/
|
|
1119
|
-
function findStatementEnd(source, position) {
|
|
1120
|
-
let i = position;
|
|
1121
|
-
while (i < source.length && (source[i] === ";" || source[i] === " " || source[i] === " ")) i++;
|
|
1122
|
-
if (i < source.length && source[i] === "\n") i++;
|
|
1123
|
-
return i;
|
|
1124
|
-
}
|
|
1610
|
+
//#region src/cli/bundler/workflow/source-transformer.ts
|
|
1125
1611
|
/**
|
|
1126
1612
|
* Find variable declarations by export names
|
|
1127
1613
|
* Returns a map of export name to statement range
|
|
@@ -1162,54 +1648,74 @@ function findVariableDeclarationsByName(program) {
|
|
|
1162
1648
|
}
|
|
1163
1649
|
/**
|
|
1164
1650
|
* Transform workflow source code
|
|
1165
|
-
* -
|
|
1651
|
+
* - Transform .trigger() calls to tailor.workflow.triggerJobFunction()
|
|
1166
1652
|
* - Other jobs: remove entire variable declaration
|
|
1167
1653
|
*
|
|
1168
1654
|
* @param source - The source code to transform
|
|
1169
1655
|
* @param targetJobName - The name of the target job (from job config)
|
|
1170
1656
|
* @param targetJobExportName - The export name of the target job (optional, for enhanced detection)
|
|
1171
1657
|
* @param otherJobExportNames - Export names of other jobs to remove (optional, for enhanced detection)
|
|
1658
|
+
* @param allJobsMap - Map from export name to job name for trigger transformation (optional)
|
|
1172
1659
|
*/
|
|
1173
|
-
function transformWorkflowSource(source, targetJobName, targetJobExportName, otherJobExportNames) {
|
|
1660
|
+
function transformWorkflowSource(source, targetJobName, targetJobExportName, otherJobExportNames, allJobsMap) {
|
|
1174
1661
|
const { program } = parseSync("input.ts", source);
|
|
1175
1662
|
const detectedJobs = findAllJobs(program, source);
|
|
1663
|
+
const jobNameMap = allJobsMap ?? buildJobNameMap(detectedJobs);
|
|
1176
1664
|
const allDeclarations = findVariableDeclarationsByName(program);
|
|
1665
|
+
const triggerCalls = detectTriggerCalls(program, source);
|
|
1177
1666
|
const replacements = [];
|
|
1178
|
-
const removedRanges =
|
|
1179
|
-
const
|
|
1180
|
-
removedRanges.
|
|
1667
|
+
const removedRanges = [];
|
|
1668
|
+
const isInsideRemovedRange = (pos) => {
|
|
1669
|
+
return removedRanges.some((r) => pos >= r.start && pos < r.end);
|
|
1181
1670
|
};
|
|
1182
|
-
const
|
|
1183
|
-
return removedRanges.
|
|
1671
|
+
const isAlreadyMarkedForRemoval = (start) => {
|
|
1672
|
+
return removedRanges.some((r) => r.start === start);
|
|
1184
1673
|
};
|
|
1185
|
-
for (const job of detectedJobs)
|
|
1186
|
-
if (job.
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1674
|
+
for (const job of detectedJobs) {
|
|
1675
|
+
if (job.name === targetJobName) continue;
|
|
1676
|
+
if (job.statementRange && !isAlreadyMarkedForRemoval(job.statementRange.start)) {
|
|
1677
|
+
const endPos = findStatementEnd(source, job.statementRange.end);
|
|
1678
|
+
removedRanges.push({
|
|
1679
|
+
start: job.statementRange.start,
|
|
1680
|
+
end: endPos
|
|
1681
|
+
});
|
|
1682
|
+
replacements.push({
|
|
1683
|
+
start: job.statementRange.start,
|
|
1684
|
+
end: endPos,
|
|
1685
|
+
text: ""
|
|
1686
|
+
});
|
|
1687
|
+
} else if (!job.statementRange) replacements.push({
|
|
1688
|
+
start: job.bodyValueRange.start,
|
|
1689
|
+
end: job.bodyValueRange.end,
|
|
1690
|
+
text: "() => {}"
|
|
1196
1691
|
});
|
|
1197
|
-
|
|
1198
|
-
} else if (!job.statementRange) replacements.push({
|
|
1199
|
-
start: job.bodyValueRange.start,
|
|
1200
|
-
end: job.bodyValueRange.end,
|
|
1201
|
-
text: "() => {}"
|
|
1202
|
-
});
|
|
1692
|
+
}
|
|
1203
1693
|
if (otherJobExportNames) for (const exportName of otherJobExportNames) {
|
|
1204
1694
|
if (exportName === targetJobExportName) continue;
|
|
1205
1695
|
const declRange = allDeclarations.get(exportName);
|
|
1206
|
-
if (declRange && !
|
|
1696
|
+
if (declRange && !isAlreadyMarkedForRemoval(declRange.start)) {
|
|
1697
|
+
const endPos = findStatementEnd(source, declRange.end);
|
|
1698
|
+
removedRanges.push({
|
|
1699
|
+
start: declRange.start,
|
|
1700
|
+
end: endPos
|
|
1701
|
+
});
|
|
1207
1702
|
replacements.push({
|
|
1208
1703
|
start: declRange.start,
|
|
1209
|
-
end:
|
|
1704
|
+
end: endPos,
|
|
1210
1705
|
text: ""
|
|
1211
1706
|
});
|
|
1212
|
-
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
for (const call of triggerCalls) {
|
|
1710
|
+
if (isInsideRemovedRange(call.callRange.start)) continue;
|
|
1711
|
+
const jobName = jobNameMap.get(call.identifierName);
|
|
1712
|
+
if (jobName) {
|
|
1713
|
+
const transformedCall = `tailor.workflow.triggerJobFunction("${jobName}", ${call.argsText || "undefined"})`;
|
|
1714
|
+
replacements.push({
|
|
1715
|
+
start: call.callRange.start,
|
|
1716
|
+
end: call.callRange.end,
|
|
1717
|
+
text: transformedCall
|
|
1718
|
+
});
|
|
1213
1719
|
}
|
|
1214
1720
|
}
|
|
1215
1721
|
return applyReplacements(source, replacements);
|
|
@@ -1221,18 +1727,20 @@ function transformWorkflowSource(source, targetJobName, targetJobExportName, oth
|
|
|
1221
1727
|
* Bundle workflow jobs
|
|
1222
1728
|
*
|
|
1223
1729
|
* This function:
|
|
1224
|
-
* 1.
|
|
1225
|
-
* 2.
|
|
1226
|
-
* 3.
|
|
1730
|
+
* 1. Detects which jobs are actually used (mainJobs + their dependencies)
|
|
1731
|
+
* 2. Uses a transform plugin to transform trigger calls during bundling
|
|
1732
|
+
* 3. Creates entry file and bundles with tree-shaking
|
|
1227
1733
|
*/
|
|
1228
|
-
async function bundleWorkflowJobs(allJobs) {
|
|
1734
|
+
async function bundleWorkflowJobs(allJobs, mainJobNames, env = {}, triggerContext) {
|
|
1229
1735
|
if (allJobs.length === 0) {
|
|
1230
1736
|
console.log(styleText("dim", "No workflow jobs to bundle"));
|
|
1231
1737
|
return;
|
|
1232
1738
|
}
|
|
1739
|
+
const usedJobs = await filterUsedJobs(allJobs, mainJobNames);
|
|
1233
1740
|
console.log("");
|
|
1234
|
-
console.log("Bundling", styleText("cyanBright",
|
|
1741
|
+
console.log("Bundling", styleText("cyanBright", usedJobs.length.toString()), "files for", styleText("cyan", "\"workflow-job\""));
|
|
1235
1742
|
const outputDir = path.resolve(getDistDir(), "workflow-jobs");
|
|
1743
|
+
if (fs.existsSync(outputDir)) fs.rmSync(outputDir, { recursive: true });
|
|
1236
1744
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
1237
1745
|
let tsconfig;
|
|
1238
1746
|
try {
|
|
@@ -1240,28 +1748,81 @@ async function bundleWorkflowJobs(allJobs) {
|
|
|
1240
1748
|
} catch {
|
|
1241
1749
|
tsconfig = void 0;
|
|
1242
1750
|
}
|
|
1243
|
-
await Promise.all(
|
|
1751
|
+
await Promise.all(usedJobs.map((job) => bundleSingleJob(job, usedJobs, outputDir, tsconfig, env, triggerContext)));
|
|
1244
1752
|
console.log(styleText("green", "Bundled"), styleText("cyan", "\"workflow-job\""));
|
|
1245
1753
|
}
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1754
|
+
/**
|
|
1755
|
+
* Filter jobs to only include those that are actually used.
|
|
1756
|
+
* A job is "used" if:
|
|
1757
|
+
* - It's a mainJob of a workflow
|
|
1758
|
+
* - It's called via .trigger() from another used job (transitively)
|
|
1759
|
+
*/
|
|
1760
|
+
async function filterUsedJobs(allJobs, mainJobNames) {
|
|
1761
|
+
if (allJobs.length === 0 || mainJobNames.length === 0) return [];
|
|
1762
|
+
const jobsBySourceFile = /* @__PURE__ */ new Map();
|
|
1763
|
+
for (const job of allJobs) {
|
|
1764
|
+
const existing = jobsBySourceFile.get(job.sourceFile) || [];
|
|
1765
|
+
existing.push(job);
|
|
1766
|
+
jobsBySourceFile.set(job.sourceFile, existing);
|
|
1767
|
+
}
|
|
1768
|
+
const exportNameToJobName = /* @__PURE__ */ new Map();
|
|
1769
|
+
for (const job of allJobs) exportNameToJobName.set(job.exportName, job.name);
|
|
1770
|
+
const dependencies = /* @__PURE__ */ new Map();
|
|
1771
|
+
const fileResults = await Promise.all(Array.from(jobsBySourceFile.entries()).map(async ([sourceFile, jobs]) => {
|
|
1772
|
+
try {
|
|
1773
|
+
const source = await fs.promises.readFile(sourceFile, "utf-8");
|
|
1774
|
+
const { program } = parseSync("input.ts", source);
|
|
1775
|
+
const detectedJobs = findAllJobs(program, source);
|
|
1776
|
+
const localExportNameToJobName = /* @__PURE__ */ new Map();
|
|
1777
|
+
for (const detected of detectedJobs) if (detected.exportName) localExportNameToJobName.set(detected.exportName, detected.name);
|
|
1778
|
+
const triggerCalls = detectTriggerCalls(program, source);
|
|
1779
|
+
const jobDependencies = [];
|
|
1780
|
+
for (const job of jobs) {
|
|
1781
|
+
const detectedJob = detectedJobs.find((d) => d.name === job.name);
|
|
1782
|
+
if (!detectedJob) continue;
|
|
1783
|
+
const jobDeps = /* @__PURE__ */ new Set();
|
|
1784
|
+
for (const call of triggerCalls) if (detectedJob.bodyValueRange && call.callRange.start >= detectedJob.bodyValueRange.start && call.callRange.end <= detectedJob.bodyValueRange.end) {
|
|
1785
|
+
const triggeredJobName = localExportNameToJobName.get(call.identifierName) || exportNameToJobName.get(call.identifierName);
|
|
1786
|
+
if (triggeredJobName) jobDeps.add(triggeredJobName);
|
|
1787
|
+
}
|
|
1788
|
+
if (jobDeps.size > 0) jobDependencies.push({
|
|
1789
|
+
jobName: job.name,
|
|
1790
|
+
deps: jobDeps
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
return jobDependencies;
|
|
1794
|
+
} catch {
|
|
1795
|
+
return [];
|
|
1796
|
+
}
|
|
1797
|
+
}));
|
|
1798
|
+
for (const jobDependencies of fileResults) for (const { jobName, deps } of jobDependencies) dependencies.set(jobName, deps);
|
|
1799
|
+
const usedJobNames = /* @__PURE__ */ new Set();
|
|
1800
|
+
function markUsed(jobName) {
|
|
1801
|
+
if (usedJobNames.has(jobName)) return;
|
|
1802
|
+
usedJobNames.add(jobName);
|
|
1803
|
+
const deps = dependencies.get(jobName);
|
|
1804
|
+
if (deps) for (const dep of deps) markUsed(dep);
|
|
1805
|
+
}
|
|
1806
|
+
for (const mainJobName of mainJobNames) markUsed(mainJobName);
|
|
1807
|
+
return allJobs.filter((job) => usedJobNames.has(job.name));
|
|
1808
|
+
}
|
|
1809
|
+
async function bundleSingleJob(job, allJobs, outputDir, tsconfig, env, triggerContext) {
|
|
1249
1810
|
const entryPath = path.join(outputDir, `${job.name}.entry.js`);
|
|
1250
1811
|
const absoluteSourcePath = path.resolve(job.sourceFile).replace(/\\/g, "/");
|
|
1251
1812
|
const entryContent = ml`
|
|
1252
1813
|
import { ${job.exportName} } from "${absoluteSourcePath}";
|
|
1253
1814
|
|
|
1254
|
-
const
|
|
1255
|
-
${jobsObject}
|
|
1256
|
-
};
|
|
1815
|
+
const env = ${JSON.stringify(env)};
|
|
1257
1816
|
|
|
1258
1817
|
globalThis.main = async (input) => {
|
|
1259
|
-
return await ${job.exportName}.body(input,
|
|
1818
|
+
return await ${job.exportName}.body(input, { env });
|
|
1260
1819
|
};
|
|
1261
1820
|
`;
|
|
1262
1821
|
fs.writeFileSync(entryPath, entryContent);
|
|
1263
1822
|
const outputPath = path.join(outputDir, `${job.name}.js`);
|
|
1264
1823
|
const otherJobExportNames = allJobs.filter((j) => j.name !== job.name).map((j) => j.exportName);
|
|
1824
|
+
const allJobsMap = /* @__PURE__ */ new Map();
|
|
1825
|
+
for (const j of allJobs) allJobsMap.set(j.exportName, j.name);
|
|
1265
1826
|
await rolldown.build(rolldown.defineConfig({
|
|
1266
1827
|
input: entryPath,
|
|
1267
1828
|
output: {
|
|
@@ -1276,9 +1837,11 @@ async function bundleSingleJob(job, allJobs, outputDir, tsconfig) {
|
|
|
1276
1837
|
name: "workflow-transform",
|
|
1277
1838
|
transform: {
|
|
1278
1839
|
filter: { id: { include: [/\.ts$/, /\.js$/] } },
|
|
1279
|
-
handler(code) {
|
|
1280
|
-
if (!code.includes("createWorkflowJob")) return null;
|
|
1281
|
-
|
|
1840
|
+
handler(code, id) {
|
|
1841
|
+
if (!code.includes("createWorkflowJob") && !code.includes("createWorkflow") && !code.includes(".trigger(")) return null;
|
|
1842
|
+
let transformed = transformWorkflowSource(code, job.name, job.exportName, otherJobExportNames, allJobsMap);
|
|
1843
|
+
if (triggerContext && transformed.includes(".trigger(")) transformed = transformFunctionTriggers(transformed, triggerContext.workflowNameMap, triggerContext.jobNameMap, triggerContext.workflowFileMap, id);
|
|
1844
|
+
return { code: transformed };
|
|
1282
1845
|
}
|
|
1283
1846
|
}
|
|
1284
1847
|
}],
|
|
@@ -1290,18 +1853,6 @@ async function bundleSingleJob(job, allJobs, outputDir, tsconfig) {
|
|
|
1290
1853
|
logLevel: "silent"
|
|
1291
1854
|
}));
|
|
1292
1855
|
}
|
|
1293
|
-
/**
|
|
1294
|
-
* Find the dependencies of a specific job
|
|
1295
|
-
*/
|
|
1296
|
-
function findJobDeps(targetJobName, allJobs) {
|
|
1297
|
-
return allJobs.find((j) => j.name === targetJobName)?.deps ?? [];
|
|
1298
|
-
}
|
|
1299
|
-
function generateJobsObject(jobNames) {
|
|
1300
|
-
if (jobNames.length === 0) return "";
|
|
1301
|
-
return jobNames.map((jobName) => {
|
|
1302
|
-
return `"${jobName.replace(/[-\s]/g, "_")}": (args) => tailor.workflow.triggerJobFunction("${jobName}", args)`;
|
|
1303
|
-
}).join(",\n ");
|
|
1304
|
-
}
|
|
1305
1856
|
|
|
1306
1857
|
//#endregion
|
|
1307
1858
|
//#region src/parser/generator-config/index.ts
|
|
@@ -3866,12 +4417,12 @@ function protoIdPConfig(idpConfig) {
|
|
|
3866
4417
|
value: {
|
|
3867
4418
|
...idpConfig.metadataURL !== void 0 ? { metadataUrl: idpConfig.metadataURL } : { rawMetadata: idpConfig.rawMetadata },
|
|
3868
4419
|
...idpConfig.spCertBase64 && { spCertBase64: {
|
|
3869
|
-
vaultName: idpConfig.spCertBase64.
|
|
3870
|
-
secretKey: idpConfig.spCertBase64.
|
|
4420
|
+
vaultName: idpConfig.spCertBase64.vaultName,
|
|
4421
|
+
secretKey: idpConfig.spCertBase64.secretKey
|
|
3871
4422
|
} },
|
|
3872
4423
|
...idpConfig.spKeyBase64 && { spKeyBase64: {
|
|
3873
|
-
vaultName: idpConfig.spKeyBase64.
|
|
3874
|
-
secretKey: idpConfig.spKeyBase64.
|
|
4424
|
+
vaultName: idpConfig.spKeyBase64.vaultName,
|
|
4425
|
+
secretKey: idpConfig.spKeyBase64.secretKey
|
|
3875
4426
|
} }
|
|
3876
4427
|
}
|
|
3877
4428
|
} }
|
|
@@ -3884,8 +4435,8 @@ function protoIdPConfig(idpConfig) {
|
|
|
3884
4435
|
value: {
|
|
3885
4436
|
clientIdKey: idpConfig.clientID,
|
|
3886
4437
|
clientSecretKey: {
|
|
3887
|
-
vaultName: idpConfig.clientSecret.
|
|
3888
|
-
secretKey: idpConfig.clientSecret.
|
|
4438
|
+
vaultName: idpConfig.clientSecret.vaultName,
|
|
4439
|
+
secretKey: idpConfig.clientSecret.secretKey
|
|
3889
4440
|
},
|
|
3890
4441
|
providerUrl: idpConfig.providerURL,
|
|
3891
4442
|
issuerUrl: idpConfig.issuerURL,
|
|
@@ -4321,8 +4872,8 @@ function protoSCIMConfig(scimConfig) {
|
|
|
4321
4872
|
authorizationConfig: {
|
|
4322
4873
|
case: "bearerSecret",
|
|
4323
4874
|
value: {
|
|
4324
|
-
vaultName: scimConfig.authorization.bearerSecret?.
|
|
4325
|
-
secretKey: scimConfig.authorization.bearerSecret?.
|
|
4875
|
+
vaultName: scimConfig.authorization.bearerSecret?.vaultName,
|
|
4876
|
+
secretKey: scimConfig.authorization.bearerSecret?.secretKey
|
|
4326
4877
|
}
|
|
4327
4878
|
}
|
|
4328
4879
|
};
|
|
@@ -4709,10 +5260,7 @@ function protoExecutor(appName, executor, env) {
|
|
|
4709
5260
|
appName: target.appName ?? appName,
|
|
4710
5261
|
query: target.query,
|
|
4711
5262
|
variables: target.variables ? { expr: `(${target.variables.toString()})(args)` } : void 0,
|
|
4712
|
-
invoker: target.
|
|
4713
|
-
namespace: target.invoker.authName,
|
|
4714
|
-
machineUserName: target.invoker.machineUser
|
|
4715
|
-
} : void 0
|
|
5263
|
+
invoker: target.authInvoker ?? void 0
|
|
4716
5264
|
}
|
|
4717
5265
|
} };
|
|
4718
5266
|
break;
|
|
@@ -4728,10 +5276,7 @@ function protoExecutor(appName, executor, env) {
|
|
|
4728
5276
|
name: `${executor.name}__target`,
|
|
4729
5277
|
script,
|
|
4730
5278
|
variables: { expr: `({ ...args, appNamespace: args.namespaceName, env: ${JSON.stringify(env)} })` },
|
|
4731
|
-
invoker: target.
|
|
4732
|
-
namespace: target.invoker.authName,
|
|
4733
|
-
machineUserName: target.invoker.machineUser
|
|
4734
|
-
} : void 0
|
|
5279
|
+
invoker: target.authInvoker ?? void 0
|
|
4735
5280
|
}
|
|
4736
5281
|
} };
|
|
4737
5282
|
break;
|
|
@@ -5685,59 +6230,56 @@ function protoGqlOperand(operand) {
|
|
|
5685
6230
|
async function applyWorkflow(client, result, phase = "create-update") {
|
|
5686
6231
|
const { changeSet } = result;
|
|
5687
6232
|
if (phase === "create-update") {
|
|
5688
|
-
await
|
|
5689
|
-
|
|
5690
|
-
for (const [jobName, script] of create.scripts.entries()) {
|
|
5691
|
-
const response = await client.createWorkflowJobFunction({
|
|
5692
|
-
workspaceId: create.workspaceId,
|
|
5693
|
-
jobFunctionName: jobName,
|
|
5694
|
-
script
|
|
5695
|
-
});
|
|
5696
|
-
if (response.jobFunction) jobFunctions[jobName] = response.jobFunction.version;
|
|
5697
|
-
}
|
|
6233
|
+
const jobFunctionVersions = await registerJobFunctions(client, changeSet);
|
|
6234
|
+
await Promise.all([...changeSet.creates.map(async (create) => {
|
|
5698
6235
|
await client.createWorkflow({
|
|
5699
6236
|
workspaceId: create.workspaceId,
|
|
5700
6237
|
workflowName: create.workflow.name,
|
|
5701
6238
|
mainJobFunctionName: create.workflow.mainJob.name,
|
|
5702
|
-
jobFunctions
|
|
6239
|
+
jobFunctions: jobFunctionVersions
|
|
5703
6240
|
});
|
|
5704
6241
|
await client.setMetadata(create.metaRequest);
|
|
5705
|
-
}))
|
|
5706
|
-
await Promise.all(changeSet.updates.map(async (update) => {
|
|
5707
|
-
const jobFunctions = {};
|
|
5708
|
-
for (const [jobName, script] of update.scripts.entries()) {
|
|
5709
|
-
const response = await client.updateWorkflowJobFunction({
|
|
5710
|
-
workspaceId: update.workspaceId,
|
|
5711
|
-
jobFunctionName: jobName,
|
|
5712
|
-
script
|
|
5713
|
-
});
|
|
5714
|
-
if (response.jobFunction) jobFunctions[jobName] = response.jobFunction.version;
|
|
5715
|
-
}
|
|
6242
|
+
}), ...changeSet.updates.map(async (update) => {
|
|
5716
6243
|
await client.updateWorkflow({
|
|
5717
6244
|
workspaceId: update.workspaceId,
|
|
5718
6245
|
workflowName: update.workflow.name,
|
|
5719
6246
|
mainJobFunctionName: update.workflow.mainJob.name,
|
|
5720
|
-
jobFunctions
|
|
6247
|
+
jobFunctions: jobFunctionVersions
|
|
5721
6248
|
});
|
|
5722
6249
|
await client.setMetadata(update.metaRequest);
|
|
5723
|
-
}));
|
|
6250
|
+
})]);
|
|
5724
6251
|
} else if (phase === "delete") await Promise.all(changeSet.deletes.map((del) => client.deleteWorkflow({
|
|
5725
6252
|
workspaceId: del.workspaceId,
|
|
5726
6253
|
workflowId: del.workflowId
|
|
5727
6254
|
})));
|
|
5728
6255
|
}
|
|
5729
6256
|
/**
|
|
5730
|
-
*
|
|
6257
|
+
* Register all job functions once, returns a map of job name to version.
|
|
6258
|
+
* Uses update for existing workflows, create for new workflows.
|
|
5731
6259
|
*/
|
|
5732
|
-
function
|
|
5733
|
-
const
|
|
5734
|
-
const
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
6260
|
+
async function registerJobFunctions(client, changeSet) {
|
|
6261
|
+
const jobFunctionVersions = {};
|
|
6262
|
+
const firstWorkflow = changeSet.creates[0] || changeSet.updates[0];
|
|
6263
|
+
if (!firstWorkflow) return jobFunctionVersions;
|
|
6264
|
+
const { workspaceId, scripts } = firstWorkflow;
|
|
6265
|
+
const hasExistingWorkflows = changeSet.updates.length > 0;
|
|
6266
|
+
const results = await Promise.all(Array.from(scripts.entries()).map(async ([jobName, script]) => {
|
|
6267
|
+
const response = hasExistingWorkflows ? await client.updateWorkflowJobFunction({
|
|
6268
|
+
workspaceId,
|
|
6269
|
+
jobFunctionName: jobName,
|
|
6270
|
+
script
|
|
6271
|
+
}) : await client.createWorkflowJobFunction({
|
|
6272
|
+
workspaceId,
|
|
6273
|
+
jobFunctionName: jobName,
|
|
6274
|
+
script
|
|
6275
|
+
});
|
|
6276
|
+
return {
|
|
6277
|
+
jobName,
|
|
6278
|
+
version: response.jobFunction?.version
|
|
6279
|
+
};
|
|
6280
|
+
}));
|
|
6281
|
+
for (const { jobName, version } of results) if (version) jobFunctionVersions[jobName] = version;
|
|
6282
|
+
return jobFunctionVersions;
|
|
5741
6283
|
}
|
|
5742
6284
|
function trn(workspaceId, name) {
|
|
5743
6285
|
return `trn:v1:workspace:${workspaceId}:workflow:${name}`;
|
|
@@ -5767,13 +6309,6 @@ async function planWorkflow(client, workspaceId, appName, workflows) {
|
|
|
5767
6309
|
}));
|
|
5768
6310
|
const allScripts = await loadWorkflowScripts();
|
|
5769
6311
|
for (const workflow of Object.values(workflows)) {
|
|
5770
|
-
const requiredJobNames = collectJobNamesFromWorkflow(workflow);
|
|
5771
|
-
const scripts = /* @__PURE__ */ new Map();
|
|
5772
|
-
for (const jobName of requiredJobNames) {
|
|
5773
|
-
const script = allScripts.get(jobName);
|
|
5774
|
-
if (script) scripts.set(jobName, script);
|
|
5775
|
-
else console.warn(`Warning: Script for job "${jobName}" not found in workflow "${workflow.name}"`);
|
|
5776
|
-
}
|
|
5777
6312
|
const existing = existingWorkflows[workflow.name];
|
|
5778
6313
|
const metaRequest = await buildMetaRequest(trn(workspaceId, workflow.name), appName);
|
|
5779
6314
|
if (existing) {
|
|
@@ -5790,7 +6325,7 @@ async function planWorkflow(client, workspaceId, appName, workflows) {
|
|
|
5790
6325
|
name: workflow.name,
|
|
5791
6326
|
workspaceId,
|
|
5792
6327
|
workflow,
|
|
5793
|
-
scripts,
|
|
6328
|
+
scripts: allScripts,
|
|
5794
6329
|
metaRequest
|
|
5795
6330
|
});
|
|
5796
6331
|
delete existingWorkflows[workflow.name];
|
|
@@ -5798,7 +6333,7 @@ async function planWorkflow(client, workspaceId, appName, workflows) {
|
|
|
5798
6333
|
name: workflow.name,
|
|
5799
6334
|
workspaceId,
|
|
5800
6335
|
workflow,
|
|
5801
|
-
scripts,
|
|
6336
|
+
scripts: allScripts,
|
|
5802
6337
|
metaRequest
|
|
5803
6338
|
});
|
|
5804
6339
|
}
|
|
@@ -5824,7 +6359,7 @@ async function loadWorkflowScripts() {
|
|
|
5824
6359
|
const jobsDir = path.join(getDistDir(), "workflow-jobs");
|
|
5825
6360
|
if (!fs.existsSync(jobsDir)) return scripts;
|
|
5826
6361
|
const files = fs.readdirSync(jobsDir);
|
|
5827
|
-
for (const file of files) if (
|
|
6362
|
+
for (const file of files) if (/^[^.]+\.js$/.test(file)) {
|
|
5828
6363
|
const jobName = file.replace(/\.js$/, "");
|
|
5829
6364
|
const scriptPath = path.join(jobsDir, file);
|
|
5830
6365
|
const script = fs.readFileSync(scriptPath, "utf-8");
|
|
@@ -5844,9 +6379,13 @@ async function apply(options) {
|
|
|
5844
6379
|
const application = defineApplication(config);
|
|
5845
6380
|
let workflowResult;
|
|
5846
6381
|
if (application.workflowConfig) workflowResult = await loadAndCollectJobs(application.workflowConfig);
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
if (
|
|
6382
|
+
const triggerContext = await buildTriggerContext(application.workflowConfig);
|
|
6383
|
+
for (const app$1 of application.applications) for (const pipeline$1 of app$1.resolverServices) await buildPipeline(pipeline$1.namespace, pipeline$1.config, triggerContext);
|
|
6384
|
+
if (application.executorService) await buildExecutor(application.executorService.config, triggerContext);
|
|
6385
|
+
if (workflowResult && workflowResult.jobs.length > 0) {
|
|
6386
|
+
const mainJobNames = workflowResult.workflowSources.map((ws) => ws.workflow.mainJob.name);
|
|
6387
|
+
await buildWorkflow(workflowResult.jobs, mainJobNames, application.env, triggerContext);
|
|
6388
|
+
}
|
|
5850
6389
|
if (buildOnly) return;
|
|
5851
6390
|
const accessToken = await loadAccessToken({
|
|
5852
6391
|
useProfile: true,
|
|
@@ -5945,14 +6484,14 @@ async function apply(options) {
|
|
|
5945
6484
|
await applyTailorDB(client, tailorDB, "delete");
|
|
5946
6485
|
console.log("Successfully applied changes.");
|
|
5947
6486
|
}
|
|
5948
|
-
async function buildPipeline(namespace, config) {
|
|
5949
|
-
await bundleResolvers(namespace, config);
|
|
6487
|
+
async function buildPipeline(namespace, config, triggerContext) {
|
|
6488
|
+
await bundleResolvers(namespace, config, triggerContext);
|
|
5950
6489
|
}
|
|
5951
|
-
async function buildExecutor(config) {
|
|
5952
|
-
await bundleExecutors(config);
|
|
6490
|
+
async function buildExecutor(config, triggerContext) {
|
|
6491
|
+
await bundleExecutors(config, triggerContext);
|
|
5953
6492
|
}
|
|
5954
|
-
async function buildWorkflow(collectedJobs) {
|
|
5955
|
-
await bundleWorkflowJobs(collectedJobs);
|
|
6493
|
+
async function buildWorkflow(collectedJobs, mainJobNames, env, triggerContext) {
|
|
6494
|
+
await bundleWorkflowJobs(collectedJobs, mainJobNames, env, triggerContext);
|
|
5956
6495
|
}
|
|
5957
6496
|
const applyCommand = defineCommand({
|
|
5958
6497
|
meta: {
|
|
@@ -7384,4 +7923,4 @@ const listCommand = defineCommand({
|
|
|
7384
7923
|
|
|
7385
7924
|
//#endregion
|
|
7386
7925
|
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 };
|
|
7387
|
-
//# sourceMappingURL=list-
|
|
7926
|
+
//# sourceMappingURL=list-B8Uv3SPW.mjs.map
|