@superatomai/sdk-node 0.0.81-dsp → 0.0.83-dsp

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -52,6 +52,7 @@ __export(index_exports, {
52
52
  UIBlock: () => UIBlock,
53
53
  UILogCollector: () => UILogCollector,
54
54
  UserManager: () => UserManager,
55
+ accessFromConfig: () => accessFromConfig,
55
56
  analyticsClient: () => analyticsClient,
56
57
  answerCatalogForBinding: () => answerCatalogForBinding,
57
58
  answerComponents: () => answerComponents,
@@ -330,7 +331,7 @@ var UserSchema = import_zod3.z.object({
330
331
  password: import_zod3.z.string().min(1, "Password is required"),
331
332
  fullname: import_zod3.z.string().optional(),
332
333
  role: import_zod3.z.string().optional(),
333
- userInfo: import_zod3.z.record(import_zod3.z.unknown()).optional(),
334
+ userInfo: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown()).optional(),
334
335
  wsIds: import_zod3.z.array(import_zod3.z.string()).optional()
335
336
  // Only in memory, not persisted to file
336
337
  });
@@ -358,8 +359,8 @@ var IncomingMessageSchema = import_zod3.z.object({
358
359
  var DataRequestPayloadSchema = import_zod3.z.object({
359
360
  collection: import_zod3.z.string(),
360
361
  op: import_zod3.z.string(),
361
- params: import_zod3.z.record(import_zod3.z.unknown()).optional(),
362
- SA_RUNTIME: import_zod3.z.record(import_zod3.z.unknown()).optional()
362
+ params: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown()).optional(),
363
+ SA_RUNTIME: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown()).optional()
363
364
  });
364
365
  var DataRequestMessageSchema = import_zod3.z.object({
365
366
  id: import_zod3.z.string(),
@@ -456,10 +457,12 @@ var UserPromptSuggestionsMessageSchema = import_zod3.z.object({
456
457
  payload: UserPromptSuggestionsPayloadSchema
457
458
  });
458
459
  var ComponentPropsSchema = import_zod3.z.object({
460
+ // Same runtime schema as under zod 3; the cast keeps zod 3's inferred `{}`, since
461
+ // zod 4 infers z.object({}) as Record<string, never> and `query.sql` stops type-checking.
459
462
  query: import_zod3.z.string().or(import_zod3.z.object({})).nullable().optional(),
460
463
  title: import_zod3.z.string().optional(),
461
464
  description: import_zod3.z.string().optional(),
462
- config: import_zod3.z.record(import_zod3.z.unknown()).optional()
465
+ config: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown()).optional()
463
466
  }).passthrough();
464
467
  var ComponentSchema = import_zod3.z.object({
465
468
  id: import_zod3.z.string(),
@@ -487,8 +490,8 @@ var WorkflowDescriptorSchema = import_zod3.z.object({
487
490
  name: import_zod3.z.string(),
488
491
  description: import_zod3.z.string(),
489
492
  whenToUse: import_zod3.z.string(),
490
- propsSchema: import_zod3.z.record(import_zod3.z.string()),
491
- defaultProps: import_zod3.z.record(import_zod3.z.unknown()).optional()
493
+ propsSchema: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.string()),
494
+ defaultProps: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown()).optional()
492
495
  });
493
496
  var WorkflowsSchema = import_zod3.z.array(WorkflowDescriptorSchema);
494
497
  var WorkflowListResponsePayloadSchema = import_zod3.z.object({
@@ -521,8 +524,9 @@ var ToolSchema = import_zod3.z.object({
521
524
  toolType: import_zod3.z.enum(["source", "direct"]).optional(),
522
525
  /** Full untruncated schema for source agent (all columns visible) */
523
526
  fullSchema: import_zod3.z.string().optional(),
524
- params: import_zod3.z.record(import_zod3.z.string()),
525
- fn: import_zod3.z.function().args(import_zod3.z.any()).returns(import_zod3.z.any()),
527
+ params: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.string()),
528
+ // zod 4: z.function() is no longer a schema, so a tool's handler is checked as a plain callable.
529
+ fn: import_zod3.z.custom((v) => typeof v === "function", { message: "fn must be a function" }),
526
530
  outputSchema: OutputSchema.optional(),
527
531
  // Optional: describes the data structure returned by this tool
528
532
  /** Cache policy. `false` = never cache (live data, write ops). Mirrors HTTP `Cache-Control: no-store`. */
@@ -544,7 +548,7 @@ var UsersRequestPayloadSchema = import_zod3.z.object({
544
548
  password: import_zod3.z.string().optional(),
545
549
  fullname: import_zod3.z.string().optional(),
546
550
  role: import_zod3.z.string().optional(),
547
- userInfo: import_zod3.z.record(import_zod3.z.unknown()).optional(),
551
+ userInfo: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown()).optional(),
548
552
  // Query operation fields
549
553
  filters: UserQueryFiltersSchema.optional(),
550
554
  limit: import_zod3.z.number().optional(),
@@ -563,7 +567,7 @@ var UILogsPayloadSchema = import_zod3.z.object({
563
567
  level: import_zod3.z.enum(["info", "error", "warn", "debug"]),
564
568
  message: import_zod3.z.string(),
565
569
  type: import_zod3.z.enum(["explanation", "query", "general"]).optional(),
566
- data: import_zod3.z.record(import_zod3.z.unknown()).optional()
570
+ data: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown()).optional()
567
571
  }))
568
572
  });
569
573
  var UILogsMessageSchema = import_zod3.z.object({
@@ -681,7 +685,7 @@ var UIBlockSchema = import_zod3.z.object({
681
685
  // DB field name / Legacy field
682
686
  generatedComponentMetadata: ComponentSchema.optional(),
683
687
  // Actual field used by UIBlock class
684
- componentData: import_zod3.z.record(import_zod3.z.any()).optional(),
688
+ componentData: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.any()).optional(),
685
689
  createdAt: import_zod3.z.string().optional(),
686
690
  /**
687
691
  * Which script recipe produced this answer. Set whenever the turn was answered
@@ -692,7 +696,7 @@ var UIBlockSchema = import_zod3.z.object({
692
696
  */
693
697
  scriptBinding: import_zod3.z.object({
694
698
  recipeId: import_zod3.z.string(),
695
- params: import_zod3.z.record(import_zod3.z.any()).optional(),
699
+ params: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.any()).optional(),
696
700
  name: import_zod3.z.string().optional(),
697
701
  columns: import_zod3.z.array(import_zod3.z.string()).optional()
698
702
  }).optional(),
@@ -773,7 +777,7 @@ var ArtifactsRequestPayloadSchema = import_zod3.z.object({
773
777
  id: import_zod3.z.number().optional(),
774
778
  name: import_zod3.z.string().optional(),
775
779
  createdBy: import_zod3.z.string().optional(),
776
- dsl: import_zod3.z.record(import_zod3.z.any()).optional(),
780
+ dsl: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.any()).optional(),
777
781
  status: import_zod3.z.string().optional(),
778
782
  deleted: import_zod3.z.boolean().optional(),
779
783
  limit: import_zod3.z.number().optional(),
@@ -853,7 +857,7 @@ var MenusRequestPayloadSchema = import_zod3.z.object({
853
857
  userMessage: import_zod3.z.string().optional(),
854
858
  parentId: import_zod3.z.number().nullable().optional(),
855
859
  sortOrder: import_zod3.z.number().optional(),
856
- props: import_zod3.z.record(import_zod3.z.unknown()).optional(),
860
+ props: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown()).optional(),
857
861
  isActive: import_zod3.z.boolean().optional(),
858
862
  // Query operation fields
859
863
  filters: MenusQueryFiltersSchema.optional(),
@@ -864,7 +868,7 @@ var MenusRequestPayloadSchema = import_zod3.z.object({
864
868
  id: import_zod3.z.number(),
865
869
  sortOrder: import_zod3.z.number()
866
870
  })).optional(),
867
- menuJson: import_zod3.z.record(import_zod3.z.unknown()).optional(),
871
+ menuJson: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown()).optional(),
868
872
  version: import_zod3.z.number().optional()
869
873
  }).optional()
870
874
  });
@@ -1041,7 +1045,7 @@ var DashComponentSchema = import_zod3.z.object({
1041
1045
  name: import_zod3.z.string(),
1042
1046
  kind: import_zod3.z.string(),
1043
1047
  purpose: import_zod3.z.string(),
1044
- props: import_zod3.z.record(DashComponentPropSchema).optional(),
1048
+ props: import_zod3.z.record(import_zod3.z.string(), DashComponentPropSchema).optional(),
1045
1049
  useWhen: import_zod3.z.string().optional(),
1046
1050
  notes: import_zod3.z.string().optional()
1047
1051
  });
@@ -1948,9 +1952,19 @@ function runWithContext(ctx, fn) {
1948
1952
  return getStorage().run(ctx, fn);
1949
1953
  }
1950
1954
  function runAsUser(user, fn) {
1951
- const { userId, orgId, role, projectId, requestId, policies, graphVersion } = user;
1955
+ const { userId, orgId, role, projectId, requestId, policies, allowedSources, graphVersion } = user;
1952
1956
  return runWithContext(
1953
- { principal: { kind: "user", userId, orgId, role }, projectId, requestId, policies, ...graphVersion !== void 0 ? { graphVersion } : {} },
1957
+ // `allowedSources` is spread in only when given, so an absent restriction
1958
+ // stays absent rather than becoming an explicit `undefined` that a later
1959
+ // `'allowedSources' in ctx` check would read as present.
1960
+ {
1961
+ principal: { kind: "user", userId, orgId, role },
1962
+ projectId,
1963
+ requestId,
1964
+ policies,
1965
+ ...allowedSources !== void 0 ? { allowedSources } : {},
1966
+ ...graphVersion !== void 0 ? { graphVersion } : {}
1967
+ },
1954
1968
  fn
1955
1969
  );
1956
1970
  }
@@ -2632,8 +2646,40 @@ function graphVersionOf(v) {
2632
2646
  if (v === "draft") return "draft";
2633
2647
  return Number.isInteger(v) && v > 0 ? v : void 0;
2634
2648
  }
2649
+ function scopedForm(config2) {
2650
+ if (!config2 || typeof config2 !== "object" || Array.isArray(config2)) return void 0;
2651
+ const c = config2;
2652
+ return "allowedSources" in c || "policies" in c ? c : void 0;
2653
+ }
2654
+ function allowedSourcesFrom(value) {
2655
+ if (value === void 0 || value === null) return null;
2656
+ if (!Array.isArray(value)) {
2657
+ if (!warnedBadSources) {
2658
+ warnedBadSources = true;
2659
+ logger.warn(
2660
+ `[RequestIdentity] "allowedSources" is ${typeof value}, not a list of source ids \u2014 treating it as NO sources rather than all of them. Fix the config: "allowedSources": ["mssql-1a2b"].`
2661
+ );
2662
+ }
2663
+ return [];
2664
+ }
2665
+ const out = [];
2666
+ for (const item of value) {
2667
+ if (typeof item !== "string" || !item.trim()) continue;
2668
+ const id = item.trim();
2669
+ if (!out.includes(id)) out.push(id);
2670
+ }
2671
+ return out;
2672
+ }
2673
+ function accessFromConfig(config2) {
2674
+ const scoped = scopedForm(config2);
2675
+ return {
2676
+ policies: policiesFromConfig(config2),
2677
+ allowedSources: scoped ? allowedSourcesFrom(scoped.allowedSources) : null
2678
+ };
2679
+ }
2635
2680
  function policiesFromConfig(config2) {
2636
- const entries = Array.isArray(config2) ? config2 : [config2];
2681
+ const raw = scopedForm(config2)?.policies ?? config2;
2682
+ const entries = Array.isArray(raw) ? raw : [raw];
2637
2683
  const out = [];
2638
2684
  for (const entry of entries) {
2639
2685
  if (!entry || typeof entry !== "object") continue;
@@ -2676,12 +2722,13 @@ function policiesFromConfig(config2) {
2676
2722
  var warnedUntrusted = false;
2677
2723
  var warnedAnonymous = false;
2678
2724
  var warnedUnlabelled = false;
2725
+ var warnedBadSources = false;
2679
2726
  var announcedVerified = false;
2680
2727
  var reportedIdMismatches = /* @__PURE__ */ new Set();
2681
2728
  function runWithMessageIdentity(message, fn) {
2682
2729
  const verified = message?.authContext;
2683
2730
  const requestId = message?.id;
2684
- const policies = verified ? policiesFromConfig(verified.config) : policiesFromConfig(message?.payload?.config);
2731
+ const { policies, allowedSources } = verified ? accessFromConfig(verified.config) : accessFromConfig(message?.payload?.config);
2685
2732
  if (verified?.userId) {
2686
2733
  const claimedId = message?.payload?.userId;
2687
2734
  if (!announcedVerified) {
@@ -2706,6 +2753,9 @@ function runWithMessageIdentity(message, fn) {
2706
2753
  role: verified.role,
2707
2754
  requestId,
2708
2755
  policies,
2756
+ // `?? undefined` so "no restriction" leaves the key off the context
2757
+ // entirely; `[]` is passed through as the deny-everything it means.
2758
+ allowedSources: allowedSources ?? void 0,
2709
2759
  // Only from the verified context: an unverified message has no say in which graph answers.
2710
2760
  graphVersion: graphVersionOf(verified.graphVersion)
2711
2761
  },
@@ -2720,7 +2770,7 @@ function runWithMessageIdentity(message, fn) {
2720
2770
  "[RequestIdentity] Using the client-supplied payload.userId as the principal \u2014 the relay is not stamping a verified authContext yet, so this identity is NOT trustworthy. Fine for plumbing; do not enable policy enforcement until the relay change lands."
2721
2771
  );
2722
2772
  }
2723
- return runAsUser({ userId: claimed, requestId, policies }, fn);
2773
+ return runAsUser({ userId: claimed, requestId, policies, allowedSources: allowedSources ?? void 0 }, fn);
2724
2774
  }
2725
2775
  if (!warnedAnonymous) {
2726
2776
  warnedAnonymous = true;
@@ -18186,7 +18236,8 @@ function storeScriptDatasetQuery(q, ctx) {
18186
18236
  return queryCache.storeQuery(q.sql, { data, count });
18187
18237
  }
18188
18238
  function buildUserAccessContext(userConfig) {
18189
- const entries = Array.isArray(userConfig) ? userConfig : [userConfig];
18239
+ const config2 = userConfig && !Array.isArray(userConfig) && typeof userConfig === "object" && ("policies" in userConfig || "allowedSources" in userConfig) ? userConfig.policies : userConfig;
18240
+ const entries = Array.isArray(config2) ? config2 : [config2];
18190
18241
  const restrictions = [];
18191
18242
  const prompts = [];
18192
18243
  let anyRestriction = false;
@@ -19692,7 +19743,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
19692
19743
  const parseResult = UserPromptRequestMessageSchema.safeParse(data);
19693
19744
  if (!parseResult.success) {
19694
19745
  const zodError = parseResult.error;
19695
- zodError.errors.forEach((err) => {
19746
+ zodError.issues.forEach((err) => {
19696
19747
  errors.push(`${err.path.join(".")}: ${err.message}`);
19697
19748
  });
19698
19749
  return { success: false, errors };
@@ -24205,7 +24256,7 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
24205
24256
  const parseResult = DashCompRequestMessageSchema.safeParse(data);
24206
24257
  if (!parseResult.success) {
24207
24258
  const zodError = parseResult.error;
24208
- zodError.errors.forEach((err) => {
24259
+ zodError.issues.forEach((err) => {
24209
24260
  errors.push(`${err.path.join(".")}: ${err.message}`);
24210
24261
  });
24211
24262
  return { success: false, errors };
@@ -24376,7 +24427,7 @@ async function handleDashboardAgentRequest(data, collections, sendMessage) {
24376
24427
  console.log("[DashboardAgentReq] Handler invoked. Raw message type/id:", data?.type, data?.id);
24377
24428
  const parseResult = DashboardAgentRequestMessageSchema.safeParse(data);
24378
24429
  if (!parseResult.success) {
24379
- logger.error("[DashboardAgentReq] Invalid message \u2014 failed schema validation:", JSON.stringify(parseResult.error.errors));
24430
+ logger.error("[DashboardAgentReq] Invalid message \u2014 failed schema validation:", JSON.stringify(parseResult.error.issues));
24380
24431
  return;
24381
24432
  }
24382
24433
  const { id, payload, from } = parseResult.data;
@@ -25748,6 +25799,11 @@ fetch(BRIDGE + '/run-tool', {
25748
25799
  // have been shown to you in full, and guessing column names wastes a turn on
25749
25800
  // a failed query. Generated per run \u2014 do not edit.
25750
25801
  const BRIDGE = ${JSON.stringify(opts.bridgeUrl)};
25802
+ // Sent for the same reason ./query sends it. A schema describes the data, so
25803
+ // WHICH tables may be described is the caller's access, not a free question \u2014
25804
+ // without this the bridge cannot tell whose run this is, and a source the run
25805
+ // may not read would be described to it in full.
25806
+ const CONTEXT_TOKEN = ${JSON.stringify(opts.contextToken ?? null)};
25751
25807
 
25752
25808
  const [toolId, ...keywords] = process.argv.slice(2);
25753
25809
  if (!toolId || !keywords.length) {
@@ -25757,7 +25813,10 @@ if (!toolId || !keywords.length) {
25757
25813
 
25758
25814
  fetch(BRIDGE + '/schema-search', {
25759
25815
  method: 'POST',
25760
- headers: { 'content-type': 'application/json' },
25816
+ headers: {
25817
+ 'content-type': 'application/json',
25818
+ ...(CONTEXT_TOKEN ? { 'x-sa-context': CONTEXT_TOKEN } : {}),
25819
+ },
25761
25820
  body: JSON.stringify({ toolId, keywords }),
25762
25821
  })
25763
25822
  .then(async (r) => {
@@ -26223,7 +26282,7 @@ function handleCodingAgentAbort(data, sendMessage) {
26223
26282
  async function handleCodingAgentRequest(data, collections, sendMessage) {
26224
26283
  const parseResult = CodingAgentRequestMessageSchema.safeParse(data);
26225
26284
  if (!parseResult.success) {
26226
- logger.error("[CodingAgentReq] Invalid message:", JSON.stringify(parseResult.error.errors));
26285
+ logger.error("[CodingAgentReq] Invalid message:", JSON.stringify(parseResult.error.issues));
26227
26286
  return;
26228
26287
  }
26229
26288
  const { id, payload, from } = parseResult.data;
@@ -26343,7 +26402,7 @@ async function handleDashBuilderRequest(data, collections, sendMessage) {
26343
26402
  async function handleDashBuilderRequestInner(data, collections, sendMessage) {
26344
26403
  const parsed = DashBuilderRequestMessageSchema.safeParse(data);
26345
26404
  if (!parsed.success) {
26346
- logger.error("[DashBuilderReq] Invalid message:", JSON.stringify(parsed.error.errors));
26405
+ logger.error("[DashBuilderReq] Invalid message:", JSON.stringify(parsed.error.issues));
26347
26406
  return;
26348
26407
  }
26349
26408
  const { id, payload, from } = parsed.data;
@@ -30094,6 +30153,7 @@ var SuperatomSDK = class {
30094
30153
  UIBlock,
30095
30154
  UILogCollector,
30096
30155
  UserManager,
30156
+ accessFromConfig,
30097
30157
  analyticsClient,
30098
30158
  answerCatalogForBinding,
30099
30159
  answerComponents,
package/dist/index.mjs CHANGED
@@ -219,7 +219,7 @@ var UserSchema = z3.object({
219
219
  password: z3.string().min(1, "Password is required"),
220
220
  fullname: z3.string().optional(),
221
221
  role: z3.string().optional(),
222
- userInfo: z3.record(z3.unknown()).optional(),
222
+ userInfo: z3.record(z3.string(), z3.unknown()).optional(),
223
223
  wsIds: z3.array(z3.string()).optional()
224
224
  // Only in memory, not persisted to file
225
225
  });
@@ -247,8 +247,8 @@ var IncomingMessageSchema = z3.object({
247
247
  var DataRequestPayloadSchema = z3.object({
248
248
  collection: z3.string(),
249
249
  op: z3.string(),
250
- params: z3.record(z3.unknown()).optional(),
251
- SA_RUNTIME: z3.record(z3.unknown()).optional()
250
+ params: z3.record(z3.string(), z3.unknown()).optional(),
251
+ SA_RUNTIME: z3.record(z3.string(), z3.unknown()).optional()
252
252
  });
253
253
  var DataRequestMessageSchema = z3.object({
254
254
  id: z3.string(),
@@ -345,10 +345,12 @@ var UserPromptSuggestionsMessageSchema = z3.object({
345
345
  payload: UserPromptSuggestionsPayloadSchema
346
346
  });
347
347
  var ComponentPropsSchema = z3.object({
348
+ // Same runtime schema as under zod 3; the cast keeps zod 3's inferred `{}`, since
349
+ // zod 4 infers z.object({}) as Record<string, never> and `query.sql` stops type-checking.
348
350
  query: z3.string().or(z3.object({})).nullable().optional(),
349
351
  title: z3.string().optional(),
350
352
  description: z3.string().optional(),
351
- config: z3.record(z3.unknown()).optional()
353
+ config: z3.record(z3.string(), z3.unknown()).optional()
352
354
  }).passthrough();
353
355
  var ComponentSchema = z3.object({
354
356
  id: z3.string(),
@@ -376,8 +378,8 @@ var WorkflowDescriptorSchema = z3.object({
376
378
  name: z3.string(),
377
379
  description: z3.string(),
378
380
  whenToUse: z3.string(),
379
- propsSchema: z3.record(z3.string()),
380
- defaultProps: z3.record(z3.unknown()).optional()
381
+ propsSchema: z3.record(z3.string(), z3.string()),
382
+ defaultProps: z3.record(z3.string(), z3.unknown()).optional()
381
383
  });
382
384
  var WorkflowsSchema = z3.array(WorkflowDescriptorSchema);
383
385
  var WorkflowListResponsePayloadSchema = z3.object({
@@ -410,8 +412,9 @@ var ToolSchema = z3.object({
410
412
  toolType: z3.enum(["source", "direct"]).optional(),
411
413
  /** Full untruncated schema for source agent (all columns visible) */
412
414
  fullSchema: z3.string().optional(),
413
- params: z3.record(z3.string()),
414
- fn: z3.function().args(z3.any()).returns(z3.any()),
415
+ params: z3.record(z3.string(), z3.string()),
416
+ // zod 4: z.function() is no longer a schema, so a tool's handler is checked as a plain callable.
417
+ fn: z3.custom((v) => typeof v === "function", { message: "fn must be a function" }),
415
418
  outputSchema: OutputSchema.optional(),
416
419
  // Optional: describes the data structure returned by this tool
417
420
  /** Cache policy. `false` = never cache (live data, write ops). Mirrors HTTP `Cache-Control: no-store`. */
@@ -433,7 +436,7 @@ var UsersRequestPayloadSchema = z3.object({
433
436
  password: z3.string().optional(),
434
437
  fullname: z3.string().optional(),
435
438
  role: z3.string().optional(),
436
- userInfo: z3.record(z3.unknown()).optional(),
439
+ userInfo: z3.record(z3.string(), z3.unknown()).optional(),
437
440
  // Query operation fields
438
441
  filters: UserQueryFiltersSchema.optional(),
439
442
  limit: z3.number().optional(),
@@ -452,7 +455,7 @@ var UILogsPayloadSchema = z3.object({
452
455
  level: z3.enum(["info", "error", "warn", "debug"]),
453
456
  message: z3.string(),
454
457
  type: z3.enum(["explanation", "query", "general"]).optional(),
455
- data: z3.record(z3.unknown()).optional()
458
+ data: z3.record(z3.string(), z3.unknown()).optional()
456
459
  }))
457
460
  });
458
461
  var UILogsMessageSchema = z3.object({
@@ -570,7 +573,7 @@ var UIBlockSchema = z3.object({
570
573
  // DB field name / Legacy field
571
574
  generatedComponentMetadata: ComponentSchema.optional(),
572
575
  // Actual field used by UIBlock class
573
- componentData: z3.record(z3.any()).optional(),
576
+ componentData: z3.record(z3.string(), z3.any()).optional(),
574
577
  createdAt: z3.string().optional(),
575
578
  /**
576
579
  * Which script recipe produced this answer. Set whenever the turn was answered
@@ -581,7 +584,7 @@ var UIBlockSchema = z3.object({
581
584
  */
582
585
  scriptBinding: z3.object({
583
586
  recipeId: z3.string(),
584
- params: z3.record(z3.any()).optional(),
587
+ params: z3.record(z3.string(), z3.any()).optional(),
585
588
  name: z3.string().optional(),
586
589
  columns: z3.array(z3.string()).optional()
587
590
  }).optional(),
@@ -662,7 +665,7 @@ var ArtifactsRequestPayloadSchema = z3.object({
662
665
  id: z3.number().optional(),
663
666
  name: z3.string().optional(),
664
667
  createdBy: z3.string().optional(),
665
- dsl: z3.record(z3.any()).optional(),
668
+ dsl: z3.record(z3.string(), z3.any()).optional(),
666
669
  status: z3.string().optional(),
667
670
  deleted: z3.boolean().optional(),
668
671
  limit: z3.number().optional(),
@@ -742,7 +745,7 @@ var MenusRequestPayloadSchema = z3.object({
742
745
  userMessage: z3.string().optional(),
743
746
  parentId: z3.number().nullable().optional(),
744
747
  sortOrder: z3.number().optional(),
745
- props: z3.record(z3.unknown()).optional(),
748
+ props: z3.record(z3.string(), z3.unknown()).optional(),
746
749
  isActive: z3.boolean().optional(),
747
750
  // Query operation fields
748
751
  filters: MenusQueryFiltersSchema.optional(),
@@ -753,7 +756,7 @@ var MenusRequestPayloadSchema = z3.object({
753
756
  id: z3.number(),
754
757
  sortOrder: z3.number()
755
758
  })).optional(),
756
- menuJson: z3.record(z3.unknown()).optional(),
759
+ menuJson: z3.record(z3.string(), z3.unknown()).optional(),
757
760
  version: z3.number().optional()
758
761
  }).optional()
759
762
  });
@@ -930,7 +933,7 @@ var DashComponentSchema = z3.object({
930
933
  name: z3.string(),
931
934
  kind: z3.string(),
932
935
  purpose: z3.string(),
933
- props: z3.record(DashComponentPropSchema).optional(),
936
+ props: z3.record(z3.string(), DashComponentPropSchema).optional(),
934
937
  useWhen: z3.string().optional(),
935
938
  notes: z3.string().optional()
936
939
  });
@@ -1837,9 +1840,19 @@ function runWithContext(ctx, fn) {
1837
1840
  return getStorage().run(ctx, fn);
1838
1841
  }
1839
1842
  function runAsUser(user, fn) {
1840
- const { userId, orgId, role, projectId, requestId, policies, graphVersion } = user;
1843
+ const { userId, orgId, role, projectId, requestId, policies, allowedSources, graphVersion } = user;
1841
1844
  return runWithContext(
1842
- { principal: { kind: "user", userId, orgId, role }, projectId, requestId, policies, ...graphVersion !== void 0 ? { graphVersion } : {} },
1845
+ // `allowedSources` is spread in only when given, so an absent restriction
1846
+ // stays absent rather than becoming an explicit `undefined` that a later
1847
+ // `'allowedSources' in ctx` check would read as present.
1848
+ {
1849
+ principal: { kind: "user", userId, orgId, role },
1850
+ projectId,
1851
+ requestId,
1852
+ policies,
1853
+ ...allowedSources !== void 0 ? { allowedSources } : {},
1854
+ ...graphVersion !== void 0 ? { graphVersion } : {}
1855
+ },
1843
1856
  fn
1844
1857
  );
1845
1858
  }
@@ -2521,8 +2534,40 @@ function graphVersionOf(v) {
2521
2534
  if (v === "draft") return "draft";
2522
2535
  return Number.isInteger(v) && v > 0 ? v : void 0;
2523
2536
  }
2537
+ function scopedForm(config2) {
2538
+ if (!config2 || typeof config2 !== "object" || Array.isArray(config2)) return void 0;
2539
+ const c = config2;
2540
+ return "allowedSources" in c || "policies" in c ? c : void 0;
2541
+ }
2542
+ function allowedSourcesFrom(value) {
2543
+ if (value === void 0 || value === null) return null;
2544
+ if (!Array.isArray(value)) {
2545
+ if (!warnedBadSources) {
2546
+ warnedBadSources = true;
2547
+ logger.warn(
2548
+ `[RequestIdentity] "allowedSources" is ${typeof value}, not a list of source ids \u2014 treating it as NO sources rather than all of them. Fix the config: "allowedSources": ["mssql-1a2b"].`
2549
+ );
2550
+ }
2551
+ return [];
2552
+ }
2553
+ const out = [];
2554
+ for (const item of value) {
2555
+ if (typeof item !== "string" || !item.trim()) continue;
2556
+ const id = item.trim();
2557
+ if (!out.includes(id)) out.push(id);
2558
+ }
2559
+ return out;
2560
+ }
2561
+ function accessFromConfig(config2) {
2562
+ const scoped = scopedForm(config2);
2563
+ return {
2564
+ policies: policiesFromConfig(config2),
2565
+ allowedSources: scoped ? allowedSourcesFrom(scoped.allowedSources) : null
2566
+ };
2567
+ }
2524
2568
  function policiesFromConfig(config2) {
2525
- const entries = Array.isArray(config2) ? config2 : [config2];
2569
+ const raw = scopedForm(config2)?.policies ?? config2;
2570
+ const entries = Array.isArray(raw) ? raw : [raw];
2526
2571
  const out = [];
2527
2572
  for (const entry of entries) {
2528
2573
  if (!entry || typeof entry !== "object") continue;
@@ -2565,12 +2610,13 @@ function policiesFromConfig(config2) {
2565
2610
  var warnedUntrusted = false;
2566
2611
  var warnedAnonymous = false;
2567
2612
  var warnedUnlabelled = false;
2613
+ var warnedBadSources = false;
2568
2614
  var announcedVerified = false;
2569
2615
  var reportedIdMismatches = /* @__PURE__ */ new Set();
2570
2616
  function runWithMessageIdentity(message, fn) {
2571
2617
  const verified = message?.authContext;
2572
2618
  const requestId = message?.id;
2573
- const policies = verified ? policiesFromConfig(verified.config) : policiesFromConfig(message?.payload?.config);
2619
+ const { policies, allowedSources } = verified ? accessFromConfig(verified.config) : accessFromConfig(message?.payload?.config);
2574
2620
  if (verified?.userId) {
2575
2621
  const claimedId = message?.payload?.userId;
2576
2622
  if (!announcedVerified) {
@@ -2595,6 +2641,9 @@ function runWithMessageIdentity(message, fn) {
2595
2641
  role: verified.role,
2596
2642
  requestId,
2597
2643
  policies,
2644
+ // `?? undefined` so "no restriction" leaves the key off the context
2645
+ // entirely; `[]` is passed through as the deny-everything it means.
2646
+ allowedSources: allowedSources ?? void 0,
2598
2647
  // Only from the verified context: an unverified message has no say in which graph answers.
2599
2648
  graphVersion: graphVersionOf(verified.graphVersion)
2600
2649
  },
@@ -2609,7 +2658,7 @@ function runWithMessageIdentity(message, fn) {
2609
2658
  "[RequestIdentity] Using the client-supplied payload.userId as the principal \u2014 the relay is not stamping a verified authContext yet, so this identity is NOT trustworthy. Fine for plumbing; do not enable policy enforcement until the relay change lands."
2610
2659
  );
2611
2660
  }
2612
- return runAsUser({ userId: claimed, requestId, policies }, fn);
2661
+ return runAsUser({ userId: claimed, requestId, policies, allowedSources: allowedSources ?? void 0 }, fn);
2613
2662
  }
2614
2663
  if (!warnedAnonymous) {
2615
2664
  warnedAnonymous = true;
@@ -18075,7 +18124,8 @@ function storeScriptDatasetQuery(q, ctx) {
18075
18124
  return queryCache.storeQuery(q.sql, { data, count });
18076
18125
  }
18077
18126
  function buildUserAccessContext(userConfig) {
18078
- const entries = Array.isArray(userConfig) ? userConfig : [userConfig];
18127
+ const config2 = userConfig && !Array.isArray(userConfig) && typeof userConfig === "object" && ("policies" in userConfig || "allowedSources" in userConfig) ? userConfig.policies : userConfig;
18128
+ const entries = Array.isArray(config2) ? config2 : [config2];
18079
18129
  const restrictions = [];
18080
18130
  const prompts = [];
18081
18131
  let anyRestriction = false;
@@ -19581,7 +19631,7 @@ var get_user_request = async (data, components, sendMessage, anthropicApiKey, gr
19581
19631
  const parseResult = UserPromptRequestMessageSchema.safeParse(data);
19582
19632
  if (!parseResult.success) {
19583
19633
  const zodError = parseResult.error;
19584
- zodError.errors.forEach((err) => {
19634
+ zodError.issues.forEach((err) => {
19585
19635
  errors.push(`${err.path.join(".")}: ${err.message}`);
19586
19636
  });
19587
19637
  return { success: false, errors };
@@ -24094,7 +24144,7 @@ var processDashCompRequest = async (data, components, _sendMessage, anthropicApi
24094
24144
  const parseResult = DashCompRequestMessageSchema.safeParse(data);
24095
24145
  if (!parseResult.success) {
24096
24146
  const zodError = parseResult.error;
24097
- zodError.errors.forEach((err) => {
24147
+ zodError.issues.forEach((err) => {
24098
24148
  errors.push(`${err.path.join(".")}: ${err.message}`);
24099
24149
  });
24100
24150
  return { success: false, errors };
@@ -24265,7 +24315,7 @@ async function handleDashboardAgentRequest(data, collections, sendMessage) {
24265
24315
  console.log("[DashboardAgentReq] Handler invoked. Raw message type/id:", data?.type, data?.id);
24266
24316
  const parseResult = DashboardAgentRequestMessageSchema.safeParse(data);
24267
24317
  if (!parseResult.success) {
24268
- logger.error("[DashboardAgentReq] Invalid message \u2014 failed schema validation:", JSON.stringify(parseResult.error.errors));
24318
+ logger.error("[DashboardAgentReq] Invalid message \u2014 failed schema validation:", JSON.stringify(parseResult.error.issues));
24269
24319
  return;
24270
24320
  }
24271
24321
  const { id, payload, from } = parseResult.data;
@@ -25637,6 +25687,11 @@ fetch(BRIDGE + '/run-tool', {
25637
25687
  // have been shown to you in full, and guessing column names wastes a turn on
25638
25688
  // a failed query. Generated per run \u2014 do not edit.
25639
25689
  const BRIDGE = ${JSON.stringify(opts.bridgeUrl)};
25690
+ // Sent for the same reason ./query sends it. A schema describes the data, so
25691
+ // WHICH tables may be described is the caller's access, not a free question \u2014
25692
+ // without this the bridge cannot tell whose run this is, and a source the run
25693
+ // may not read would be described to it in full.
25694
+ const CONTEXT_TOKEN = ${JSON.stringify(opts.contextToken ?? null)};
25640
25695
 
25641
25696
  const [toolId, ...keywords] = process.argv.slice(2);
25642
25697
  if (!toolId || !keywords.length) {
@@ -25646,7 +25701,10 @@ if (!toolId || !keywords.length) {
25646
25701
 
25647
25702
  fetch(BRIDGE + '/schema-search', {
25648
25703
  method: 'POST',
25649
- headers: { 'content-type': 'application/json' },
25704
+ headers: {
25705
+ 'content-type': 'application/json',
25706
+ ...(CONTEXT_TOKEN ? { 'x-sa-context': CONTEXT_TOKEN } : {}),
25707
+ },
25650
25708
  body: JSON.stringify({ toolId, keywords }),
25651
25709
  })
25652
25710
  .then(async (r) => {
@@ -26112,7 +26170,7 @@ function handleCodingAgentAbort(data, sendMessage) {
26112
26170
  async function handleCodingAgentRequest(data, collections, sendMessage) {
26113
26171
  const parseResult = CodingAgentRequestMessageSchema.safeParse(data);
26114
26172
  if (!parseResult.success) {
26115
- logger.error("[CodingAgentReq] Invalid message:", JSON.stringify(parseResult.error.errors));
26173
+ logger.error("[CodingAgentReq] Invalid message:", JSON.stringify(parseResult.error.issues));
26116
26174
  return;
26117
26175
  }
26118
26176
  const { id, payload, from } = parseResult.data;
@@ -26232,7 +26290,7 @@ async function handleDashBuilderRequest(data, collections, sendMessage) {
26232
26290
  async function handleDashBuilderRequestInner(data, collections, sendMessage) {
26233
26291
  const parsed = DashBuilderRequestMessageSchema.safeParse(data);
26234
26292
  if (!parsed.success) {
26235
- logger.error("[DashBuilderReq] Invalid message:", JSON.stringify(parsed.error.errors));
26293
+ logger.error("[DashBuilderReq] Invalid message:", JSON.stringify(parsed.error.issues));
26236
26294
  return;
26237
26295
  }
26238
26296
  const { id, payload, from } = parsed.data;
@@ -29982,6 +30040,7 @@ export {
29982
30040
  UIBlock,
29983
30041
  UILogCollector,
29984
30042
  UserManager,
30043
+ accessFromConfig,
29985
30044
  analyticsClient,
29986
30045
  answerCatalogForBinding,
29987
30046
  answerComponents,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superatomai/sdk-node",
3
- "version": "0.0.81-dsp",
3
+ "version": "0.0.83-dsp",
4
4
  "description": "Node.js TypeScript SDK for Superatom",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -41,7 +41,7 @@
41
41
  "openai": "^4.77.0",
42
42
  "typebox": "^1.1.38",
43
43
  "ws": "^8.21.0",
44
- "zod": "^3.25.76"
44
+ "zod": "^4.6.6"
45
45
  },
46
46
  "optionalDependencies": {
47
47
  "@openai/codex-sdk": "0.156.1"