@workglow/task-graph 0.1.1 → 0.2.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/dist/browser.js +899 -187
- package/dist/browser.js.map +40 -32
- package/dist/bun.js +899 -187
- package/dist/bun.js.map +40 -32
- package/dist/common.d.ts +2 -0
- package/dist/common.d.ts.map +1 -1
- package/dist/node.js +899 -187
- package/dist/node.js.map +40 -32
- package/dist/storage/TaskGraphRepository.d.ts.map +1 -1
- package/dist/storage/TaskGraphTabularRepository.d.ts.map +1 -1
- package/dist/storage/TaskOutputRepository.d.ts.map +1 -1
- package/dist/storage/TaskOutputTabularRepository.d.ts +1 -1
- package/dist/storage/TaskOutputTabularRepository.d.ts.map +1 -1
- package/dist/task/ConditionalTask.d.ts +7 -2
- package/dist/task/ConditionalTask.d.ts.map +1 -1
- package/dist/task/EntitlementEnforcer.d.ts +55 -0
- package/dist/task/EntitlementEnforcer.d.ts.map +1 -0
- package/dist/task/EntitlementPolicy.d.ts +60 -0
- package/dist/task/EntitlementPolicy.d.ts.map +1 -0
- package/dist/task/EntitlementProfiles.d.ts +49 -0
- package/dist/task/EntitlementProfiles.d.ts.map +1 -0
- package/dist/task/EntitlementResolver.d.ts +50 -0
- package/dist/task/EntitlementResolver.d.ts.map +1 -0
- package/dist/task/FallbackTask.d.ts +31 -24
- package/dist/task/FallbackTask.d.ts.map +1 -1
- package/dist/task/FallbackTaskRunner.d.ts +2 -2
- package/dist/task/FallbackTaskRunner.d.ts.map +1 -1
- package/dist/task/GraphAsTask.d.ts +18 -6
- package/dist/task/GraphAsTask.d.ts.map +1 -1
- package/dist/task/GraphAsTaskRunner.d.ts +3 -2
- package/dist/task/GraphAsTaskRunner.d.ts.map +1 -1
- package/dist/task/ITask.d.ts +12 -1
- package/dist/task/ITask.d.ts.map +1 -1
- package/dist/task/InputCompactor.d.ts +37 -0
- package/dist/task/InputCompactor.d.ts.map +1 -0
- package/dist/task/InputResolver.d.ts +19 -1
- package/dist/task/InputResolver.d.ts.map +1 -1
- package/dist/task/IteratorTask.d.ts +9 -4
- package/dist/task/IteratorTask.d.ts.map +1 -1
- package/dist/task/IteratorTaskRunner.d.ts +1 -1
- package/dist/task/IteratorTaskRunner.d.ts.map +1 -1
- package/dist/task/MapTask.d.ts +8 -3
- package/dist/task/MapTask.d.ts.map +1 -1
- package/dist/task/ReduceTask.d.ts +9 -4
- package/dist/task/ReduceTask.d.ts.map +1 -1
- package/dist/task/StreamTypes.d.ts +6 -2
- package/dist/task/StreamTypes.d.ts.map +1 -1
- package/dist/task/Task.d.ts +37 -7
- package/dist/task/Task.d.ts.map +1 -1
- package/dist/task/TaskEntitlements.d.ts +134 -0
- package/dist/task/TaskEntitlements.d.ts.map +1 -0
- package/dist/task/TaskError.d.ts +7 -0
- package/dist/task/TaskError.d.ts.map +1 -1
- package/dist/task/TaskEvents.d.ts +3 -0
- package/dist/task/TaskEvents.d.ts.map +1 -1
- package/dist/task/TaskJSON.d.ts +18 -5
- package/dist/task/TaskJSON.d.ts.map +1 -1
- package/dist/task/TaskRegistry.d.ts +16 -3
- package/dist/task/TaskRegistry.d.ts.map +1 -1
- package/dist/task/TaskRunner.d.ts +5 -4
- package/dist/task/TaskRunner.d.ts.map +1 -1
- package/dist/task/TaskTypes.d.ts +10 -2
- package/dist/task/TaskTypes.d.ts.map +1 -1
- package/dist/task/WhileTask.d.ts +8 -4
- package/dist/task/WhileTask.d.ts.map +1 -1
- package/dist/task/WhileTaskRunner.d.ts +1 -1
- package/dist/task/WhileTaskRunner.d.ts.map +1 -1
- package/dist/task/index.d.ts +6 -0
- package/dist/task/index.d.ts.map +1 -1
- package/dist/task/iterationSchema.d.ts +2 -1
- package/dist/task/iterationSchema.d.ts.map +1 -1
- package/dist/task-graph/Dataflow.d.ts +1 -1
- package/dist/task-graph/Dataflow.d.ts.map +1 -1
- package/dist/task-graph/GraphEntitlementUtils.d.ts +30 -0
- package/dist/task-graph/GraphEntitlementUtils.d.ts.map +1 -0
- package/dist/task-graph/GraphFormatScanner.d.ts +41 -0
- package/dist/task-graph/GraphFormatScanner.d.ts.map +1 -0
- package/dist/task-graph/GraphToWorkflowCode.d.ts.map +1 -1
- package/dist/task-graph/TaskGraph.d.ts +23 -5
- package/dist/task-graph/TaskGraph.d.ts.map +1 -1
- package/dist/task-graph/TaskGraphEvents.d.ts +3 -0
- package/dist/task-graph/TaskGraphEvents.d.ts.map +1 -1
- package/dist/task-graph/TaskGraphRunner.d.ts +13 -1
- package/dist/task-graph/TaskGraphRunner.d.ts.map +1 -1
- package/dist/task-graph/Workflow.d.ts +32 -17
- package/dist/task-graph/Workflow.d.ts.map +1 -1
- package/package.json +12 -7
package/dist/node.js
CHANGED
|
@@ -38,6 +38,11 @@ var TaskConfigSchema = {
|
|
|
38
38
|
type: "object",
|
|
39
39
|
additionalProperties: true,
|
|
40
40
|
"x-ui-hidden": true
|
|
41
|
+
},
|
|
42
|
+
defaults: {
|
|
43
|
+
type: "object",
|
|
44
|
+
additionalProperties: true,
|
|
45
|
+
"x-ui-hidden": true
|
|
41
46
|
}
|
|
42
47
|
},
|
|
43
48
|
additionalProperties: false
|
|
@@ -256,6 +261,316 @@ class DataflowArrow extends Dataflow {
|
|
|
256
261
|
super(sourceTaskId, sourceTaskPortId, targetTaskId, targetTaskPortId);
|
|
257
262
|
}
|
|
258
263
|
}
|
|
264
|
+
// src/task/TaskEntitlements.ts
|
|
265
|
+
var Entitlements = {
|
|
266
|
+
NETWORK: "network",
|
|
267
|
+
NETWORK_HTTP: "network:http",
|
|
268
|
+
NETWORK_WEBSOCKET: "network:websocket",
|
|
269
|
+
NETWORK_PRIVATE: "network:private",
|
|
270
|
+
FILESYSTEM: "filesystem",
|
|
271
|
+
FILESYSTEM_READ: "filesystem:read",
|
|
272
|
+
FILESYSTEM_WRITE: "filesystem:write",
|
|
273
|
+
CODE_EXECUTION: "code-execution",
|
|
274
|
+
CODE_EXECUTION_JS: "code-execution:javascript",
|
|
275
|
+
CREDENTIAL: "credential",
|
|
276
|
+
AI: "ai",
|
|
277
|
+
AI_MODEL: "ai:model",
|
|
278
|
+
AI_INFERENCE: "ai:inference",
|
|
279
|
+
MCP: "mcp",
|
|
280
|
+
MCP_TOOL_CALL: "mcp:tool-call",
|
|
281
|
+
MCP_RESOURCE_READ: "mcp:resource-read",
|
|
282
|
+
MCP_PROMPT_GET: "mcp:prompt-get",
|
|
283
|
+
MCP_STDIO: "mcp:stdio",
|
|
284
|
+
STORAGE: "storage",
|
|
285
|
+
STORAGE_READ: "storage:read",
|
|
286
|
+
STORAGE_WRITE: "storage:write"
|
|
287
|
+
};
|
|
288
|
+
var EMPTY_ENTITLEMENTS = Object.freeze({
|
|
289
|
+
entitlements: Object.freeze([])
|
|
290
|
+
});
|
|
291
|
+
function entitlementCovers(granted, required) {
|
|
292
|
+
return required === granted || required.startsWith(granted + ":");
|
|
293
|
+
}
|
|
294
|
+
function resourcePatternMatches(grantPattern, requiredResource) {
|
|
295
|
+
if (grantPattern === requiredResource)
|
|
296
|
+
return true;
|
|
297
|
+
const starIdx = grantPattern.indexOf("*");
|
|
298
|
+
if (starIdx === -1)
|
|
299
|
+
return false;
|
|
300
|
+
const prefix = grantPattern.slice(0, starIdx);
|
|
301
|
+
const suffix = grantPattern.slice(starIdx + 1);
|
|
302
|
+
if (!requiredResource.startsWith(prefix))
|
|
303
|
+
return false;
|
|
304
|
+
if (!requiredResource.endsWith(suffix))
|
|
305
|
+
return false;
|
|
306
|
+
return requiredResource.length >= prefix.length + suffix.length;
|
|
307
|
+
}
|
|
308
|
+
function grantCoversResources(grant, required) {
|
|
309
|
+
if (grant.resources === undefined)
|
|
310
|
+
return true;
|
|
311
|
+
if (required.resources === undefined)
|
|
312
|
+
return false;
|
|
313
|
+
return required.resources.every((req) => grant.resources.some((pat) => resourcePatternMatches(pat, req)));
|
|
314
|
+
}
|
|
315
|
+
function mergeEntitlements(a, b) {
|
|
316
|
+
if (a.entitlements.length === 0)
|
|
317
|
+
return b;
|
|
318
|
+
if (b.entitlements.length === 0)
|
|
319
|
+
return a;
|
|
320
|
+
const merged = new Map;
|
|
321
|
+
for (const entitlement of a.entitlements) {
|
|
322
|
+
merged.set(entitlement.id, entitlement);
|
|
323
|
+
}
|
|
324
|
+
for (const entitlement of b.entitlements) {
|
|
325
|
+
const existing = merged.get(entitlement.id);
|
|
326
|
+
if (existing) {
|
|
327
|
+
merged.set(entitlement.id, mergeEntitlementPair(existing, entitlement));
|
|
328
|
+
} else {
|
|
329
|
+
merged.set(entitlement.id, entitlement);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return { entitlements: Array.from(merged.values()) };
|
|
333
|
+
}
|
|
334
|
+
function mergeEntitlementPair(a, b) {
|
|
335
|
+
const optional = (a.optional ?? false) && (b.optional ?? false) ? true : undefined;
|
|
336
|
+
const reason = a.reason ?? b.reason;
|
|
337
|
+
const resources = mergeResources(a.resources, b.resources);
|
|
338
|
+
const result = {
|
|
339
|
+
id: a.id,
|
|
340
|
+
...reason !== undefined && { reason },
|
|
341
|
+
...optional === true && { optional: true },
|
|
342
|
+
...resources !== undefined && { resources }
|
|
343
|
+
};
|
|
344
|
+
return result;
|
|
345
|
+
}
|
|
346
|
+
function mergeResources(a, b) {
|
|
347
|
+
if (a === undefined || b === undefined)
|
|
348
|
+
return;
|
|
349
|
+
const set = new Set([...a, ...b]);
|
|
350
|
+
return Array.from(set);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// src/task-graph/GraphEntitlementUtils.ts
|
|
354
|
+
function computeGraphEntitlements(graph, options) {
|
|
355
|
+
const tasks = graph.getTasks();
|
|
356
|
+
if (tasks.length === 0)
|
|
357
|
+
return EMPTY_ENTITLEMENTS;
|
|
358
|
+
const trackOrigins = options?.trackOrigins ?? false;
|
|
359
|
+
const conditionalBranches = options?.conditionalBranches ?? "all";
|
|
360
|
+
const merged = new Map;
|
|
361
|
+
for (const task of tasks) {
|
|
362
|
+
if (conditionalBranches === "active" && task.status !== undefined) {
|
|
363
|
+
if (task.status === TaskStatus.DISABLED)
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
const taskEntitlements = task.entitlements();
|
|
367
|
+
for (const entitlement of taskEntitlements.entitlements) {
|
|
368
|
+
const existing = merged.get(entitlement.id);
|
|
369
|
+
if (existing) {
|
|
370
|
+
existing.entitlement = mergeEntitlementPair(existing.entitlement, entitlement);
|
|
371
|
+
if (trackOrigins) {
|
|
372
|
+
existing.sourceTaskIds.push(task.id);
|
|
373
|
+
}
|
|
374
|
+
} else {
|
|
375
|
+
merged.set(entitlement.id, {
|
|
376
|
+
entitlement,
|
|
377
|
+
sourceTaskIds: trackOrigins ? [task.id] : []
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (merged.size === 0)
|
|
383
|
+
return EMPTY_ENTITLEMENTS;
|
|
384
|
+
if (trackOrigins) {
|
|
385
|
+
const entitlements = [];
|
|
386
|
+
for (const { entitlement, sourceTaskIds } of merged.values()) {
|
|
387
|
+
entitlements.push({ ...entitlement, sourceTaskIds });
|
|
388
|
+
}
|
|
389
|
+
return { entitlements };
|
|
390
|
+
}
|
|
391
|
+
return { entitlements: Array.from(merged.values()).map((e) => e.entitlement) };
|
|
392
|
+
}
|
|
393
|
+
// src/task/InputResolver.ts
|
|
394
|
+
import { getInputResolvers } from "@workglow/util";
|
|
395
|
+
function getSchemaFormat(schema, visited = new WeakSet) {
|
|
396
|
+
if (typeof schema !== "object" || schema === null)
|
|
397
|
+
return;
|
|
398
|
+
if (visited.has(schema))
|
|
399
|
+
return;
|
|
400
|
+
visited.add(schema);
|
|
401
|
+
const s = schema;
|
|
402
|
+
if (typeof s.format === "string")
|
|
403
|
+
return s.format;
|
|
404
|
+
const variants = s.oneOf ?? s.anyOf;
|
|
405
|
+
if (Array.isArray(variants)) {
|
|
406
|
+
for (const variant of variants) {
|
|
407
|
+
if (typeof variant === "object" && variant !== null) {
|
|
408
|
+
const v = variant;
|
|
409
|
+
if (typeof v.format === "string")
|
|
410
|
+
return v.format;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
const allOf = s.allOf;
|
|
415
|
+
if (Array.isArray(allOf)) {
|
|
416
|
+
for (const sub of allOf) {
|
|
417
|
+
const fmt = getSchemaFormat(sub, visited);
|
|
418
|
+
if (fmt !== undefined)
|
|
419
|
+
return fmt;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
function getObjectSchema(schema, visited = new WeakSet) {
|
|
425
|
+
if (typeof schema !== "object" || schema === null)
|
|
426
|
+
return;
|
|
427
|
+
if (visited.has(schema))
|
|
428
|
+
return;
|
|
429
|
+
visited.add(schema);
|
|
430
|
+
const s = schema;
|
|
431
|
+
if (s.type === "object" && s.properties && typeof s.properties === "object") {
|
|
432
|
+
return s;
|
|
433
|
+
}
|
|
434
|
+
const variants = s.oneOf ?? s.anyOf;
|
|
435
|
+
if (Array.isArray(variants)) {
|
|
436
|
+
for (const variant of variants) {
|
|
437
|
+
if (typeof variant === "object" && variant !== null) {
|
|
438
|
+
const v = variant;
|
|
439
|
+
if (v.type === "object" && v.properties && typeof v.properties === "object") {
|
|
440
|
+
return v;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
const allOf = s.allOf;
|
|
446
|
+
if (Array.isArray(allOf)) {
|
|
447
|
+
for (const sub of allOf) {
|
|
448
|
+
const result = getObjectSchema(sub, visited);
|
|
449
|
+
if (result !== undefined)
|
|
450
|
+
return result;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
function getFormatPrefix(format) {
|
|
456
|
+
const colonIndex = format.indexOf(":");
|
|
457
|
+
return colonIndex >= 0 ? format.substring(0, colonIndex) : format;
|
|
458
|
+
}
|
|
459
|
+
function schemaHasFormatAnnotations(schema) {
|
|
460
|
+
if (typeof schema === "boolean")
|
|
461
|
+
return false;
|
|
462
|
+
const properties = schema.properties;
|
|
463
|
+
if (!properties || typeof properties !== "object")
|
|
464
|
+
return false;
|
|
465
|
+
for (const propSchema of Object.values(properties)) {
|
|
466
|
+
if (getSchemaFormat(propSchema) !== undefined)
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
async function resolveSchemaInputs(input, schema, config, visited = new Set) {
|
|
472
|
+
if (typeof schema === "boolean")
|
|
473
|
+
return input;
|
|
474
|
+
const properties = schema.properties;
|
|
475
|
+
if (!properties || typeof properties !== "object")
|
|
476
|
+
return input;
|
|
477
|
+
const resolvers = getInputResolvers();
|
|
478
|
+
const resolved = { ...input };
|
|
479
|
+
for (const [key, propSchema] of Object.entries(properties)) {
|
|
480
|
+
let value = resolved[key];
|
|
481
|
+
const format = getSchemaFormat(propSchema);
|
|
482
|
+
if (format) {
|
|
483
|
+
let resolver = resolvers.get(format);
|
|
484
|
+
if (!resolver) {
|
|
485
|
+
const prefix = getFormatPrefix(format);
|
|
486
|
+
resolver = resolvers.get(prefix);
|
|
487
|
+
}
|
|
488
|
+
if (resolver) {
|
|
489
|
+
if (typeof value === "string") {
|
|
490
|
+
value = await resolver(value, format, config.registry);
|
|
491
|
+
resolved[key] = value;
|
|
492
|
+
} else if (Array.isArray(value) && value.some((item) => typeof item === "string")) {
|
|
493
|
+
const results = await Promise.all(value.map((item) => typeof item === "string" ? resolver(item, format, config.registry) : item));
|
|
494
|
+
value = results.filter((result) => result !== undefined);
|
|
495
|
+
resolved[key] = value;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if (value !== null && value !== undefined && typeof value === "object" && !Array.isArray(value)) {
|
|
500
|
+
const objectSchema = getObjectSchema(propSchema);
|
|
501
|
+
if (objectSchema && !visited.has(objectSchema)) {
|
|
502
|
+
visited.add(objectSchema);
|
|
503
|
+
try {
|
|
504
|
+
resolved[key] = await resolveSchemaInputs(value, objectSchema, config, visited);
|
|
505
|
+
} finally {
|
|
506
|
+
visited.delete(objectSchema);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return resolved;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// src/task-graph/GraphFormatScanner.ts
|
|
515
|
+
function schemaHasFormat(schema, targetFormat) {
|
|
516
|
+
if (typeof schema !== "object" || schema === null)
|
|
517
|
+
return false;
|
|
518
|
+
const s = schema;
|
|
519
|
+
const properties = s.properties;
|
|
520
|
+
if (properties && typeof properties === "object") {
|
|
521
|
+
for (const propSchema of Object.values(properties)) {
|
|
522
|
+
const format = getSchemaFormat(propSchema);
|
|
523
|
+
if (format === targetFormat)
|
|
524
|
+
return true;
|
|
525
|
+
const objectSchema = getObjectSchema(propSchema);
|
|
526
|
+
if (objectSchema && schemaHasFormat(objectSchema, targetFormat))
|
|
527
|
+
return true;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
function scanGraphForFormat(graph, targetFormat) {
|
|
533
|
+
for (const task of graph.getTasks()) {
|
|
534
|
+
const inputSchema = task.inputSchema();
|
|
535
|
+
if (typeof inputSchema !== "boolean" && schemaHasFormat(inputSchema, targetFormat)) {
|
|
536
|
+
return true;
|
|
537
|
+
}
|
|
538
|
+
const configSchema = task.configSchema();
|
|
539
|
+
if (typeof configSchema !== "boolean" && schemaHasFormat(configSchema, targetFormat)) {
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
function scanGraphForCredentials(graph) {
|
|
546
|
+
const credentialFormats = new Set;
|
|
547
|
+
for (const task of graph.getTasks()) {
|
|
548
|
+
collectCredentialFormats(task.inputSchema(), credentialFormats);
|
|
549
|
+
collectCredentialFormats(task.configSchema(), credentialFormats);
|
|
550
|
+
}
|
|
551
|
+
return {
|
|
552
|
+
needsCredentials: credentialFormats.size > 0,
|
|
553
|
+
credentialFormats
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
function collectCredentialFormats(schema, formats) {
|
|
557
|
+
if (typeof schema === "boolean" || typeof schema !== "object" || schema === null)
|
|
558
|
+
return;
|
|
559
|
+
const s = schema;
|
|
560
|
+
const properties = s.properties;
|
|
561
|
+
if (!properties || typeof properties !== "object")
|
|
562
|
+
return;
|
|
563
|
+
for (const propSchema of Object.values(properties)) {
|
|
564
|
+
const format = getSchemaFormat(propSchema);
|
|
565
|
+
if (format === "credential") {
|
|
566
|
+
formats.add(format);
|
|
567
|
+
}
|
|
568
|
+
const objectSchema = getObjectSchema(propSchema);
|
|
569
|
+
if (objectSchema) {
|
|
570
|
+
collectCredentialFormats(objectSchema, formats);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
259
574
|
// src/task-graph/GraphSchemaUtils.ts
|
|
260
575
|
import { uuid4 } from "@workglow/util";
|
|
261
576
|
function calculateNodeDepths(graph) {
|
|
@@ -605,8 +920,8 @@ function addBoundaryNodesToDependencyJson(items, graph) {
|
|
|
605
920
|
return [...prependItems, ...items, ...appendItems];
|
|
606
921
|
}
|
|
607
922
|
// src/task-graph/TaskGraph.ts
|
|
608
|
-
import { DirectedAcyclicGraph } from "@workglow/util/graph";
|
|
609
923
|
import { EventEmitter as EventEmitter4, uuid4 as uuid44 } from "@workglow/util";
|
|
924
|
+
import { DirectedAcyclicGraph } from "@workglow/util/graph";
|
|
610
925
|
|
|
611
926
|
// src/task/GraphAsTask.ts
|
|
612
927
|
import { getLogger as getLogger4 } from "@workglow/util";
|
|
@@ -724,8 +1039,8 @@ function getNestedValue(obj, path) {
|
|
|
724
1039
|
}
|
|
725
1040
|
|
|
726
1041
|
// src/task/Task.ts
|
|
727
|
-
import { compileSchema } from "@workglow/util/schema";
|
|
728
1042
|
import { deepEqual, EventEmitter as EventEmitter3, uuid4 as uuid42 } from "@workglow/util";
|
|
1043
|
+
import { compileSchema } from "@workglow/util/schema";
|
|
729
1044
|
|
|
730
1045
|
// src/task/TaskError.ts
|
|
731
1046
|
import { BaseError } from "@workglow/util";
|
|
@@ -805,6 +1120,13 @@ class TaskInvalidInputError extends TaskError {
|
|
|
805
1120
|
}
|
|
806
1121
|
}
|
|
807
1122
|
|
|
1123
|
+
class TaskEntitlementError extends TaskError {
|
|
1124
|
+
static type = "TaskEntitlementError";
|
|
1125
|
+
constructor(message = "Required entitlements denied") {
|
|
1126
|
+
super(message);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
|
|
808
1130
|
class TaskSerializationError extends TaskError {
|
|
809
1131
|
static type = "TaskSerializationError";
|
|
810
1132
|
constructor(taskType) {
|
|
@@ -820,100 +1142,6 @@ import {
|
|
|
820
1142
|
SpanStatusCode
|
|
821
1143
|
} from "@workglow/util";
|
|
822
1144
|
|
|
823
|
-
// src/task/InputResolver.ts
|
|
824
|
-
import { getInputResolvers } from "@workglow/util";
|
|
825
|
-
function getSchemaFormat(schema) {
|
|
826
|
-
if (typeof schema !== "object" || schema === null)
|
|
827
|
-
return;
|
|
828
|
-
const s = schema;
|
|
829
|
-
if (typeof s.format === "string")
|
|
830
|
-
return s.format;
|
|
831
|
-
const variants = s.oneOf ?? s.anyOf;
|
|
832
|
-
if (Array.isArray(variants)) {
|
|
833
|
-
for (const variant of variants) {
|
|
834
|
-
if (typeof variant === "object" && variant !== null) {
|
|
835
|
-
const v = variant;
|
|
836
|
-
if (typeof v.format === "string")
|
|
837
|
-
return v.format;
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
return;
|
|
842
|
-
}
|
|
843
|
-
function getObjectSchema(schema) {
|
|
844
|
-
if (typeof schema !== "object" || schema === null)
|
|
845
|
-
return;
|
|
846
|
-
const s = schema;
|
|
847
|
-
if (s.type === "object" && s.properties && typeof s.properties === "object") {
|
|
848
|
-
return s;
|
|
849
|
-
}
|
|
850
|
-
const variants = s.oneOf ?? s.anyOf;
|
|
851
|
-
if (Array.isArray(variants)) {
|
|
852
|
-
for (const variant of variants) {
|
|
853
|
-
if (typeof variant === "object" && variant !== null) {
|
|
854
|
-
const v = variant;
|
|
855
|
-
if (v.type === "object" && v.properties && typeof v.properties === "object") {
|
|
856
|
-
return v;
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
return;
|
|
862
|
-
}
|
|
863
|
-
function getFormatPrefix(format) {
|
|
864
|
-
const colonIndex = format.indexOf(":");
|
|
865
|
-
return colonIndex >= 0 ? format.substring(0, colonIndex) : format;
|
|
866
|
-
}
|
|
867
|
-
function schemaHasFormatAnnotations(schema) {
|
|
868
|
-
if (typeof schema === "boolean")
|
|
869
|
-
return false;
|
|
870
|
-
const properties = schema.properties;
|
|
871
|
-
if (!properties || typeof properties !== "object")
|
|
872
|
-
return false;
|
|
873
|
-
for (const propSchema of Object.values(properties)) {
|
|
874
|
-
if (getSchemaFormat(propSchema) !== undefined)
|
|
875
|
-
return true;
|
|
876
|
-
}
|
|
877
|
-
return false;
|
|
878
|
-
}
|
|
879
|
-
async function resolveSchemaInputs(input, schema, config) {
|
|
880
|
-
if (typeof schema === "boolean")
|
|
881
|
-
return input;
|
|
882
|
-
const properties = schema.properties;
|
|
883
|
-
if (!properties || typeof properties !== "object")
|
|
884
|
-
return input;
|
|
885
|
-
const resolvers = getInputResolvers();
|
|
886
|
-
const resolved = { ...input };
|
|
887
|
-
for (const [key, propSchema] of Object.entries(properties)) {
|
|
888
|
-
let value = resolved[key];
|
|
889
|
-
const format = getSchemaFormat(propSchema);
|
|
890
|
-
if (format) {
|
|
891
|
-
let resolver = resolvers.get(format);
|
|
892
|
-
if (!resolver) {
|
|
893
|
-
const prefix = getFormatPrefix(format);
|
|
894
|
-
resolver = resolvers.get(prefix);
|
|
895
|
-
}
|
|
896
|
-
if (resolver) {
|
|
897
|
-
if (typeof value === "string") {
|
|
898
|
-
value = await resolver(value, format, config.registry);
|
|
899
|
-
resolved[key] = value;
|
|
900
|
-
} else if (Array.isArray(value) && value.some((item) => typeof item === "string")) {
|
|
901
|
-
const results = await Promise.all(value.map((item) => typeof item === "string" ? resolver(item, format, config.registry) : item));
|
|
902
|
-
value = results.filter((result) => result !== undefined);
|
|
903
|
-
resolved[key] = value;
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
if (value !== null && value !== undefined && typeof value === "object" && !Array.isArray(value)) {
|
|
908
|
-
const objectSchema = getObjectSchema(propSchema);
|
|
909
|
-
if (objectSchema) {
|
|
910
|
-
resolved[key] = await resolveSchemaInputs(value, objectSchema, config);
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
return resolved;
|
|
915
|
-
}
|
|
916
|
-
|
|
917
1145
|
// src/task/StreamTypes.ts
|
|
918
1146
|
function getPortStreamMode(schema, portId) {
|
|
919
1147
|
if (typeof schema === "boolean")
|
|
@@ -1205,11 +1433,29 @@ class TaskRunner {
|
|
|
1205
1433
|
}
|
|
1206
1434
|
case "object-delta": {
|
|
1207
1435
|
if (accumulatedObjects) {
|
|
1208
|
-
accumulatedObjects.
|
|
1436
|
+
const existing = accumulatedObjects.get(event.port);
|
|
1437
|
+
if (Array.isArray(event.objectDelta)) {
|
|
1438
|
+
const arr = Array.isArray(existing) ? [...existing] : [];
|
|
1439
|
+
for (const item of event.objectDelta) {
|
|
1440
|
+
const itemObj = item;
|
|
1441
|
+
if (itemObj && typeof itemObj === "object" && "id" in itemObj) {
|
|
1442
|
+
const idx = arr.findIndex((e) => e.id === itemObj.id);
|
|
1443
|
+
if (idx >= 0)
|
|
1444
|
+
arr[idx] = item;
|
|
1445
|
+
else
|
|
1446
|
+
arr.push(item);
|
|
1447
|
+
} else {
|
|
1448
|
+
arr.push(item);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
accumulatedObjects.set(event.port, arr);
|
|
1452
|
+
} else {
|
|
1453
|
+
accumulatedObjects.set(event.port, event.objectDelta);
|
|
1454
|
+
}
|
|
1209
1455
|
}
|
|
1210
1456
|
this.task.runOutputData = {
|
|
1211
1457
|
...this.task.runOutputData,
|
|
1212
|
-
[event.port]: event.objectDelta
|
|
1458
|
+
[event.port]: accumulatedObjects?.get(event.port) ?? event.objectDelta
|
|
1213
1459
|
};
|
|
1214
1460
|
this.task.emit("stream_chunk", event);
|
|
1215
1461
|
const progress = Math.min(99, Math.round(100 * (1 - Math.exp(-0.05 * chunkCount))));
|
|
@@ -1270,11 +1516,6 @@ class TaskRunner {
|
|
|
1270
1516
|
this.abortController.signal.addEventListener("abort", () => {
|
|
1271
1517
|
this.handleAbort();
|
|
1272
1518
|
});
|
|
1273
|
-
if (config.signal?.aborted) {
|
|
1274
|
-
this.abortController.abort();
|
|
1275
|
-
} else if (config.signal) {
|
|
1276
|
-
config.signal.addEventListener("abort", () => this.abortController.abort(), { once: true });
|
|
1277
|
-
}
|
|
1278
1519
|
const cache = config.outputCache ?? this.task.runConfig?.outputCache;
|
|
1279
1520
|
if (cache === true) {
|
|
1280
1521
|
let instance = globalServiceRegistry.get(TASK_OUTPUT_REPOSITORY);
|
|
@@ -1285,6 +1526,21 @@ class TaskRunner {
|
|
|
1285
1526
|
this.outputCache = cache;
|
|
1286
1527
|
}
|
|
1287
1528
|
this.shouldAccumulate = config.shouldAccumulate !== false;
|
|
1529
|
+
if (config.updateProgress) {
|
|
1530
|
+
this.updateProgress = config.updateProgress;
|
|
1531
|
+
}
|
|
1532
|
+
if (config.registry) {
|
|
1533
|
+
this.registry = config.registry;
|
|
1534
|
+
}
|
|
1535
|
+
if (config.signal) {
|
|
1536
|
+
const onAbort = () => this.abortController.abort();
|
|
1537
|
+
config.signal.addEventListener("abort", onAbort, { once: true });
|
|
1538
|
+
if (config.signal.aborted) {
|
|
1539
|
+
config.signal.removeEventListener("abort", onAbort);
|
|
1540
|
+
this.abortController.abort();
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1288
1544
|
const timeout = this.task.config.timeout;
|
|
1289
1545
|
if (timeout !== undefined && timeout > 0) {
|
|
1290
1546
|
this.pendingTimeoutError = new TaskTimeoutError(timeout);
|
|
@@ -1292,12 +1548,6 @@ class TaskRunner {
|
|
|
1292
1548
|
this.abort();
|
|
1293
1549
|
}, timeout);
|
|
1294
1550
|
}
|
|
1295
|
-
if (config.updateProgress) {
|
|
1296
|
-
this.updateProgress = config.updateProgress;
|
|
1297
|
-
}
|
|
1298
|
-
if (config.registry) {
|
|
1299
|
-
this.registry = config.registry;
|
|
1300
|
-
}
|
|
1301
1551
|
const telemetry = getTelemetryProvider();
|
|
1302
1552
|
if (telemetry.isEnabled) {
|
|
1303
1553
|
this.telemetrySpan = telemetry.startSpan("workglow.task.run", {
|
|
@@ -1434,6 +1684,11 @@ class Task {
|
|
|
1434
1684
|
static hasDynamicSchemas = false;
|
|
1435
1685
|
static passthroughInputsToOutputs = false;
|
|
1436
1686
|
static customizable = false;
|
|
1687
|
+
static isGraphOutput = false;
|
|
1688
|
+
static hasDynamicEntitlements = false;
|
|
1689
|
+
static entitlements() {
|
|
1690
|
+
return EMPTY_ENTITLEMENTS;
|
|
1691
|
+
}
|
|
1437
1692
|
static inputSchema() {
|
|
1438
1693
|
return {
|
|
1439
1694
|
type: "object",
|
|
@@ -1488,6 +1743,13 @@ class Task {
|
|
|
1488
1743
|
configSchema() {
|
|
1489
1744
|
return this.constructor.configSchema();
|
|
1490
1745
|
}
|
|
1746
|
+
entitlements() {
|
|
1747
|
+
return this.constructor.entitlements();
|
|
1748
|
+
}
|
|
1749
|
+
emitEntitlementChange(entitlements) {
|
|
1750
|
+
const final = entitlements ?? this.entitlements();
|
|
1751
|
+
this.emit("entitlementChange", final);
|
|
1752
|
+
}
|
|
1491
1753
|
get type() {
|
|
1492
1754
|
return this.constructor.type;
|
|
1493
1755
|
}
|
|
@@ -1525,15 +1787,16 @@ class Task {
|
|
|
1525
1787
|
return this._events;
|
|
1526
1788
|
}
|
|
1527
1789
|
_events;
|
|
1528
|
-
constructor(
|
|
1790
|
+
constructor(config = {}, runConfig = {}) {
|
|
1791
|
+
const { defaults: callerDefaultInputs, ...restConfig } = config;
|
|
1529
1792
|
const inputDefaults = this.getDefaultInputsFromStaticInputDefinitions();
|
|
1530
|
-
const mergedDefaults = Object.assign(inputDefaults, callerDefaultInputs);
|
|
1793
|
+
const mergedDefaults = Object.assign(inputDefaults, callerDefaultInputs ?? {});
|
|
1531
1794
|
this.defaults = this.stripSymbols(mergedDefaults);
|
|
1532
1795
|
this.resetInputData();
|
|
1533
1796
|
const title = this.constructor.title || undefined;
|
|
1534
1797
|
const baseConfig = Object.assign({
|
|
1535
1798
|
...title ? { title } : {}
|
|
1536
|
-
},
|
|
1799
|
+
}, restConfig);
|
|
1537
1800
|
if (baseConfig.id === undefined) {
|
|
1538
1801
|
baseConfig.id = uuid42();
|
|
1539
1802
|
}
|
|
@@ -1880,6 +2143,10 @@ class Task {
|
|
|
1880
2143
|
if (Object.keys(config).length > 0) {
|
|
1881
2144
|
base.config = config;
|
|
1882
2145
|
}
|
|
2146
|
+
const taskEntitlements = this.entitlements();
|
|
2147
|
+
if (taskEntitlements.entitlements.length > 0) {
|
|
2148
|
+
base.entitlements = taskEntitlements;
|
|
2149
|
+
}
|
|
1883
2150
|
return this.stripSymbols(base);
|
|
1884
2151
|
}
|
|
1885
2152
|
toDependencyJSON(options) {
|
|
@@ -2009,7 +2276,7 @@ class ConditionalTask extends Task {
|
|
|
2009
2276
|
}
|
|
2010
2277
|
}
|
|
2011
2278
|
} catch (error) {
|
|
2012
|
-
getLogger2().
|
|
2279
|
+
getLogger2().error(`Condition evaluation failed for branch "${branch.id}":`, { error });
|
|
2013
2280
|
}
|
|
2014
2281
|
}
|
|
2015
2282
|
if (this.activeBranches.size === 0 && defaultBranch) {
|
|
@@ -2133,6 +2400,111 @@ class ConditionalTask extends Task {
|
|
|
2133
2400
|
}
|
|
2134
2401
|
}
|
|
2135
2402
|
|
|
2403
|
+
// src/task/EntitlementEnforcer.ts
|
|
2404
|
+
import { createServiceToken as createServiceToken3 } from "@workglow/util";
|
|
2405
|
+
|
|
2406
|
+
// src/task/EntitlementPolicy.ts
|
|
2407
|
+
var EMPTY_POLICY = Object.freeze({
|
|
2408
|
+
deny: Object.freeze([]),
|
|
2409
|
+
grant: Object.freeze([]),
|
|
2410
|
+
ask: Object.freeze([])
|
|
2411
|
+
});
|
|
2412
|
+
function ruleCovers(rule, required) {
|
|
2413
|
+
if (!entitlementCovers(rule.id, required.id))
|
|
2414
|
+
return false;
|
|
2415
|
+
return grantCoversResources(rule, required);
|
|
2416
|
+
}
|
|
2417
|
+
function evaluatePolicy(policy, required) {
|
|
2418
|
+
const results = [];
|
|
2419
|
+
for (const entitlement of required.entitlements) {
|
|
2420
|
+
if (entitlement.optional)
|
|
2421
|
+
continue;
|
|
2422
|
+
const denyMatch = policy.deny.find((rule) => ruleCovers(rule, entitlement));
|
|
2423
|
+
if (denyMatch) {
|
|
2424
|
+
results.push({ verdict: "denied", entitlement, matchedRule: denyMatch });
|
|
2425
|
+
continue;
|
|
2426
|
+
}
|
|
2427
|
+
const grantMatch = policy.grant.find((rule) => ruleCovers(rule, entitlement));
|
|
2428
|
+
if (grantMatch) {
|
|
2429
|
+
results.push({ verdict: "granted", entitlement, matchedRule: grantMatch });
|
|
2430
|
+
continue;
|
|
2431
|
+
}
|
|
2432
|
+
const askMatch = policy.ask.find((rule) => ruleCovers(rule, entitlement));
|
|
2433
|
+
if (askMatch) {
|
|
2434
|
+
results.push({ verdict: "ask", entitlement, matchedRule: askMatch });
|
|
2435
|
+
continue;
|
|
2436
|
+
}
|
|
2437
|
+
results.push({ verdict: "denied", entitlement });
|
|
2438
|
+
}
|
|
2439
|
+
return results;
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
// src/task/EntitlementResolver.ts
|
|
2443
|
+
import { createServiceToken as createServiceToken2 } from "@workglow/util";
|
|
2444
|
+
var PERMISSIVE_RESOLVER = {
|
|
2445
|
+
lookup: () => "grant",
|
|
2446
|
+
prompt: async () => "grant",
|
|
2447
|
+
save: () => {}
|
|
2448
|
+
};
|
|
2449
|
+
var DENY_ALL_RESOLVER = {
|
|
2450
|
+
lookup: () => "deny",
|
|
2451
|
+
prompt: async () => "deny",
|
|
2452
|
+
save: () => {}
|
|
2453
|
+
};
|
|
2454
|
+
var ENTITLEMENT_RESOLVER = createServiceToken2("workglow.entitlementResolver");
|
|
2455
|
+
|
|
2456
|
+
// src/task/EntitlementEnforcer.ts
|
|
2457
|
+
var PERMISSIVE_ENFORCER = {
|
|
2458
|
+
checkAll: async () => [],
|
|
2459
|
+
checkTask: async () => []
|
|
2460
|
+
};
|
|
2461
|
+
function createPolicyEnforcer(policy, resolver = PERMISSIVE_RESOLVER) {
|
|
2462
|
+
async function resolveAsks(required, taskType, taskId) {
|
|
2463
|
+
const results = evaluatePolicy(policy, required);
|
|
2464
|
+
const denied = [];
|
|
2465
|
+
for (const result of results) {
|
|
2466
|
+
if (result.verdict === "denied") {
|
|
2467
|
+
denied.push(result.entitlement);
|
|
2468
|
+
} else if (result.verdict === "ask") {
|
|
2469
|
+
const request = {
|
|
2470
|
+
entitlement: result.entitlement,
|
|
2471
|
+
taskType: taskType ?? "unknown",
|
|
2472
|
+
taskId: taskId ?? "unknown"
|
|
2473
|
+
};
|
|
2474
|
+
const saved = resolver.lookup(request);
|
|
2475
|
+
if (saved !== undefined) {
|
|
2476
|
+
if (saved === "deny") {
|
|
2477
|
+
denied.push(result.entitlement);
|
|
2478
|
+
}
|
|
2479
|
+
continue;
|
|
2480
|
+
}
|
|
2481
|
+
const answer = await resolver.prompt(request);
|
|
2482
|
+
resolver.save(request, answer);
|
|
2483
|
+
if (answer === "deny") {
|
|
2484
|
+
denied.push(result.entitlement);
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
return denied;
|
|
2489
|
+
}
|
|
2490
|
+
return {
|
|
2491
|
+
async checkAll(required) {
|
|
2492
|
+
return resolveAsks(required);
|
|
2493
|
+
},
|
|
2494
|
+
async checkTask(task) {
|
|
2495
|
+
const entitlements = task.entitlements();
|
|
2496
|
+
return resolveAsks(entitlements, task.constructor.type, task.id);
|
|
2497
|
+
}
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2500
|
+
function createScopedEnforcer(grants) {
|
|
2501
|
+
return createPolicyEnforcer({ deny: [], grant: grants, ask: [] });
|
|
2502
|
+
}
|
|
2503
|
+
function createGrantListEnforcer(grants) {
|
|
2504
|
+
return createScopedEnforcer(grants.map((id) => ({ id })));
|
|
2505
|
+
}
|
|
2506
|
+
var ENTITLEMENT_ENFORCER = createServiceToken3("workglow.entitlementEnforcer");
|
|
2507
|
+
|
|
2136
2508
|
// src/task-graph/TaskGraphScheduler.ts
|
|
2137
2509
|
class TopologicalScheduler {
|
|
2138
2510
|
dag;
|
|
@@ -2301,6 +2673,7 @@ class TaskGraphRunner {
|
|
|
2301
2673
|
telemetrySpan;
|
|
2302
2674
|
graphTimeoutTimer;
|
|
2303
2675
|
pendingGraphTimeoutError;
|
|
2676
|
+
activeEnforcer;
|
|
2304
2677
|
constructor(graph, outputCache, processScheduler = new DependencyBasedScheduler(graph), reactiveScheduler = new TopologicalScheduler(graph)) {
|
|
2305
2678
|
this.processScheduler = processScheduler;
|
|
2306
2679
|
this.reactiveScheduler = reactiveScheduler;
|
|
@@ -2369,7 +2742,7 @@ class TaskGraphRunner {
|
|
|
2369
2742
|
throw new TaskAbortedError;
|
|
2370
2743
|
}
|
|
2371
2744
|
await this.handleComplete();
|
|
2372
|
-
return results;
|
|
2745
|
+
return this.filterLeafResults(results);
|
|
2373
2746
|
}
|
|
2374
2747
|
async runGraphReactive(input = {}, config) {
|
|
2375
2748
|
await this.handleStartReactive(config);
|
|
@@ -2393,7 +2766,7 @@ class TaskGraphRunner {
|
|
|
2393
2766
|
}
|
|
2394
2767
|
}
|
|
2395
2768
|
await this.handleCompleteReactive();
|
|
2396
|
-
return results;
|
|
2769
|
+
return this.filterLeafResults(results);
|
|
2397
2770
|
} catch (error) {
|
|
2398
2771
|
await this.handleErrorReactive();
|
|
2399
2772
|
throw error;
|
|
@@ -2425,6 +2798,15 @@ class TaskGraphRunner {
|
|
|
2425
2798
|
task.regenerateGraph();
|
|
2426
2799
|
}
|
|
2427
2800
|
}
|
|
2801
|
+
filterLeafResults(results) {
|
|
2802
|
+
if (results.length <= 1)
|
|
2803
|
+
return results;
|
|
2804
|
+
const graphOutputResults = results.filter((r) => {
|
|
2805
|
+
const task = this.graph.getTask(r.id);
|
|
2806
|
+
return task && task.constructor.isGraphOutput;
|
|
2807
|
+
});
|
|
2808
|
+
return graphOutputResults.length > 0 ? graphOutputResults : results;
|
|
2809
|
+
}
|
|
2428
2810
|
mergeExecuteOutputsToRunOutput(results, compoundMerge) {
|
|
2429
2811
|
if (compoundMerge === GRAPH_RESULT_ARRAY) {
|
|
2430
2812
|
return results;
|
|
@@ -2606,6 +2988,12 @@ class TaskGraphRunner {
|
|
|
2606
2988
|
}
|
|
2607
2989
|
await this.awaitStreamInputs(task);
|
|
2608
2990
|
this.copyInputFromEdgesToNode(task);
|
|
2991
|
+
if (this.activeEnforcer && task.constructor.hasDynamicEntitlements) {
|
|
2992
|
+
const denied = await this.activeEnforcer.checkTask(task);
|
|
2993
|
+
if (denied.length > 0) {
|
|
2994
|
+
throw new TaskEntitlementError(`Task ${task.constructor.type} denied entitlements: ${denied.map((e) => e.id).join(", ")}`);
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2609
2997
|
if (isStreamable) {
|
|
2610
2998
|
return this.runStreamingTask(task, input);
|
|
2611
2999
|
}
|
|
@@ -2775,12 +3163,6 @@ class TaskGraphRunner {
|
|
|
2775
3163
|
}
|
|
2776
3164
|
this.graph.outputCache = this.outputCache;
|
|
2777
3165
|
}
|
|
2778
|
-
if (config?.maxTasks !== undefined && config.maxTasks > 0) {
|
|
2779
|
-
const taskCount = this.graph.getTasks().length;
|
|
2780
|
-
if (taskCount > config.maxTasks) {
|
|
2781
|
-
throw new TaskConfigurationError(`Graph has ${taskCount} tasks, exceeding the limit of ${config.maxTasks}`);
|
|
2782
|
-
}
|
|
2783
|
-
}
|
|
2784
3166
|
if (this.running || this.reactiveRunning) {
|
|
2785
3167
|
throw new TaskConfigurationError("Graph is already running");
|
|
2786
3168
|
}
|
|
@@ -2796,13 +3178,16 @@ class TaskGraphRunner {
|
|
|
2796
3178
|
this.abortController?.abort();
|
|
2797
3179
|
}, config.timeout);
|
|
2798
3180
|
}
|
|
2799
|
-
if (config?.parentSignal
|
|
2800
|
-
|
|
2801
|
-
return;
|
|
2802
|
-
} else {
|
|
2803
|
-
config?.parentSignal?.addEventListener("abort", () => {
|
|
3181
|
+
if (config?.parentSignal) {
|
|
3182
|
+
const onParentAbort = () => {
|
|
2804
3183
|
this.abortController?.abort();
|
|
2805
|
-
}
|
|
3184
|
+
};
|
|
3185
|
+
config.parentSignal.addEventListener("abort", onParentAbort, { once: true });
|
|
3186
|
+
if (config.parentSignal.aborted) {
|
|
3187
|
+
config.parentSignal.removeEventListener("abort", onParentAbort);
|
|
3188
|
+
this.abortController.abort();
|
|
3189
|
+
return;
|
|
3190
|
+
}
|
|
2806
3191
|
}
|
|
2807
3192
|
this.runId = uuid43();
|
|
2808
3193
|
this.resetGraph(this.graph, this.runId);
|
|
@@ -2810,6 +3195,36 @@ class TaskGraphRunner {
|
|
|
2810
3195
|
this.inProgressTasks.clear();
|
|
2811
3196
|
this.inProgressFunctions.clear();
|
|
2812
3197
|
this.failedTaskErrors.clear();
|
|
3198
|
+
try {
|
|
3199
|
+
if (config?.maxTasks !== undefined && config.maxTasks > 0) {
|
|
3200
|
+
const taskCount = this.graph.getTasks().length;
|
|
3201
|
+
if (taskCount > config.maxTasks) {
|
|
3202
|
+
throw new TaskConfigurationError(`Graph has ${taskCount} tasks, exceeding the limit of ${config.maxTasks}`);
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
if (config?.enforceEntitlements) {
|
|
3206
|
+
if (!this.registry.has(ENTITLEMENT_ENFORCER)) {
|
|
3207
|
+
throw new TaskConfigurationError("enforceEntitlements is enabled but no IEntitlementEnforcer is registered. " + "Register an enforcer via ENTITLEMENT_ENFORCER before running the graph.");
|
|
3208
|
+
}
|
|
3209
|
+
const enforcer = this.registry.get(ENTITLEMENT_ENFORCER);
|
|
3210
|
+
const denied = await enforcer.checkAll(computeGraphEntitlements(this.graph));
|
|
3211
|
+
if (denied.length > 0) {
|
|
3212
|
+
throw new TaskEntitlementError(`Denied entitlements: ${denied.map((e) => e.id).join(", ")}`);
|
|
3213
|
+
}
|
|
3214
|
+
this.activeEnforcer = enforcer;
|
|
3215
|
+
} else {
|
|
3216
|
+
this.activeEnforcer = undefined;
|
|
3217
|
+
}
|
|
3218
|
+
} catch (err) {
|
|
3219
|
+
if (this.graphTimeoutTimer !== undefined) {
|
|
3220
|
+
clearTimeout(this.graphTimeoutTimer);
|
|
3221
|
+
this.graphTimeoutTimer = undefined;
|
|
3222
|
+
}
|
|
3223
|
+
this.abortController = undefined;
|
|
3224
|
+
this.activeEnforcer = undefined;
|
|
3225
|
+
this.running = false;
|
|
3226
|
+
throw err;
|
|
3227
|
+
}
|
|
2813
3228
|
const telemetry = getTelemetryProvider2();
|
|
2814
3229
|
if (telemetry.isEnabled) {
|
|
2815
3230
|
this.telemetrySpan = telemetry.startSpan("workglow.graph.run", {
|
|
@@ -2847,6 +3262,7 @@ class TaskGraphRunner {
|
|
|
2847
3262
|
async handleComplete() {
|
|
2848
3263
|
this.clearGraphTimeout();
|
|
2849
3264
|
this.running = false;
|
|
3265
|
+
this.activeEnforcer = undefined;
|
|
2850
3266
|
if (this.telemetrySpan) {
|
|
2851
3267
|
this.telemetrySpan.setStatus(SpanStatusCode2.OK);
|
|
2852
3268
|
this.telemetrySpan.end();
|
|
@@ -2865,6 +3281,7 @@ class TaskGraphRunner {
|
|
|
2865
3281
|
}
|
|
2866
3282
|
}));
|
|
2867
3283
|
this.running = false;
|
|
3284
|
+
this.activeEnforcer = undefined;
|
|
2868
3285
|
if (this.telemetrySpan) {
|
|
2869
3286
|
this.telemetrySpan.setStatus(SpanStatusCode2.ERROR, error.message);
|
|
2870
3287
|
this.telemetrySpan.setAttributes({ "workglow.graph.error": error.message });
|
|
@@ -2884,6 +3301,7 @@ class TaskGraphRunner {
|
|
|
2884
3301
|
}
|
|
2885
3302
|
}));
|
|
2886
3303
|
this.running = false;
|
|
3304
|
+
this.activeEnforcer = undefined;
|
|
2887
3305
|
if (this.telemetrySpan) {
|
|
2888
3306
|
this.telemetrySpan.setStatus(SpanStatusCode2.ERROR, "aborted");
|
|
2889
3307
|
this.telemetrySpan.addEvent("workglow.graph.aborted");
|
|
@@ -2985,9 +3403,10 @@ class GraphAsTask extends Task {
|
|
|
2985
3403
|
static category = "Flow Control";
|
|
2986
3404
|
static compoundMerge = PROPERTY_ARRAY;
|
|
2987
3405
|
static hasDynamicSchemas = true;
|
|
2988
|
-
|
|
3406
|
+
static hasDynamicEntitlements = true;
|
|
3407
|
+
constructor(config = {}) {
|
|
2989
3408
|
const { subGraph, ...rest } = config;
|
|
2990
|
-
super(
|
|
3409
|
+
super(rest);
|
|
2991
3410
|
if (subGraph) {
|
|
2992
3411
|
this.subGraph = subGraph;
|
|
2993
3412
|
}
|
|
@@ -3034,6 +3453,12 @@ class GraphAsTask extends Task {
|
|
|
3034
3453
|
}
|
|
3035
3454
|
return computeGraphOutputSchema(this.subGraph);
|
|
3036
3455
|
}
|
|
3456
|
+
entitlements() {
|
|
3457
|
+
if (!this.hasChildren()) {
|
|
3458
|
+
return this.constructor.entitlements();
|
|
3459
|
+
}
|
|
3460
|
+
return computeGraphEntitlements(this.subGraph);
|
|
3461
|
+
}
|
|
3037
3462
|
resetInputData() {
|
|
3038
3463
|
super.resetInputData();
|
|
3039
3464
|
if (this.hasChildren()) {
|
|
@@ -3072,26 +3497,44 @@ class GraphAsTask extends Task {
|
|
|
3072
3497
|
}
|
|
3073
3498
|
}
|
|
3074
3499
|
const eventQueue = [];
|
|
3075
|
-
let resolveWaiting;
|
|
3076
3500
|
let subgraphDone = false;
|
|
3501
|
+
let { promise: notifyPromise, resolve: notifyResolve } = Promise.withResolvers();
|
|
3502
|
+
let isWaiting = false;
|
|
3503
|
+
let hasPending = false;
|
|
3504
|
+
const notify = () => {
|
|
3505
|
+
if (isWaiting) {
|
|
3506
|
+
notifyResolve();
|
|
3507
|
+
({ promise: notifyPromise, resolve: notifyResolve } = Promise.withResolvers());
|
|
3508
|
+
isWaiting = false;
|
|
3509
|
+
} else {
|
|
3510
|
+
hasPending = true;
|
|
3511
|
+
}
|
|
3512
|
+
};
|
|
3077
3513
|
const unsub = this.subGraph.subscribeToTaskStreaming({
|
|
3078
3514
|
onStreamChunk: (taskId, event) => {
|
|
3079
3515
|
if (endingNodeIds.has(taskId) && event.type !== "finish") {
|
|
3080
3516
|
eventQueue.push(event);
|
|
3081
|
-
|
|
3517
|
+
notify();
|
|
3082
3518
|
}
|
|
3083
3519
|
}
|
|
3084
3520
|
});
|
|
3085
3521
|
const runPromise = this.subGraph.run(input, { parentSignal: context.signal, accumulateLeafOutputs: false }).then((results2) => {
|
|
3086
3522
|
subgraphDone = true;
|
|
3087
|
-
|
|
3523
|
+
notify();
|
|
3088
3524
|
return results2;
|
|
3525
|
+
}, (err) => {
|
|
3526
|
+
subgraphDone = true;
|
|
3527
|
+
notify();
|
|
3528
|
+
throw err;
|
|
3089
3529
|
});
|
|
3090
3530
|
while (!subgraphDone) {
|
|
3091
3531
|
if (eventQueue.length === 0) {
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
}
|
|
3532
|
+
if (hasPending) {
|
|
3533
|
+
hasPending = false;
|
|
3534
|
+
} else {
|
|
3535
|
+
isWaiting = true;
|
|
3536
|
+
await notifyPromise;
|
|
3537
|
+
}
|
|
3095
3538
|
}
|
|
3096
3539
|
while (eventQueue.length > 0) {
|
|
3097
3540
|
yield eventQueue.shift();
|
|
@@ -3111,6 +3554,7 @@ class GraphAsTask extends Task {
|
|
|
3111
3554
|
regenerateGraph() {
|
|
3112
3555
|
this._inputSchemaNode = undefined;
|
|
3113
3556
|
this.events.emit("regenerate");
|
|
3557
|
+
this.emitEntitlementChange();
|
|
3114
3558
|
}
|
|
3115
3559
|
toJSON(options) {
|
|
3116
3560
|
let json = super.toJSON(options);
|
|
@@ -3145,8 +3589,8 @@ function getWrapperClasses() {
|
|
|
3145
3589
|
if (!_OwnGraphTask) {
|
|
3146
3590
|
|
|
3147
3591
|
class ListeningGraphAsTask extends GraphAsTask {
|
|
3148
|
-
constructor(
|
|
3149
|
-
super(
|
|
3592
|
+
constructor(config) {
|
|
3593
|
+
super(config);
|
|
3150
3594
|
this.subGraph.on("start", () => {
|
|
3151
3595
|
this.emit("start");
|
|
3152
3596
|
});
|
|
@@ -3207,7 +3651,7 @@ function convertPipeFunctionToTask(fn, config) {
|
|
|
3207
3651
|
return fn(input, context);
|
|
3208
3652
|
}
|
|
3209
3653
|
}
|
|
3210
|
-
return new QuickTask(
|
|
3654
|
+
return new QuickTask(config);
|
|
3211
3655
|
}
|
|
3212
3656
|
function isWorkflowLike(arg) {
|
|
3213
3657
|
return arg != null && typeof arg === "object" && "graph" in arg && arg.graph instanceof TaskGraph && "run" in arg && typeof arg.run === "function";
|
|
@@ -3220,18 +3664,18 @@ function ensureTask(arg, config = {}) {
|
|
|
3220
3664
|
getWrapperClasses();
|
|
3221
3665
|
const { isOwned, ...cleanConfig } = config;
|
|
3222
3666
|
if (isOwned) {
|
|
3223
|
-
return new _OwnGraphTask({
|
|
3667
|
+
return new _OwnGraphTask({ ...cleanConfig, subGraph: arg });
|
|
3224
3668
|
} else {
|
|
3225
|
-
return new _GraphTask({
|
|
3669
|
+
return new _GraphTask({ ...cleanConfig, subGraph: arg });
|
|
3226
3670
|
}
|
|
3227
3671
|
}
|
|
3228
3672
|
if (isWorkflowLike(arg)) {
|
|
3229
3673
|
getWrapperClasses();
|
|
3230
3674
|
const { isOwned, ...cleanConfig } = config;
|
|
3231
3675
|
if (isOwned) {
|
|
3232
|
-
return new _OwnWorkflowTask({
|
|
3676
|
+
return new _OwnWorkflowTask({ ...cleanConfig, subGraph: arg.graph });
|
|
3233
3677
|
} else {
|
|
3234
|
-
return new _ConvWorkflowTask({
|
|
3678
|
+
return new _ConvWorkflowTask({ ...cleanConfig, subGraph: arg.graph });
|
|
3235
3679
|
}
|
|
3236
3680
|
}
|
|
3237
3681
|
return convertPipeFunctionToTask(arg, config);
|
|
@@ -3499,6 +3943,43 @@ class TaskGraph {
|
|
|
3499
3943
|
unsubscribes.forEach((unsub) => unsub());
|
|
3500
3944
|
};
|
|
3501
3945
|
}
|
|
3946
|
+
subscribeToTaskEntitlements(callback) {
|
|
3947
|
+
const globalUnsubs = [];
|
|
3948
|
+
const taskUnsubs = new Map;
|
|
3949
|
+
const emitChange = () => {
|
|
3950
|
+
const entitlements = computeGraphEntitlements(this);
|
|
3951
|
+
this.emit("entitlementChange", entitlements);
|
|
3952
|
+
callback(entitlements);
|
|
3953
|
+
};
|
|
3954
|
+
const subscribeTask = (taskId) => {
|
|
3955
|
+
const task = this.getTask(taskId);
|
|
3956
|
+
if (!task || typeof task.subscribe !== "function")
|
|
3957
|
+
return;
|
|
3958
|
+
const unsub = task.subscribe("entitlementChange", () => emitChange());
|
|
3959
|
+
taskUnsubs.set(taskId, unsub);
|
|
3960
|
+
};
|
|
3961
|
+
for (const task of this.getTasks()) {
|
|
3962
|
+
subscribeTask(task.id);
|
|
3963
|
+
}
|
|
3964
|
+
emitChange();
|
|
3965
|
+
globalUnsubs.push(this.subscribe("task_added", (taskId) => {
|
|
3966
|
+
subscribeTask(taskId);
|
|
3967
|
+
emitChange();
|
|
3968
|
+
}));
|
|
3969
|
+
globalUnsubs.push(this.subscribe("task_removed", (taskId) => {
|
|
3970
|
+
const unsub = taskUnsubs.get(taskId);
|
|
3971
|
+
if (unsub) {
|
|
3972
|
+
unsub();
|
|
3973
|
+
taskUnsubs.delete(taskId);
|
|
3974
|
+
}
|
|
3975
|
+
emitChange();
|
|
3976
|
+
}));
|
|
3977
|
+
return () => {
|
|
3978
|
+
globalUnsubs.forEach((unsub) => unsub());
|
|
3979
|
+
taskUnsubs.forEach((unsub) => unsub());
|
|
3980
|
+
taskUnsubs.clear();
|
|
3981
|
+
};
|
|
3982
|
+
}
|
|
3502
3983
|
on(name, fn) {
|
|
3503
3984
|
const dagEvent = EventTaskGraphToDagMapping[name];
|
|
3504
3985
|
if (dagEvent) {
|
|
@@ -3543,11 +4024,7 @@ function serialGraph(tasks, inputHandle, outputHandle) {
|
|
|
3543
4024
|
return graph;
|
|
3544
4025
|
}
|
|
3545
4026
|
// src/task-graph/Workflow.ts
|
|
3546
|
-
import {
|
|
3547
|
-
EventEmitter as EventEmitter5,
|
|
3548
|
-
getLogger as getLogger5,
|
|
3549
|
-
uuid4 as uuid45
|
|
3550
|
-
} from "@workglow/util";
|
|
4027
|
+
import { EventEmitter as EventEmitter5, getLogger as getLogger5, uuid4 as uuid45 } from "@workglow/util";
|
|
3551
4028
|
function getLastTask(workflow) {
|
|
3552
4029
|
const tasks = workflow.graph.getTasks();
|
|
3553
4030
|
return tasks.length > 0 ? tasks[tasks.length - 1] : undefined;
|
|
@@ -3570,7 +4047,6 @@ function pipe(args, workflow = new Workflow) {
|
|
|
3570
4047
|
function parallel(args, mergeFn = PROPERTY_ARRAY, workflow = new Workflow) {
|
|
3571
4048
|
let previousTask = getLastTask(workflow);
|
|
3572
4049
|
const tasks = args.map((arg) => ensureTask(arg));
|
|
3573
|
-
const input = {};
|
|
3574
4050
|
const config = {
|
|
3575
4051
|
compoundMerge: mergeFn
|
|
3576
4052
|
};
|
|
@@ -3579,7 +4055,7 @@ function parallel(args, mergeFn = PROPERTY_ARRAY, workflow = new Workflow) {
|
|
|
3579
4055
|
class ParallelTask extends GraphAsTask {
|
|
3580
4056
|
static type = name;
|
|
3581
4057
|
}
|
|
3582
|
-
const mergeTask = new ParallelTask(
|
|
4058
|
+
const mergeTask = new ParallelTask(config);
|
|
3583
4059
|
mergeTask.subGraph.addTasks(tasks);
|
|
3584
4060
|
workflow.graph.addTask(mergeTask);
|
|
3585
4061
|
if (previousTask) {
|
|
@@ -3658,10 +4134,11 @@ class WorkflowTask extends GraphAsTask {
|
|
|
3658
4134
|
}
|
|
3659
4135
|
|
|
3660
4136
|
class Workflow {
|
|
3661
|
-
constructor(cache, parent, iteratorTask) {
|
|
4137
|
+
constructor(cache, parent, iteratorTask, registry) {
|
|
3662
4138
|
this._outputCache = cache;
|
|
3663
4139
|
this._parentWorkflow = parent;
|
|
3664
4140
|
this._iteratorTask = iteratorTask;
|
|
4141
|
+
this._registry = registry ?? parent?._registry;
|
|
3665
4142
|
this._graph = new TaskGraph({ outputCache: this._outputCache });
|
|
3666
4143
|
if (!parent) {
|
|
3667
4144
|
this._onChanged = this._onChanged.bind(this);
|
|
@@ -3672,6 +4149,8 @@ class Workflow {
|
|
|
3672
4149
|
_dataFlows = [];
|
|
3673
4150
|
_error = "";
|
|
3674
4151
|
_outputCache;
|
|
4152
|
+
_registry;
|
|
4153
|
+
_entitlementUnsub;
|
|
3675
4154
|
_abortController;
|
|
3676
4155
|
_parentWorkflow;
|
|
3677
4156
|
_iteratorTask;
|
|
@@ -3687,7 +4166,11 @@ class Workflow {
|
|
|
3687
4166
|
const helper = function(input = {}, config = {}) {
|
|
3688
4167
|
this._error = "";
|
|
3689
4168
|
const parent = getLastTask(this);
|
|
3690
|
-
const task = this.addTaskToGraph(taskClass,
|
|
4169
|
+
const task = this.addTaskToGraph(taskClass, {
|
|
4170
|
+
id: uuid45(),
|
|
4171
|
+
...config,
|
|
4172
|
+
defaults: input
|
|
4173
|
+
});
|
|
3691
4174
|
if (this._dataFlows.length > 0) {
|
|
3692
4175
|
this._dataFlows.forEach((dataflow) => {
|
|
3693
4176
|
const taskSchema = task.inputSchema();
|
|
@@ -3785,7 +4268,7 @@ class Workflow {
|
|
|
3785
4268
|
const output = await this.graph.run(input, {
|
|
3786
4269
|
parentSignal: this._abortController.signal,
|
|
3787
4270
|
outputCache: this._outputCache,
|
|
3788
|
-
registry: config?.registry
|
|
4271
|
+
registry: config?.registry ?? this._registry
|
|
3789
4272
|
});
|
|
3790
4273
|
const results = this.graph.mergeExecuteOutputsToRunOutput(output, PROPERTY_ARRAY);
|
|
3791
4274
|
this.events.emit("complete");
|
|
@@ -3822,6 +4305,9 @@ class Workflow {
|
|
|
3822
4305
|
toDependencyJSON(options = { withBoundaryNodes: true }) {
|
|
3823
4306
|
return this._graph.toDependencyJSON(options);
|
|
3824
4307
|
}
|
|
4308
|
+
entitlements(options) {
|
|
4309
|
+
return computeGraphEntitlements(this._graph, options);
|
|
4310
|
+
}
|
|
3825
4311
|
pipe(...args) {
|
|
3826
4312
|
return pipe(args, this);
|
|
3827
4313
|
}
|
|
@@ -3906,6 +4392,7 @@ class Workflow {
|
|
|
3906
4392
|
this._graph.on("dataflow_added", this._onChanged);
|
|
3907
4393
|
this._graph.on("dataflow_replaced", this._onChanged);
|
|
3908
4394
|
this._graph.on("dataflow_removed", this._onChanged);
|
|
4395
|
+
this._entitlementUnsub = this._graph.subscribeToTaskEntitlements((entitlements) => this.events.emit("entitlementChange", entitlements));
|
|
3909
4396
|
}
|
|
3910
4397
|
clearEvents() {
|
|
3911
4398
|
this._graph.off("task_added", this._onChanged);
|
|
@@ -3914,6 +4401,8 @@ class Workflow {
|
|
|
3914
4401
|
this._graph.off("dataflow_added", this._onChanged);
|
|
3915
4402
|
this._graph.off("dataflow_replaced", this._onChanged);
|
|
3916
4403
|
this._graph.off("dataflow_removed", this._onChanged);
|
|
4404
|
+
this._entitlementUnsub?.();
|
|
4405
|
+
this._entitlementUnsub = undefined;
|
|
3917
4406
|
}
|
|
3918
4407
|
_onChanged(id) {
|
|
3919
4408
|
this.events.emit("changed", id);
|
|
@@ -3945,8 +4434,8 @@ class Workflow {
|
|
|
3945
4434
|
this.graph.addDataflow(dataflow);
|
|
3946
4435
|
return this;
|
|
3947
4436
|
}
|
|
3948
|
-
addTaskToGraph(taskClass,
|
|
3949
|
-
const task = new taskClass(
|
|
4437
|
+
addTaskToGraph(taskClass, config) {
|
|
4438
|
+
const task = new taskClass(config, this._registry ? { registry: this._registry } : undefined);
|
|
3950
4439
|
const id = this.graph.addTask(task);
|
|
3951
4440
|
this.events.emit("changed", id);
|
|
3952
4441
|
return task;
|
|
@@ -3958,7 +4447,7 @@ class Workflow {
|
|
|
3958
4447
|
addLoopTask(taskClass, config = {}) {
|
|
3959
4448
|
this._error = "";
|
|
3960
4449
|
const parent = getLastTask(this);
|
|
3961
|
-
const task = this.addTaskToGraph(taskClass, {
|
|
4450
|
+
const task = this.addTaskToGraph(taskClass, { id: uuid45(), ...config });
|
|
3962
4451
|
if (this._dataFlows.length > 0) {
|
|
3963
4452
|
this._dataFlows.forEach((dataflow) => {
|
|
3964
4453
|
const taskSchema = task.inputSchema();
|
|
@@ -3972,7 +4461,7 @@ class Workflow {
|
|
|
3972
4461
|
});
|
|
3973
4462
|
this._dataFlows = [];
|
|
3974
4463
|
}
|
|
3975
|
-
const loopBuilder = new Workflow(this.outputCache(), this, task);
|
|
4464
|
+
const loopBuilder = new Workflow(this.outputCache(), this, task, this._registry);
|
|
3976
4465
|
if (parent) {
|
|
3977
4466
|
loopBuilder._pendingLoopConnect = { parent, iteratorTask: task };
|
|
3978
4467
|
}
|
|
@@ -4055,10 +4544,29 @@ class Workflow {
|
|
|
4055
4544
|
const sourceSchema = sourceTask.outputSchema();
|
|
4056
4545
|
if (typeof sourceSchema === "boolean")
|
|
4057
4546
|
continue;
|
|
4058
|
-
|
|
4547
|
+
let prop = sourceSchema.properties?.[df.sourceTaskPortId];
|
|
4548
|
+
let propRequired = sourceSchema.required?.includes(df.sourceTaskPortId) ?? false;
|
|
4549
|
+
if (!prop && sourceSchema.additionalProperties === true && sourceTask.constructor.passthroughInputsToOutputs === true) {
|
|
4550
|
+
const upstreamDfs = graph.getSourceDataflows(sourceTask.id);
|
|
4551
|
+
for (const udf of upstreamDfs) {
|
|
4552
|
+
if (udf.targetTaskPortId !== df.sourceTaskPortId)
|
|
4553
|
+
continue;
|
|
4554
|
+
const upstreamTask = graph.getTask(udf.sourceTaskId);
|
|
4555
|
+
if (!upstreamTask)
|
|
4556
|
+
continue;
|
|
4557
|
+
const upstreamSchema = upstreamTask.outputSchema();
|
|
4558
|
+
if (typeof upstreamSchema === "boolean")
|
|
4559
|
+
continue;
|
|
4560
|
+
prop = upstreamSchema.properties?.[udf.sourceTaskPortId];
|
|
4561
|
+
if (prop) {
|
|
4562
|
+
propRequired = upstreamSchema.required?.includes(udf.sourceTaskPortId) ?? false;
|
|
4563
|
+
break;
|
|
4564
|
+
}
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4059
4567
|
if (prop && typeof prop !== "boolean") {
|
|
4060
4568
|
properties[df.targetTaskPortId] = prop;
|
|
4061
|
-
if (
|
|
4569
|
+
if (propRequired && !required.includes(df.targetTaskPortId)) {
|
|
4062
4570
|
required.push(df.targetTaskPortId);
|
|
4063
4571
|
}
|
|
4064
4572
|
}
|
|
@@ -4158,11 +4666,30 @@ class Workflow {
|
|
|
4158
4666
|
const makeMatch = (fromSchema, toSchema, fromTaskId, toTaskId, comparator) => {
|
|
4159
4667
|
if (typeof fromSchema === "object") {
|
|
4160
4668
|
if (toSchema === true || typeof toSchema === "object" && toSchema.additionalProperties === true) {
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4669
|
+
const outputKeys = Object.keys(fromSchema.properties || {});
|
|
4670
|
+
if (outputKeys.length > 0) {
|
|
4671
|
+
for (const fromOutputPortId of outputKeys) {
|
|
4672
|
+
if (matches.has(fromOutputPortId))
|
|
4673
|
+
continue;
|
|
4674
|
+
matches.set(fromOutputPortId, fromOutputPortId);
|
|
4675
|
+
graph.addDataflow(new Dataflow(fromTaskId, fromOutputPortId, toTaskId, fromOutputPortId));
|
|
4676
|
+
}
|
|
4677
|
+
} else if (fromSchema.additionalProperties === true) {
|
|
4678
|
+
const sourceGraphTask = graph.getTask(fromTaskId);
|
|
4679
|
+
if (sourceGraphTask && sourceGraphTask.constructor.passthroughInputsToOutputs === true) {
|
|
4680
|
+
const incomingDfs = graph.getSourceDataflows(fromTaskId);
|
|
4681
|
+
for (const df of incomingDfs) {
|
|
4682
|
+
const portId = df.targetTaskPortId;
|
|
4683
|
+
if (portId === DATAFLOW_ALL_PORTS)
|
|
4684
|
+
continue;
|
|
4685
|
+
if (matches.has(portId))
|
|
4686
|
+
continue;
|
|
4687
|
+
if (connectedInputKeys.has(portId))
|
|
4688
|
+
continue;
|
|
4689
|
+
matches.set(portId, portId);
|
|
4690
|
+
graph.addDataflow(new Dataflow(fromTaskId, portId, toTaskId, portId));
|
|
4691
|
+
}
|
|
4692
|
+
}
|
|
4166
4693
|
}
|
|
4167
4694
|
return;
|
|
4168
4695
|
}
|
|
@@ -4558,7 +5085,18 @@ function extractLoopConfig(task) {
|
|
|
4558
5085
|
}
|
|
4559
5086
|
return config;
|
|
4560
5087
|
}
|
|
5088
|
+
function stripUndefined(obj) {
|
|
5089
|
+
if (!obj)
|
|
5090
|
+
return obj;
|
|
5091
|
+
const result = {};
|
|
5092
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
5093
|
+
if (v !== undefined)
|
|
5094
|
+
result[k] = v;
|
|
5095
|
+
}
|
|
5096
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
5097
|
+
}
|
|
4561
5098
|
function buildMethodArgs(defaults, config, baseIndent = "", columnOffset = 0) {
|
|
5099
|
+
defaults = stripUndefined(defaults);
|
|
4562
5100
|
const hasDefaults = defaults && Object.keys(defaults).length > 0;
|
|
4563
5101
|
const hasConfig = Object.keys(config).length > 0;
|
|
4564
5102
|
if (!hasDefaults && !hasConfig)
|
|
@@ -4634,6 +5172,37 @@ ${baseIndent}}`;
|
|
|
4634
5172
|
function resetMethodNameCache() {
|
|
4635
5173
|
methodNameCache = undefined;
|
|
4636
5174
|
}
|
|
5175
|
+
// src/task/EntitlementProfiles.ts
|
|
5176
|
+
var BROWSER_GRANTS = [
|
|
5177
|
+
{ id: Entitlements.NETWORK },
|
|
5178
|
+
{ id: Entitlements.AI },
|
|
5179
|
+
{ id: Entitlements.MCP_TOOL_CALL },
|
|
5180
|
+
{ id: Entitlements.MCP_RESOURCE_READ },
|
|
5181
|
+
{ id: Entitlements.MCP_PROMPT_GET },
|
|
5182
|
+
{ id: Entitlements.STORAGE },
|
|
5183
|
+
{ id: Entitlements.CREDENTIAL }
|
|
5184
|
+
];
|
|
5185
|
+
var DESKTOP_GRANTS = [
|
|
5186
|
+
...BROWSER_GRANTS,
|
|
5187
|
+
{ id: Entitlements.FILESYSTEM },
|
|
5188
|
+
{ id: Entitlements.CODE_EXECUTION },
|
|
5189
|
+
{ id: Entitlements.MCP_STDIO }
|
|
5190
|
+
];
|
|
5191
|
+
var SERVER_GRANTS = [...DESKTOP_GRANTS];
|
|
5192
|
+
var PROFILE_GRANTS = {
|
|
5193
|
+
browser: BROWSER_GRANTS,
|
|
5194
|
+
desktop: DESKTOP_GRANTS,
|
|
5195
|
+
server: SERVER_GRANTS
|
|
5196
|
+
};
|
|
5197
|
+
function createProfilePolicy(profile) {
|
|
5198
|
+
return { deny: [], grant: PROFILE_GRANTS[profile], ask: [] };
|
|
5199
|
+
}
|
|
5200
|
+
function createProfileEnforcer(profile, resolver) {
|
|
5201
|
+
return createPolicyEnforcer(createProfilePolicy(profile), resolver);
|
|
5202
|
+
}
|
|
5203
|
+
function getProfileGrants(profile) {
|
|
5204
|
+
return PROFILE_GRANTS[profile];
|
|
5205
|
+
}
|
|
4637
5206
|
// src/task/FallbackTaskRunner.ts
|
|
4638
5207
|
class FallbackTaskRunner extends GraphAsTaskRunner {
|
|
4639
5208
|
async executeTask(input) {
|
|
@@ -4833,6 +5402,83 @@ queueMicrotask(() => {
|
|
|
4833
5402
|
};
|
|
4834
5403
|
Workflow.prototype.endFallbackWith = CreateEndLoopWorkflow("endFallbackWith");
|
|
4835
5404
|
});
|
|
5405
|
+
// src/task/InputCompactor.ts
|
|
5406
|
+
import { getInputCompactors } from "@workglow/util";
|
|
5407
|
+
function schemaAllowsString(schema, visited = new WeakSet) {
|
|
5408
|
+
if (typeof schema !== "object" || schema === null)
|
|
5409
|
+
return false;
|
|
5410
|
+
if (visited.has(schema))
|
|
5411
|
+
return false;
|
|
5412
|
+
visited.add(schema);
|
|
5413
|
+
const s = schema;
|
|
5414
|
+
if (s.type === "string")
|
|
5415
|
+
return true;
|
|
5416
|
+
const variants = s.oneOf ?? s.anyOf;
|
|
5417
|
+
if (Array.isArray(variants)) {
|
|
5418
|
+
for (const variant of variants) {
|
|
5419
|
+
if (schemaAllowsString(variant, visited))
|
|
5420
|
+
return true;
|
|
5421
|
+
}
|
|
5422
|
+
}
|
|
5423
|
+
const allOf = s.allOf;
|
|
5424
|
+
if (Array.isArray(allOf)) {
|
|
5425
|
+
for (const sub of allOf) {
|
|
5426
|
+
if (schemaAllowsString(sub, visited))
|
|
5427
|
+
return true;
|
|
5428
|
+
}
|
|
5429
|
+
}
|
|
5430
|
+
return false;
|
|
5431
|
+
}
|
|
5432
|
+
async function compactSchemaInputs(input, schema, config, visited = new Set) {
|
|
5433
|
+
if (typeof schema === "boolean")
|
|
5434
|
+
return input;
|
|
5435
|
+
const properties = schema.properties;
|
|
5436
|
+
if (!properties || typeof properties !== "object")
|
|
5437
|
+
return input;
|
|
5438
|
+
const compactors = getInputCompactors();
|
|
5439
|
+
const compacted = { ...input };
|
|
5440
|
+
for (const [key, propSchema] of Object.entries(properties)) {
|
|
5441
|
+
let value = compacted[key];
|
|
5442
|
+
const format = getSchemaFormat(propSchema);
|
|
5443
|
+
if (format) {
|
|
5444
|
+
let compactor = compactors.get(format);
|
|
5445
|
+
if (!compactor) {
|
|
5446
|
+
const prefix = getFormatPrefix(format);
|
|
5447
|
+
compactor = compactors.get(prefix);
|
|
5448
|
+
}
|
|
5449
|
+
if (compactor) {
|
|
5450
|
+
if (value !== null && value !== undefined && typeof value === "object" && !Array.isArray(value) && schemaAllowsString(propSchema)) {
|
|
5451
|
+
const id = await compactor(value, format, config.registry);
|
|
5452
|
+
if (id !== undefined) {
|
|
5453
|
+
compacted[key] = id;
|
|
5454
|
+
continue;
|
|
5455
|
+
}
|
|
5456
|
+
} else if (Array.isArray(value)) {
|
|
5457
|
+
compacted[key] = await Promise.all(value.map(async (item) => {
|
|
5458
|
+
if (item !== null && item !== undefined && typeof item === "object" && !Array.isArray(item)) {
|
|
5459
|
+
const id = await compactor(item, format, config.registry);
|
|
5460
|
+
return id !== undefined ? id : item;
|
|
5461
|
+
}
|
|
5462
|
+
return item;
|
|
5463
|
+
}));
|
|
5464
|
+
continue;
|
|
5465
|
+
}
|
|
5466
|
+
}
|
|
5467
|
+
}
|
|
5468
|
+
if (value !== null && value !== undefined && typeof value === "object" && !Array.isArray(value)) {
|
|
5469
|
+
const objectSchema = getObjectSchema(propSchema);
|
|
5470
|
+
if (objectSchema && !visited.has(objectSchema)) {
|
|
5471
|
+
visited.add(objectSchema);
|
|
5472
|
+
try {
|
|
5473
|
+
compacted[key] = await compactSchemaInputs(value, objectSchema, config, visited);
|
|
5474
|
+
} finally {
|
|
5475
|
+
visited.delete(objectSchema);
|
|
5476
|
+
}
|
|
5477
|
+
}
|
|
5478
|
+
}
|
|
5479
|
+
}
|
|
5480
|
+
return compacted;
|
|
5481
|
+
}
|
|
4836
5482
|
// src/task/IteratorTaskRunner.ts
|
|
4837
5483
|
import { uuid4 as uuid46 } from "@workglow/util";
|
|
4838
5484
|
class IteratorTaskRunner extends GraphAsTaskRunner {
|
|
@@ -4951,7 +5597,7 @@ class IteratorTaskRunner extends GraphAsTaskRunner {
|
|
|
4951
5597
|
const newId = uuid46();
|
|
4952
5598
|
idMap.set(task.config.id, newId);
|
|
4953
5599
|
const clonedConfig = { ...task.config, id: newId };
|
|
4954
|
-
const newTask = new ctor(task.defaults
|
|
5600
|
+
const newTask = new ctor({ ...clonedConfig, defaults: task.defaults }, task.runConfig);
|
|
4955
5601
|
if (task.hasChildren()) {
|
|
4956
5602
|
newTask.subGraph = this.cloneGraph(task.subGraph);
|
|
4957
5603
|
}
|
|
@@ -5151,9 +5797,6 @@ class IteratorTask extends GraphAsTask {
|
|
|
5151
5797
|
}
|
|
5152
5798
|
_iteratorPortInfo;
|
|
5153
5799
|
_iterationInputSchema;
|
|
5154
|
-
constructor(input = {}, config = {}) {
|
|
5155
|
-
super(input, config);
|
|
5156
|
-
}
|
|
5157
5800
|
get runner() {
|
|
5158
5801
|
if (!this._runner) {
|
|
5159
5802
|
this._runner = new IteratorTaskRunner(this);
|
|
@@ -5564,9 +6207,6 @@ class WhileTask extends GraphAsTask {
|
|
|
5564
6207
|
canSerializeConfig() {
|
|
5565
6208
|
return typeof this.config.condition !== "function";
|
|
5566
6209
|
}
|
|
5567
|
-
constructor(input = {}, config = {}) {
|
|
5568
|
-
super(input, config);
|
|
5569
|
-
}
|
|
5570
6210
|
get runner() {
|
|
5571
6211
|
if (!this._runner) {
|
|
5572
6212
|
this._runner = new WhileTaskRunner(this);
|
|
@@ -6088,8 +6728,8 @@ import {
|
|
|
6088
6728
|
JobQueueServer
|
|
6089
6729
|
} from "@workglow/job-queue";
|
|
6090
6730
|
import { InMemoryQueueStorage } from "@workglow/storage";
|
|
6091
|
-
import { createServiceToken as
|
|
6092
|
-
var JOB_QUEUE_FACTORY =
|
|
6731
|
+
import { createServiceToken as createServiceToken4, globalServiceRegistry as globalServiceRegistry3 } from "@workglow/util";
|
|
6732
|
+
var JOB_QUEUE_FACTORY = createServiceToken4("taskgraph.jobQueueFactory");
|
|
6093
6733
|
var defaultJobQueueFactory = async ({
|
|
6094
6734
|
queueName,
|
|
6095
6735
|
jobClass,
|
|
@@ -6254,13 +6894,13 @@ class ReduceTask extends IteratorTask {
|
|
|
6254
6894
|
static configSchema() {
|
|
6255
6895
|
return reduceTaskConfigSchema;
|
|
6256
6896
|
}
|
|
6257
|
-
constructor(
|
|
6897
|
+
constructor(config = {}) {
|
|
6258
6898
|
const reduceConfig = {
|
|
6259
6899
|
...config,
|
|
6260
6900
|
concurrencyLimit: 1,
|
|
6261
6901
|
batchSize: 1
|
|
6262
6902
|
};
|
|
6263
|
-
super(
|
|
6903
|
+
super(reduceConfig);
|
|
6264
6904
|
}
|
|
6265
6905
|
get initialValue() {
|
|
6266
6906
|
return this.config.initialValue ?? {};
|
|
@@ -6332,23 +6972,48 @@ queueMicrotask(() => {
|
|
|
6332
6972
|
});
|
|
6333
6973
|
// src/task/TaskRegistry.ts
|
|
6334
6974
|
import {
|
|
6335
|
-
createServiceToken as
|
|
6975
|
+
createServiceToken as createServiceToken5,
|
|
6976
|
+
getLogger as getLogger6,
|
|
6336
6977
|
globalServiceRegistry as globalServiceRegistry4,
|
|
6978
|
+
registerInputCompactor,
|
|
6337
6979
|
registerInputResolver
|
|
6338
6980
|
} from "@workglow/util";
|
|
6981
|
+
import { validateSchema } from "@workglow/util/schema";
|
|
6339
6982
|
var taskConstructors = new Map;
|
|
6340
6983
|
function registerTask(baseClass) {
|
|
6341
|
-
|
|
6984
|
+
const existing = taskConstructors.get(baseClass.type);
|
|
6985
|
+
if (existing) {
|
|
6986
|
+
if (existing === baseClass)
|
|
6987
|
+
return;
|
|
6988
|
+
throw new Error(`Task type "${baseClass.type}" is already registered. Unregister it first to replace.`);
|
|
6989
|
+
}
|
|
6342
6990
|
taskConstructors.set(baseClass.type, baseClass);
|
|
6991
|
+
const schemas = [
|
|
6992
|
+
{ name: "inputSchema", schema: baseClass.inputSchema() },
|
|
6993
|
+
{ name: "outputSchema", schema: baseClass.outputSchema() }
|
|
6994
|
+
];
|
|
6995
|
+
for (const { name, schema } of schemas) {
|
|
6996
|
+
const result = validateSchema(schema);
|
|
6997
|
+
if (!result.valid) {
|
|
6998
|
+
const messages = result.errors.map((e) => `${e.path}: ${e.message}`).join("; ");
|
|
6999
|
+
getLogger6().warn(`Task "${baseClass.type}" has invalid ${name}: ${messages}`, {
|
|
7000
|
+
taskType: baseClass.type,
|
|
7001
|
+
schemaName: name,
|
|
7002
|
+
errors: result.errors
|
|
7003
|
+
});
|
|
7004
|
+
}
|
|
7005
|
+
}
|
|
7006
|
+
}
|
|
7007
|
+
function unregisterTask(type) {
|
|
7008
|
+
return taskConstructors.delete(type);
|
|
6343
7009
|
}
|
|
6344
7010
|
var TaskRegistry = {
|
|
6345
7011
|
all: taskConstructors,
|
|
6346
|
-
registerTask
|
|
7012
|
+
registerTask,
|
|
7013
|
+
unregisterTask
|
|
6347
7014
|
};
|
|
6348
|
-
var TASK_CONSTRUCTORS =
|
|
6349
|
-
|
|
6350
|
-
globalServiceRegistry4.register(TASK_CONSTRUCTORS, () => TaskRegistry.all, true);
|
|
6351
|
-
}
|
|
7015
|
+
var TASK_CONSTRUCTORS = createServiceToken5("task.constructors");
|
|
7016
|
+
globalServiceRegistry4.registerIfAbsent(TASK_CONSTRUCTORS, () => TaskRegistry.all, true);
|
|
6352
7017
|
function getGlobalTaskConstructors() {
|
|
6353
7018
|
return globalServiceRegistry4.get(TASK_CONSTRUCTORS);
|
|
6354
7019
|
}
|
|
@@ -6376,6 +7041,17 @@ function resolveTaskFromRegistry(id, _format, registry) {
|
|
|
6376
7041
|
};
|
|
6377
7042
|
}
|
|
6378
7043
|
registerInputResolver("tasks", resolveTaskFromRegistry);
|
|
7044
|
+
registerInputCompactor("tasks", (value, _format, registry) => {
|
|
7045
|
+
if (typeof value === "object" && value !== null && "name" in value) {
|
|
7046
|
+
const name = value.name;
|
|
7047
|
+
if (typeof name !== "string")
|
|
7048
|
+
return;
|
|
7049
|
+
const constructors = getTaskConstructors(registry);
|
|
7050
|
+
const ctor = constructors.get(name);
|
|
7051
|
+
return ctor ? name : undefined;
|
|
7052
|
+
}
|
|
7053
|
+
return;
|
|
7054
|
+
});
|
|
6379
7055
|
|
|
6380
7056
|
// src/task/TaskJSON.ts
|
|
6381
7057
|
var createSingleTaskFromJSON = (item, registry, options) => {
|
|
@@ -6395,11 +7071,15 @@ var createSingleTaskFromJSON = (item, registry, options) => {
|
|
|
6395
7071
|
const taskClass = constructors.get(item.type);
|
|
6396
7072
|
if (!taskClass)
|
|
6397
7073
|
throw new TaskJSONError(`Task type ${item.type} not found, perhaps not registered?`);
|
|
7074
|
+
if (typeof taskClass !== "function" || typeof taskClass.type !== "string") {
|
|
7075
|
+
throw new TaskJSONError(`Task type ${item.type} resolved to an invalid constructor`);
|
|
7076
|
+
}
|
|
6398
7077
|
const taskConfig = {
|
|
6399
7078
|
...item.config,
|
|
6400
|
-
id: item.id
|
|
7079
|
+
id: item.id,
|
|
7080
|
+
defaults: item.defaults ?? {}
|
|
6401
7081
|
};
|
|
6402
|
-
const task = new taskClass(
|
|
7082
|
+
const task = new taskClass(taskConfig, registry ? { registry } : {});
|
|
6403
7083
|
return task;
|
|
6404
7084
|
};
|
|
6405
7085
|
var createTaskFromDependencyJSON = (item, registry, options) => {
|
|
@@ -6493,8 +7173,8 @@ var registerBaseTasks = () => {
|
|
|
6493
7173
|
return tasks;
|
|
6494
7174
|
};
|
|
6495
7175
|
// src/storage/TaskGraphRepository.ts
|
|
6496
|
-
import { createServiceToken as
|
|
6497
|
-
var TASK_GRAPH_REPOSITORY =
|
|
7176
|
+
import { createServiceToken as createServiceToken6, EventEmitter as EventEmitter7 } from "@workglow/util";
|
|
7177
|
+
var TASK_GRAPH_REPOSITORY = createServiceToken6("taskgraph.taskGraphRepository");
|
|
6498
7178
|
|
|
6499
7179
|
class TaskGraphRepository {
|
|
6500
7180
|
type = "TaskGraphRepository";
|
|
@@ -6660,6 +7340,9 @@ export {
|
|
|
6660
7340
|
serialGraph,
|
|
6661
7341
|
schemaHasFormatAnnotations,
|
|
6662
7342
|
schemaAcceptsArray,
|
|
7343
|
+
scanGraphForFormat,
|
|
7344
|
+
scanGraphForCredentials,
|
|
7345
|
+
resourcePatternMatches,
|
|
6663
7346
|
resolveSchemaInputs,
|
|
6664
7347
|
resetMethodNameCache,
|
|
6665
7348
|
removeIterationProperties,
|
|
@@ -6668,6 +7351,9 @@ export {
|
|
|
6668
7351
|
reduceTaskConfigSchema,
|
|
6669
7352
|
pipe,
|
|
6670
7353
|
parallel,
|
|
7354
|
+
mergeResources,
|
|
7355
|
+
mergeEntitlements,
|
|
7356
|
+
mergeEntitlementPair,
|
|
6671
7357
|
mergeChainedOutputToInput,
|
|
6672
7358
|
mapTaskConfigSchema,
|
|
6673
7359
|
iteratorTaskConfigSchema,
|
|
@@ -6680,12 +7366,16 @@ export {
|
|
|
6680
7366
|
hasStructuredOutput,
|
|
6681
7367
|
graphToWorkflowCode,
|
|
6682
7368
|
graphAsTaskConfigSchema,
|
|
7369
|
+
grantCoversResources,
|
|
6683
7370
|
getTaskQueueRegistry,
|
|
6684
7371
|
getTaskConstructors,
|
|
6685
7372
|
getStructuredOutputSchemas,
|
|
6686
7373
|
getStreamingPorts,
|
|
7374
|
+
getSchemaFormat,
|
|
7375
|
+
getProfileGrants,
|
|
6687
7376
|
getPortStreamMode,
|
|
6688
7377
|
getOutputStreamMode,
|
|
7378
|
+
getObjectSchema,
|
|
6689
7379
|
getObjectPortId,
|
|
6690
7380
|
getNestedValue,
|
|
6691
7381
|
getLastTask,
|
|
@@ -6693,6 +7383,7 @@ export {
|
|
|
6693
7383
|
getIterationContextSchemaForType,
|
|
6694
7384
|
getInputModeFromSchema,
|
|
6695
7385
|
getGlobalTaskConstructors,
|
|
7386
|
+
getFormatPrefix,
|
|
6696
7387
|
getAppendPortId,
|
|
6697
7388
|
formatValue,
|
|
6698
7389
|
findArrayPorts,
|
|
@@ -6700,20 +7391,29 @@ export {
|
|
|
6700
7391
|
fallbackTaskConfigSchema,
|
|
6701
7392
|
extractIterationProperties,
|
|
6702
7393
|
extractBaseSchema,
|
|
7394
|
+
evaluatePolicy,
|
|
6703
7395
|
evaluateCondition,
|
|
7396
|
+
entitlementCovers,
|
|
6704
7397
|
ensureTask,
|
|
6705
7398
|
edgeNeedsAccumulation,
|
|
6706
7399
|
createTaskFromGraphJSON,
|
|
6707
7400
|
createTaskFromDependencyJSON,
|
|
7401
|
+
createScopedEnforcer,
|
|
7402
|
+
createProfilePolicy,
|
|
7403
|
+
createProfileEnforcer,
|
|
7404
|
+
createPolicyEnforcer,
|
|
6708
7405
|
createJobQueueFactoryWithOptions,
|
|
6709
7406
|
createGraphFromGraphJSON,
|
|
6710
7407
|
createGraphFromDependencyJSON,
|
|
7408
|
+
createGrantListEnforcer,
|
|
6711
7409
|
createFlexibleSchema,
|
|
6712
7410
|
createArraySchema,
|
|
6713
7411
|
connect,
|
|
6714
7412
|
conditionalTaskConfigSchema,
|
|
6715
7413
|
computeGraphOutputSchema,
|
|
6716
7414
|
computeGraphInputSchema,
|
|
7415
|
+
computeGraphEntitlements,
|
|
7416
|
+
compactSchemaInputs,
|
|
6717
7417
|
calculateNodeDepths,
|
|
6718
7418
|
buildIterationInputSchema,
|
|
6719
7419
|
addIterationContextToSchema,
|
|
@@ -6744,6 +7444,7 @@ export {
|
|
|
6744
7444
|
TaskGraph,
|
|
6745
7445
|
TaskFailedError,
|
|
6746
7446
|
TaskError,
|
|
7447
|
+
TaskEntitlementError,
|
|
6747
7448
|
TaskConfigurationError,
|
|
6748
7449
|
TaskConfigSchema,
|
|
6749
7450
|
TaskAbortedError,
|
|
@@ -6751,8 +7452,11 @@ export {
|
|
|
6751
7452
|
TASK_OUTPUT_REPOSITORY,
|
|
6752
7453
|
TASK_GRAPH_REPOSITORY,
|
|
6753
7454
|
TASK_CONSTRUCTORS,
|
|
7455
|
+
SERVER_GRANTS,
|
|
6754
7456
|
ReduceTask,
|
|
6755
7457
|
PROPERTY_ARRAY,
|
|
7458
|
+
PERMISSIVE_RESOLVER,
|
|
7459
|
+
PERMISSIVE_ENFORCER,
|
|
6756
7460
|
MapTask,
|
|
6757
7461
|
JobTaskFailedError,
|
|
6758
7462
|
JOB_QUEUE_FACTORY,
|
|
@@ -6766,15 +7470,23 @@ export {
|
|
|
6766
7470
|
FallbackTask,
|
|
6767
7471
|
EventTaskGraphToDagMapping,
|
|
6768
7472
|
EventDagToTaskGraphMapping,
|
|
7473
|
+
Entitlements,
|
|
7474
|
+
ENTITLEMENT_RESOLVER,
|
|
7475
|
+
ENTITLEMENT_ENFORCER,
|
|
7476
|
+
EMPTY_POLICY,
|
|
7477
|
+
EMPTY_ENTITLEMENTS,
|
|
6769
7478
|
DataflowArrow,
|
|
6770
7479
|
Dataflow,
|
|
7480
|
+
DESKTOP_GRANTS,
|
|
7481
|
+
DENY_ALL_RESOLVER,
|
|
6771
7482
|
DATAFLOW_ERROR_PORT,
|
|
6772
7483
|
DATAFLOW_ALL_PORTS,
|
|
6773
7484
|
CreateWorkflow,
|
|
6774
7485
|
CreateLoopWorkflow,
|
|
6775
7486
|
CreateEndLoopWorkflow,
|
|
6776
7487
|
CreateAdaptiveWorkflow,
|
|
6777
|
-
ConditionalTask
|
|
7488
|
+
ConditionalTask,
|
|
7489
|
+
BROWSER_GRANTS
|
|
6778
7490
|
};
|
|
6779
7491
|
|
|
6780
|
-
//# debugId=
|
|
7492
|
+
//# debugId=B1EF4C881FE1D2EF64756E2164756E21
|