@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.
- package/CHANGELOG.md +29 -0
- package/dist/cli/api.d.mts +1 -1
- package/dist/cli/api.mjs +2 -2
- package/dist/cli/index.mjs +2 -2
- package/dist/configure/index.d.mts +3 -3
- package/dist/configure/index.mjs +8 -3
- package/dist/configure/index.mjs.map +1 -1
- package/dist/{index-BbM-sCHw.d.mts → index-DBWm2TOg.d.mts} +9 -3
- package/dist/{job-vYIg6hFf.mjs → job-BGBMNqRW.mjs} +47 -6
- package/dist/job-BGBMNqRW.mjs.map +1 -0
- package/dist/{list-D-R1mEOM.mjs → list-CCYkqZyi.mjs} +828 -316
- package/dist/list-CCYkqZyi.mjs.map +1 -0
- package/dist/{types-JFLKYNHP.d.mts → types-CvxHveYR.d.mts} +61 -32
- package/dist/utils/test/index.d.mts +2 -2
- package/package.json +4 -4
- package/dist/job-vYIg6hFf.mjs.map +0 -1
- package/dist/list-D-R1mEOM.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-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
|
-
|
|
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"),
|
|
@@ -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/
|
|
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
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
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)
|
|
1813
|
+
if (deps) for (const dep of deps) collectDeps(dep, collected);
|
|
1327
1814
|
}
|
|
1328
|
-
for (const mainJobName of mainJobNames)
|
|
1329
|
-
|
|
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
|
-
|
|
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.
|
|
3941
|
-
secretKey: idpConfig.spCertBase64.
|
|
4437
|
+
vaultName: idpConfig.spCertBase64.vaultName,
|
|
4438
|
+
secretKey: idpConfig.spCertBase64.secretKey
|
|
3942
4439
|
} },
|
|
3943
4440
|
...idpConfig.spKeyBase64 && { spKeyBase64: {
|
|
3944
|
-
vaultName: idpConfig.spKeyBase64.
|
|
3945
|
-
secretKey: idpConfig.spKeyBase64.
|
|
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.
|
|
3959
|
-
secretKey: idpConfig.clientSecret.
|
|
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?.
|
|
4396
|
-
secretKey: scimConfig.authorization.bearerSecret?.
|
|
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.
|
|
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.
|
|
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:
|
|
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:
|
|
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
|
-
*
|
|
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(
|
|
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
|
-
|
|
5909
|
-
|
|
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
|
-
|
|
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-
|
|
7963
|
+
//# sourceMappingURL=list-CCYkqZyi.mjs.map
|