@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.
Files changed (87) hide show
  1. package/dist/browser.js +899 -187
  2. package/dist/browser.js.map +40 -32
  3. package/dist/bun.js +899 -187
  4. package/dist/bun.js.map +40 -32
  5. package/dist/common.d.ts +2 -0
  6. package/dist/common.d.ts.map +1 -1
  7. package/dist/node.js +899 -187
  8. package/dist/node.js.map +40 -32
  9. package/dist/storage/TaskGraphRepository.d.ts.map +1 -1
  10. package/dist/storage/TaskGraphTabularRepository.d.ts.map +1 -1
  11. package/dist/storage/TaskOutputRepository.d.ts.map +1 -1
  12. package/dist/storage/TaskOutputTabularRepository.d.ts +1 -1
  13. package/dist/storage/TaskOutputTabularRepository.d.ts.map +1 -1
  14. package/dist/task/ConditionalTask.d.ts +7 -2
  15. package/dist/task/ConditionalTask.d.ts.map +1 -1
  16. package/dist/task/EntitlementEnforcer.d.ts +55 -0
  17. package/dist/task/EntitlementEnforcer.d.ts.map +1 -0
  18. package/dist/task/EntitlementPolicy.d.ts +60 -0
  19. package/dist/task/EntitlementPolicy.d.ts.map +1 -0
  20. package/dist/task/EntitlementProfiles.d.ts +49 -0
  21. package/dist/task/EntitlementProfiles.d.ts.map +1 -0
  22. package/dist/task/EntitlementResolver.d.ts +50 -0
  23. package/dist/task/EntitlementResolver.d.ts.map +1 -0
  24. package/dist/task/FallbackTask.d.ts +31 -24
  25. package/dist/task/FallbackTask.d.ts.map +1 -1
  26. package/dist/task/FallbackTaskRunner.d.ts +2 -2
  27. package/dist/task/FallbackTaskRunner.d.ts.map +1 -1
  28. package/dist/task/GraphAsTask.d.ts +18 -6
  29. package/dist/task/GraphAsTask.d.ts.map +1 -1
  30. package/dist/task/GraphAsTaskRunner.d.ts +3 -2
  31. package/dist/task/GraphAsTaskRunner.d.ts.map +1 -1
  32. package/dist/task/ITask.d.ts +12 -1
  33. package/dist/task/ITask.d.ts.map +1 -1
  34. package/dist/task/InputCompactor.d.ts +37 -0
  35. package/dist/task/InputCompactor.d.ts.map +1 -0
  36. package/dist/task/InputResolver.d.ts +19 -1
  37. package/dist/task/InputResolver.d.ts.map +1 -1
  38. package/dist/task/IteratorTask.d.ts +9 -4
  39. package/dist/task/IteratorTask.d.ts.map +1 -1
  40. package/dist/task/IteratorTaskRunner.d.ts +1 -1
  41. package/dist/task/IteratorTaskRunner.d.ts.map +1 -1
  42. package/dist/task/MapTask.d.ts +8 -3
  43. package/dist/task/MapTask.d.ts.map +1 -1
  44. package/dist/task/ReduceTask.d.ts +9 -4
  45. package/dist/task/ReduceTask.d.ts.map +1 -1
  46. package/dist/task/StreamTypes.d.ts +6 -2
  47. package/dist/task/StreamTypes.d.ts.map +1 -1
  48. package/dist/task/Task.d.ts +37 -7
  49. package/dist/task/Task.d.ts.map +1 -1
  50. package/dist/task/TaskEntitlements.d.ts +134 -0
  51. package/dist/task/TaskEntitlements.d.ts.map +1 -0
  52. package/dist/task/TaskError.d.ts +7 -0
  53. package/dist/task/TaskError.d.ts.map +1 -1
  54. package/dist/task/TaskEvents.d.ts +3 -0
  55. package/dist/task/TaskEvents.d.ts.map +1 -1
  56. package/dist/task/TaskJSON.d.ts +18 -5
  57. package/dist/task/TaskJSON.d.ts.map +1 -1
  58. package/dist/task/TaskRegistry.d.ts +16 -3
  59. package/dist/task/TaskRegistry.d.ts.map +1 -1
  60. package/dist/task/TaskRunner.d.ts +5 -4
  61. package/dist/task/TaskRunner.d.ts.map +1 -1
  62. package/dist/task/TaskTypes.d.ts +10 -2
  63. package/dist/task/TaskTypes.d.ts.map +1 -1
  64. package/dist/task/WhileTask.d.ts +8 -4
  65. package/dist/task/WhileTask.d.ts.map +1 -1
  66. package/dist/task/WhileTaskRunner.d.ts +1 -1
  67. package/dist/task/WhileTaskRunner.d.ts.map +1 -1
  68. package/dist/task/index.d.ts +6 -0
  69. package/dist/task/index.d.ts.map +1 -1
  70. package/dist/task/iterationSchema.d.ts +2 -1
  71. package/dist/task/iterationSchema.d.ts.map +1 -1
  72. package/dist/task-graph/Dataflow.d.ts +1 -1
  73. package/dist/task-graph/Dataflow.d.ts.map +1 -1
  74. package/dist/task-graph/GraphEntitlementUtils.d.ts +30 -0
  75. package/dist/task-graph/GraphEntitlementUtils.d.ts.map +1 -0
  76. package/dist/task-graph/GraphFormatScanner.d.ts +41 -0
  77. package/dist/task-graph/GraphFormatScanner.d.ts.map +1 -0
  78. package/dist/task-graph/GraphToWorkflowCode.d.ts.map +1 -1
  79. package/dist/task-graph/TaskGraph.d.ts +23 -5
  80. package/dist/task-graph/TaskGraph.d.ts.map +1 -1
  81. package/dist/task-graph/TaskGraphEvents.d.ts +3 -0
  82. package/dist/task-graph/TaskGraphEvents.d.ts.map +1 -1
  83. package/dist/task-graph/TaskGraphRunner.d.ts +13 -1
  84. package/dist/task-graph/TaskGraphRunner.d.ts.map +1 -1
  85. package/dist/task-graph/Workflow.d.ts +32 -17
  86. package/dist/task-graph/Workflow.d.ts.map +1 -1
  87. 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.set(event.port, event.objectDelta);
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(callerDefaultInputs = {}, config = {}, runConfig = {}) {
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
- }, config);
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().warn(`Condition evaluation failed for branch "${branch.id}":`, { error });
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?.aborted) {
2800
- this.abortController.abort();
2801
- return;
2802
- } else {
2803
- config?.parentSignal?.addEventListener("abort", () => {
3181
+ if (config?.parentSignal) {
3182
+ const onParentAbort = () => {
2804
3183
  this.abortController?.abort();
2805
- }, { once: true });
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
- constructor(input = {}, config = {}) {
3406
+ static hasDynamicEntitlements = true;
3407
+ constructor(config = {}) {
2989
3408
  const { subGraph, ...rest } = config;
2990
- super(input, rest);
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
- resolveWaiting?.();
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
- resolveWaiting?.();
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
- await new Promise((resolve) => {
3093
- resolveWaiting = resolve;
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(input, config) {
3149
- super(input, config);
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({}, config);
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({}, { ...cleanConfig, subGraph: arg });
3667
+ return new _OwnGraphTask({ ...cleanConfig, subGraph: arg });
3224
3668
  } else {
3225
- return new _GraphTask({}, { ...cleanConfig, subGraph: arg });
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({}, { ...cleanConfig, subGraph: arg.graph });
3676
+ return new _OwnWorkflowTask({ ...cleanConfig, subGraph: arg.graph });
3233
3677
  } else {
3234
- return new _ConvWorkflowTask({}, { ...cleanConfig, subGraph: arg.graph });
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(input, config);
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, input, { id: uuid45(), ...config });
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, input, config) {
3949
- const task = new taskClass(input, config);
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, {}, { id: uuid45(), ...config });
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
- const prop = sourceSchema.properties?.[df.sourceTaskPortId];
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 (sourceSchema.required?.includes(df.sourceTaskPortId) && !required.includes(df.targetTaskPortId)) {
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
- for (const fromOutputPortId of Object.keys(fromSchema.properties || {})) {
4162
- if (matches.has(fromOutputPortId))
4163
- continue;
4164
- matches.set(fromOutputPortId, fromOutputPortId);
4165
- graph.addDataflow(new Dataflow(fromTaskId, fromOutputPortId, toTaskId, fromOutputPortId));
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, clonedConfig, task.runConfig);
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 createServiceToken2, globalServiceRegistry as globalServiceRegistry3 } from "@workglow/util";
6092
- var JOB_QUEUE_FACTORY = createServiceToken2("taskgraph.jobQueueFactory");
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(input = {}, config = {}) {
6897
+ constructor(config = {}) {
6258
6898
  const reduceConfig = {
6259
6899
  ...config,
6260
6900
  concurrencyLimit: 1,
6261
6901
  batchSize: 1
6262
6902
  };
6263
- super(input, reduceConfig);
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 createServiceToken3,
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
- if (taskConstructors.has(baseClass.type)) {}
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 = createServiceToken3("task.constructors");
6349
- if (!globalServiceRegistry4.has(TASK_CONSTRUCTORS)) {
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(item.defaults ?? {}, taskConfig, registry ? { registry } : {});
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 createServiceToken4, EventEmitter as EventEmitter7 } from "@workglow/util";
6497
- var TASK_GRAPH_REPOSITORY = createServiceToken4("taskgraph.taskGraphRepository");
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=2758F4534C10DA3764756E2164756E21
7492
+ //# debugId=B1EF4C881FE1D2EF64756E2164756E21