@bpmsoftwaresolutions/ai-engine-client 1.1.36 → 1.1.38

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +118 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bpmsoftwaresolutions/ai-engine-client",
3
- "version": "1.1.36",
3
+ "version": "1.1.38",
4
4
  "description": "Thin npm client for the AI Engine operator and retrieval APIs",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const DEFAULT_TIMEOUT_MS = 30000;
2
- export const AI_ENGINE_CLIENT_VERSION = '1.1.36';
2
+ export const AI_ENGINE_CLIENT_VERSION = '1.1.38';
3
3
  export const GOVERNED_MUTATION_REQUIRED_CAPABILITIES = [
4
4
  'executeVerifiedMutation',
5
5
  'post_mutation_verification',
@@ -114,6 +114,11 @@ function cleanText(value) {
114
114
  return text || null;
115
115
  }
116
116
 
117
+ function looksLikeUuid(value) {
118
+ const text = cleanText(value);
119
+ return Boolean(text && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(text));
120
+ }
121
+
117
122
  function countRoadmapProjectionLines(markdown) {
118
123
  const lines = [];
119
124
  let inSummary = false;
@@ -291,6 +296,15 @@ export class AIEngineClient {
291
296
  submitArtifact: (scriptId, payload) => this.submitScriptArtifact(scriptId, payload),
292
297
  getRunEvidence: (query) => this.getScriptRunEvidence(query),
293
298
  };
299
+ this.reports = {
300
+ run: (request) => this.runReportDefinition(request),
301
+ };
302
+ this.projections = {
303
+ render: (request) => this.renderProjection(request),
304
+ };
305
+ this.actions = {
306
+ submit: (request) => this.submitActionIntent(request),
307
+ };
294
308
  }
295
309
 
296
310
  static fromEnv(options = {}) {
@@ -373,6 +387,101 @@ export class AIEngineClient {
373
387
  return this._request('/api/v1/latest-memory-projection');
374
388
  }
375
389
 
390
+ // ─── Data Access Gateway ──────────────────────────────────────────────────
391
+
392
+ async query({
393
+ surface,
394
+ contractKey,
395
+ parameters = {},
396
+ fields = [],
397
+ fieldAllowlist = [],
398
+ actorScopes = [],
399
+ requiredScopes = [],
400
+ shape = 'json',
401
+ requestedBy,
402
+ } = {}) {
403
+ const normalizedSurface = cleanText(surface) || cleanText(contractKey);
404
+ if (!normalizedSurface) {
405
+ throw new Error('surface is required.');
406
+ }
407
+ const normalizedShape = cleanText(shape) || 'json';
408
+ if (!['json', 'table', 'cards', 'markdown'].includes(normalizedShape)) {
409
+ throw new Error('shape must be one of json, table, cards, or markdown.');
410
+ }
411
+ const normalizedFields = cleanList(fields);
412
+ const normalizedAllowlist = cleanList(fieldAllowlist);
413
+ const disallowedFields = normalizedFields.filter((field) => !normalizedAllowlist.includes(field));
414
+ if (normalizedAllowlist.length > 0 && disallowedFields.length > 0) {
415
+ throw new Error(`Requested fields are not allowed: ${disallowedFields.join(', ')}.`);
416
+ }
417
+ const normalizedActorScopes = cleanList(actorScopes);
418
+ const normalizedRequiredScopes = cleanList(requiredScopes);
419
+ const missingScopes = normalizedRequiredScopes.filter((scope) => !normalizedActorScopes.includes(scope));
420
+ if (missingScopes.length > 0) {
421
+ throw new Error(`Missing required scopes: ${missingScopes.join(', ')}.`);
422
+ }
423
+ return this._request('/api/gateway/query', {
424
+ method: 'POST',
425
+ body: {
426
+ surface: normalizedSurface,
427
+ parameters: isPlainObject(parameters) ? parameters : {},
428
+ fields: normalizedFields,
429
+ field_allowlist: normalizedAllowlist,
430
+ actor_scopes: normalizedActorScopes,
431
+ required_scopes: normalizedRequiredScopes,
432
+ shape: normalizedShape,
433
+ requested_by: cleanText(requestedBy),
434
+ },
435
+ });
436
+ }
437
+
438
+ async runReportDefinition({ reportKey, definition = {}, requestedBy } = {}) {
439
+ const normalizedReportKey = cleanText(reportKey);
440
+ if (!normalizedReportKey) {
441
+ throw new Error('reportKey is required.');
442
+ }
443
+ return this._request('/api/gateway/reports/run', {
444
+ method: 'POST',
445
+ body: {
446
+ report_key: normalizedReportKey,
447
+ definition: isPlainObject(definition) ? definition : {},
448
+ requested_by: cleanText(requestedBy),
449
+ },
450
+ });
451
+ }
452
+
453
+ async renderProjection({ projectionType, viewContract = {}, requestedBy } = {}) {
454
+ const normalizedProjectionType = cleanText(projectionType);
455
+ if (!normalizedProjectionType) {
456
+ throw new Error('projectionType is required.');
457
+ }
458
+ return this._request('/api/gateway/projections/render', {
459
+ method: 'POST',
460
+ body: {
461
+ projection_type: normalizedProjectionType,
462
+ view_contract: isPlainObject(viewContract) ? viewContract : {},
463
+ requested_by: cleanText(requestedBy),
464
+ },
465
+ });
466
+ }
467
+
468
+ async submitActionIntent({ action, target = {}, payload = {}, requiredScope, requestedBy } = {}) {
469
+ const normalizedAction = cleanText(action);
470
+ if (!normalizedAction) {
471
+ throw new Error('action is required.');
472
+ }
473
+ return this._request('/api/gateway/actions/submit', {
474
+ method: 'POST',
475
+ body: {
476
+ action: normalizedAction,
477
+ target: isPlainObject(target) ? target : {},
478
+ payload: isPlainObject(payload) ? payload : {},
479
+ required_scope: cleanText(requiredScope) || 'ai-engine.write',
480
+ requested_by: cleanText(requestedBy),
481
+ },
482
+ });
483
+ }
484
+
376
485
  async currentProjectStatus({ projectId } = {}) {
377
486
  return this._request('/api/operator/current-project-status', {
378
487
  query: { project_id: projectId },
@@ -1674,6 +1783,14 @@ export class AIEngineClient {
1674
1783
  ...packetPayload,
1675
1784
  imported_by: normalizedImportedBy,
1676
1785
  });
1786
+ const packetId = cleanText(importedPacket?.packet_id || importedPacket?.packetId || importedPacket?.implementation_packet_key || importedPacket?.implementationPacketKey || packetPayload.packetId || packetPayload.packet_id);
1787
+ const implementationPacketId = cleanText(importedPacket?.implementation_packet_id || importedPacket?.implementationPacketId);
1788
+ if (!implementationPacketId) {
1789
+ throw new Error('Imported implementation packet response must include implementation_packet_id.');
1790
+ }
1791
+ if (!looksLikeUuid(implementationPacketId)) {
1792
+ throw new Error('Imported implementation packet response returned a non-UUID implementation_packet_id.');
1793
+ }
1677
1794
  const projectReference = this._resolveImplementationPacketProjectReference(packetPayload);
1678
1795
  if (!projectReference) {
1679
1796
  throw new Error('Could not resolve a project reference from the packet payload.');
@@ -1694,8 +1811,6 @@ export class AIEngineClient {
1694
1811
  }
1695
1812
  const resolvedWorkflowId = await this._resolveImplementationPacketWorkflowId(workflowReference);
1696
1813
  const workflowSlug = cleanText(projectSummary.workflow_slug);
1697
- const packetId = cleanText(importedPacket?.packet_id || importedPacket?.packetId || importedPacket?.implementation_packet_key || importedPacket?.implementationPacketKey || packetPayload.packetId || packetPayload.packet_id);
1698
- const implementationPacketId = cleanText(importedPacket?.implementation_packet_id || importedPacket?.implementationPacketId || packetId);
1699
1814
 
1700
1815
  const binding = await this.bindImplementationPacketToWorkflow(resolvedWorkflowId, {
1701
1816
  packet_id: packetId,