@ductape/sdk 0.1.110 → 0.1.114

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 (69) hide show
  1. package/dist/api/services/processorApi.service.d.ts +2 -0
  2. package/dist/api/services/processorApi.service.js +51 -0
  3. package/dist/api/services/processorApi.service.js.map +1 -1
  4. package/dist/api/services/productsApi.service.d.ts +7 -1
  5. package/dist/api/services/productsApi.service.js.map +1 -1
  6. package/dist/api/urls.d.ts +1 -0
  7. package/dist/api/urls.js +5 -4
  8. package/dist/api/urls.js.map +1 -1
  9. package/dist/context/execution-context.d.ts +37 -0
  10. package/dist/context/execution-context.js +38 -0
  11. package/dist/context/execution-context.js.map +1 -0
  12. package/dist/context/index.d.ts +1 -0
  13. package/dist/context/index.js +18 -0
  14. package/dist/context/index.js.map +1 -0
  15. package/dist/database/adapters/mongodb.adapter.js +7 -7
  16. package/dist/database/adapters/mongodb.adapter.js.map +1 -1
  17. package/dist/database/databases.service.d.ts +4 -0
  18. package/dist/database/databases.service.js +7 -1
  19. package/dist/database/databases.service.js.map +1 -1
  20. package/dist/features/feature-executor.d.ts +19 -0
  21. package/dist/features/feature-executor.js +330 -98
  22. package/dist/features/feature-executor.js.map +1 -1
  23. package/dist/features/features.service.d.ts +21 -1
  24. package/dist/features/features.service.js +136 -33
  25. package/dist/features/features.service.js.map +1 -1
  26. package/dist/features/index.d.ts +2 -1
  27. package/dist/features/index.js +3 -1
  28. package/dist/features/index.js.map +1 -1
  29. package/dist/features/types/features.types.d.ts +17 -2
  30. package/dist/features/types/features.types.js.map +1 -1
  31. package/dist/functions/functions.runtime.d.ts +25 -0
  32. package/dist/functions/functions.runtime.js +278 -0
  33. package/dist/functions/functions.runtime.js.map +1 -0
  34. package/dist/functions/http-handler.d.ts +17 -0
  35. package/dist/functions/http-handler.js +51 -0
  36. package/dist/functions/http-handler.js.map +1 -0
  37. package/dist/functions/index.d.ts +3 -0
  38. package/dist/functions/index.js +20 -0
  39. package/dist/functions/index.js.map +1 -0
  40. package/dist/functions/types.d.ts +100 -0
  41. package/dist/functions/types.js +15 -0
  42. package/dist/functions/types.js.map +1 -0
  43. package/dist/graph/graphs.service.d.ts +1 -1
  44. package/dist/graph/graphs.service.js +73 -43
  45. package/dist/graph/graphs.service.js.map +1 -1
  46. package/dist/graph/types/traversal.interface.d.ts +2 -0
  47. package/dist/index.d.ts +18 -2
  48. package/dist/index.js +27 -3
  49. package/dist/index.js.map +1 -1
  50. package/dist/processor/services/processor.service.d.ts +6 -0
  51. package/dist/processor/services/processor.service.js +8 -13
  52. package/dist/processor/services/processor.service.js.map +1 -1
  53. package/dist/products/bootstrap-cache.js +7 -2
  54. package/dist/products/bootstrap-cache.js.map +1 -1
  55. package/dist/products/services/products.service.d.ts +2 -2
  56. package/dist/products/services/products.service.js +36 -1
  57. package/dist/products/services/products.service.js.map +1 -1
  58. package/dist/sessions/sessions.helper.js +13 -1
  59. package/dist/sessions/sessions.helper.js.map +1 -1
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/dist/types/processor.types.d.ts +15 -0
  62. package/dist/types/processor.types.js.map +1 -1
  63. package/dist/types/productsBuilder.types.d.ts +3 -0
  64. package/dist/types/productsBuilder.types.js +2 -0
  65. package/dist/types/productsBuilder.types.js.map +1 -1
  66. package/dist/vector/vector-database.service.d.ts +2 -0
  67. package/dist/vector/vector-database.service.js +21 -12
  68. package/dist/vector/vector-database.service.js.map +1 -1
  69. package/package.json +1 -1
@@ -43,9 +43,11 @@ var __importStar = (this && this.__importStar) || (function () {
43
43
  var __importDefault = (this && this.__importDefault) || function (mod) {
44
44
  return (mod && mod.__esModule) ? mod : { "default": mod };
45
45
  };
46
+ var _a, _b;
46
47
  Object.defineProperty(exports, "__esModule", { value: true });
47
- exports.featureService = exports.FeatureService = exports.FeatureError = void 0;
48
+ exports.featureService = exports.FeatureCompilationError = exports.FeatureService = exports.FeatureError = void 0;
48
49
  const crypto_1 = require("crypto");
50
+ const functions_1 = require("../functions");
49
51
  const products_service_1 = __importDefault(require("../products/services/products.service"));
50
52
  const processor_service_1 = __importDefault(require("../processor/services/processor.service"));
51
53
  const featureApi_service_1 = require("../api/services/featureApi.service");
@@ -55,6 +57,15 @@ const processor_utils_1 = require("../processor/utils/processor.utils");
55
57
  const cache_manager_1 = require("../cache/cache.manager");
56
58
  const productsBuilder_types_1 = require("../types/productsBuilder.types");
57
59
  const feature_executor_1 = require("./feature-executor");
60
+ // Feature compilation/execution used to emit dozens of synchronous console writes
61
+ // on every request. Preserve the diagnostic stream behind DUCTAPE_DEBUG without
62
+ // charging production feature latency for formatting and stdout I/O.
63
+ const featureDebugEnabled = typeof process !== 'undefined' && (((_a = process.env) === null || _a === void 0 ? void 0 : _a.DUCTAPE_DEBUG) === 'true' || ((_b = process.env) === null || _b === void 0 ? void 0 : _b.DUCTAPE_DEBUG) === '1');
64
+ const console = {
65
+ log: featureDebugEnabled ? globalThis.console.log.bind(globalThis.console) : (..._args) => { },
66
+ warn: globalThis.console.warn.bind(globalThis.console),
67
+ error: globalThis.console.error.bind(globalThis.console),
68
+ };
58
69
  /**
59
70
  * Error class for feature-related errors
60
71
  */
@@ -189,6 +200,7 @@ class FeatureService {
189
200
  user_id: this.config.user_id,
190
201
  token: this.config.token,
191
202
  env_type: this.config.env_type,
203
+ redis_client: this.config.redis_client,
192
204
  access_key: this.config.access_key,
193
205
  workspace_private_key: this._privateKey || undefined,
194
206
  });
@@ -302,7 +314,7 @@ class FeatureService {
302
314
  // Persist to backend using ProductBuilder
303
315
  const builder = await this.getProductBuilder(productTag);
304
316
  console.log('[FeatureService] create calling builder.createFeature', { tag: featureData.tag });
305
- await builder.createFeature(featureData);
317
+ const persisted = await builder.createFeature(featureData);
306
318
  // Store locally
307
319
  const localConfig = {
308
320
  name: featureData.name,
@@ -318,6 +330,12 @@ class FeatureService {
318
330
  };
319
331
  this.localConfigs.set(featureData.tag, localConfig);
320
332
  console.log('[FeatureService] create SUCCESS', { productTag, tag: featureData.tag });
333
+ return persisted;
334
+ }
335
+ /** True only when the remote catalogue read path can observe the feature. */
336
+ async exists(featureTag, productTag) {
337
+ const builder = await this.getProductBuilder(productTag);
338
+ return Boolean(await builder.fetchFeature(featureTag));
321
339
  }
322
340
  /**
323
341
  * Fetch all features for a product
@@ -479,7 +497,16 @@ class FeatureService {
479
497
  // If product is specified, create the feature
480
498
  if (options.product) {
481
499
  console.log('[FeatureService] define creating feature on backend', { product: options.product, tag: schema.tag });
482
- await this.create(options.product, schema);
500
+ const builder = await this.getProductBuilder(options.product);
501
+ const existing = await builder.fetchFeature(schema.tag);
502
+ if (existing)
503
+ await builder.updateFeature(schema.tag, schema);
504
+ else
505
+ await builder.createFeature(schema, true);
506
+ const persisted = await builder.fetchFeature(schema.tag);
507
+ if (!persisted) {
508
+ throw new FeatureError(`Feature ${schema.tag} was acknowledged but is absent from the catalogue read path`, 'FEATURE_CATALOGUE_INCONSISTENT');
509
+ }
483
510
  }
484
511
  // Store locally
485
512
  const localConfig = {
@@ -505,6 +532,56 @@ class FeatureService {
505
532
  schema,
506
533
  };
507
534
  }
535
+ /** Compile several definitions without performing any remote writes. */
536
+ async compileMany(definitions) {
537
+ const tags = definitions.map((definition) => definition.tag);
538
+ const duplicate = tags.find((tag, index) => tags.indexOf(tag) !== index);
539
+ if (duplicate)
540
+ throw FeatureError.validationError(`Duplicate feature tag in batch: ${duplicate}`);
541
+ return Promise.all(definitions.map((definition) => new FeatureCompiler(definition).compileAsync()));
542
+ }
543
+ /**
544
+ * Publish a definition set with read-back verification. If a write fails, newly
545
+ * created records are removed and pre-existing records are restored.
546
+ */
547
+ async publishMany(productTag, definitions, options = {}) {
548
+ const schemas = await this.compileMany(definitions);
549
+ if (options.dryRun)
550
+ return { product: productTag, dry_run: true, features: schemas };
551
+ const builder = await this.getProductBuilder(productTag);
552
+ const previous = new Map();
553
+ const changed = [];
554
+ try {
555
+ for (const schema of schemas) {
556
+ const existing = await builder.fetchFeature(schema.tag);
557
+ previous.set(schema.tag, existing);
558
+ if (existing)
559
+ await builder.updateFeature(schema.tag, schema);
560
+ else
561
+ await builder.createFeature(schema, true);
562
+ const readBack = await builder.fetchFeature(schema.tag);
563
+ if (!readBack)
564
+ throw new Error(`Feature ${schema.tag} is missing after publish`);
565
+ changed.push(schema.tag);
566
+ }
567
+ return { product: productTag, dry_run: false, features: schemas };
568
+ }
569
+ catch (error) {
570
+ for (const tag of changed.reverse()) {
571
+ const old = previous.get(tag);
572
+ try {
573
+ if (old)
574
+ await builder.updateFeature(tag, old);
575
+ else
576
+ await builder.deleteFeature(tag);
577
+ }
578
+ catch (rollbackError) {
579
+ console.error('[Ductape] Feature batch rollback failed', { product: productTag, tag, rollbackError });
580
+ }
581
+ }
582
+ throw error;
583
+ }
584
+ }
508
585
  // ==================== WORKFLOW EXECUTION ====================
509
586
  /**
510
587
  * Execute a feature
@@ -1512,25 +1589,6 @@ function buildConditionFromScenario(scenario) {
1512
1589
  }
1513
1590
  return parts.length === 0 ? '' : parts.join(' && ');
1514
1591
  }
1515
- /** Create ctx.input that prefers recordInput values (for loops/switch) and falls back to $Input{field} for other keys. */
1516
- function createHybridInputProxy(recordInput, inputProxy) {
1517
- const base = recordInput !== null && recordInput !== void 0 ? recordInput : {};
1518
- if (!inputProxy)
1519
- return base;
1520
- return new Proxy(base, {
1521
- get(target, prop) {
1522
- if (typeof prop !== 'string')
1523
- return target[prop];
1524
- if (prop in target && target[prop] !== undefined) {
1525
- return target[prop];
1526
- }
1527
- return inputProxy[prop];
1528
- },
1529
- has(target, prop) {
1530
- return prop in target || (inputProxy && prop in inputProxy);
1531
- },
1532
- });
1533
- }
1534
1592
  class RecordingContext {
1535
1593
  constructor(_input, featureTag, featureInputSchema, stepResultOverrides, scenarioCondition, recordInput) {
1536
1594
  this._steps = [];
@@ -1548,7 +1606,6 @@ class RecordingContext {
1548
1606
  /** When set (from recordScenarios), every step we push gets this condition so it only runs when input matches. */
1549
1607
  this._scenarioCondition = null;
1550
1608
  this._recordInput = null;
1551
- this._hybridInput = null;
1552
1609
  this._featureTag = featureTag;
1553
1610
  this._inputSchemaKeys = featureInputSchema ? Object.keys(featureInputSchema) : [];
1554
1611
  this._stepResultOverrides = stepResultOverrides !== null && stepResultOverrides !== void 0 ? stepResultOverrides : {};
@@ -1557,12 +1614,17 @@ class RecordingContext {
1557
1614
  if (this._inputSchemaKeys.length > 0) {
1558
1615
  this._inputProxy = createInputProxy(this._inputSchemaKeys);
1559
1616
  }
1560
- this._hybridInput = createHybridInputProxy(this._recordInput, this._inputProxy);
1561
1617
  }
1562
- // Readonly feature metadata prefer recordInput for control flow (loops, switch), fall back to $Input{field}
1618
+ // Runtime input is always represented by operators. Sample recording data must
1619
+ // never be allowed to become a production step literal.
1563
1620
  get input() {
1564
- var _a, _b;
1565
- return ((_b = (_a = this._hybridInput) !== null && _a !== void 0 ? _a : this._inputProxy) !== null && _b !== void 0 ? _b : {});
1621
+ var _a;
1622
+ return ((_a = this._inputProxy) !== null && _a !== void 0 ? _a : {});
1623
+ }
1624
+ // Explicit compile-time data for loops and branch discovery.
1625
+ get sampleInput() {
1626
+ var _a;
1627
+ return ((_a = this._recordInput) !== null && _a !== void 0 ? _a : {});
1566
1628
  }
1567
1629
  get feature_id() {
1568
1630
  return `compile-${this._featureTag}`;
@@ -1617,10 +1679,15 @@ class RecordingContext {
1617
1679
  try {
1618
1680
  stepReturn = await handler();
1619
1681
  }
1620
- catch (e) {
1621
- // Ignore errors during compilation - we're just tracing
1682
+ catch (error) {
1683
+ throw new FeatureCompilationError(this._featureTag, tag, `The step callback threw while compiling: ${error instanceof Error ? error.message : String(error)}. ` +
1684
+ 'Feature callbacks may only use serializable ctx primitives or ctx.functions.');
1622
1685
  }
1623
1686
  this._pendingStep = null;
1687
+ if (!step.event) {
1688
+ throw new FeatureCompilationError(this._featureTag, tag, 'The step did not record a portable operation. Arbitrary application callbacks cannot be serialized. ' +
1689
+ 'Use ctx.functions, ctx.action, ctx.database, ctx.events, ctx.storage, ctx.graph, ctx.vector, ctx.quota, or ctx.fallback.');
1690
+ }
1624
1691
  // Parse and store step output in schema (operator strings for downstream $Step{tag}{field} references)
1625
1692
  const valueToCapture = stepReturn !== undefined && stepReturn !== null && typeof stepReturn === 'object' && !Array.isArray(stepReturn)
1626
1693
  ? stepReturn.output !== undefined && stepReturn.process_id !== undefined
@@ -1899,6 +1966,27 @@ class RecordingContext {
1899
1966
  },
1900
1967
  };
1901
1968
  }
1969
+ get functions() {
1970
+ const invoke = async (contract, operation, input) => {
1971
+ const reference = (0, functions_1.referenceFromContract)(contract, operation);
1972
+ this._updateCurrentStep(productsBuilder_types_1.FeatureStepType.FUNCTION, operation, {
1973
+ function_ref: reference,
1974
+ input,
1975
+ options: { timeout: reference.timeout_ms },
1976
+ });
1977
+ return createStepOutputProxy();
1978
+ };
1979
+ return {
1980
+ invoke,
1981
+ use: (contract) => new Proxy({}, {
1982
+ get: (_target, property) => {
1983
+ if (typeof property !== 'string' || !(property in contract.operations))
1984
+ return undefined;
1985
+ return (input) => invoke(contract, property, input);
1986
+ },
1987
+ }),
1988
+ };
1989
+ }
1902
1990
  get transform() {
1903
1991
  return {
1904
1992
  size: (obj) => Object.keys(obj).length,
@@ -2032,6 +2120,8 @@ class RecordingContext {
2032
2120
  step.fallback = data.fallback;
2033
2121
  if (data.feature)
2034
2122
  step.feature = data.feature;
2123
+ if (data.function_ref)
2124
+ step.function_ref = data.function_ref;
2035
2125
  if (data.input) {
2036
2126
  step.input = convertToOperatorInput(data.input, this._inputProxy, this._inputSchemaKeys);
2037
2127
  }
@@ -2150,7 +2240,7 @@ class FeatureCompiler {
2150
2240
  * With recordInput, uses that as ctx.input so loops and control flow see real values.
2151
2241
  */
2152
2242
  async compileAsync() {
2153
- var _a, _b, _c, _d;
2243
+ var _a, _b, _c, _d, _e;
2154
2244
  const scenarios = this.options.recordScenarios && this.options.recordScenarios.length > 0
2155
2245
  ? this.options.recordScenarios
2156
2246
  : [(_a = this.options.recordInput) !== null && _a !== void 0 ? _a : {}];
@@ -2173,7 +2263,11 @@ class FeatureCompiler {
2173
2263
  if (out !== undefined && out !== null)
2174
2264
  handlerOutput = out;
2175
2265
  }
2176
- catch (_) { }
2266
+ catch (error) {
2267
+ if (error instanceof FeatureCompilationError)
2268
+ throw error;
2269
+ throw new FeatureCompilationError(this.options.tag, (_c = recordingCtx.current_step) !== null && _c !== void 0 ? _c : '(handler)', error instanceof Error ? error.message : String(error));
2270
+ }
2177
2271
  for (const s of recordingCtx.getSteps()) {
2178
2272
  const existing = stepsByTag.get(s.tag);
2179
2273
  if (existing) {
@@ -2193,12 +2287,12 @@ class FeatureCompiler {
2193
2287
  const finalSteps = stepOrder.map((tag) => stepsByTag.get(tag)).filter(Boolean);
2194
2288
  const output = handlerOutput !== undefined && handlerOutput !== null && lastCtx
2195
2289
  ? lastCtx.captureOutput(handlerOutput)
2196
- : ((_c = this.options.output) !== null && _c !== void 0 ? _c : {});
2290
+ : ((_d = this.options.output) !== null && _d !== void 0 ? _d : {});
2197
2291
  return {
2198
2292
  name: this.options.name,
2199
2293
  tag: this.options.tag,
2200
2294
  description: this.options.description,
2201
- input: (_d = this.options.input) !== null && _d !== void 0 ? _d : {},
2295
+ input: (_e = this.options.input) !== null && _e !== void 0 ? _e : {},
2202
2296
  output: output,
2203
2297
  steps: finalSteps,
2204
2298
  signals: this.options.signals
@@ -2218,6 +2312,15 @@ class FeatureCompiler {
2218
2312
  };
2219
2313
  }
2220
2314
  }
2315
+ class FeatureCompilationError extends Error {
2316
+ constructor(featureTag, stepTag, message) {
2317
+ super(`Feature "${featureTag}", step "${stepTag}": ${message}`);
2318
+ this.featureTag = featureTag;
2319
+ this.stepTag = stepTag;
2320
+ this.name = 'FeatureCompilationError';
2321
+ }
2322
+ }
2323
+ exports.FeatureCompilationError = FeatureCompilationError;
2221
2324
  // Export singleton instance for convenience
2222
2325
  exports.featureService = new FeatureService();
2223
2326
  // Default export