@superatomai/sdk-node 0.0.88-dsp → 0.0.89-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
@@ -62,6 +62,7 @@ __export(index_exports, {
62
62
  bridgePreamble: () => bridgePreamble,
63
63
  captureContext: () => captureContext,
64
64
  clearContextTokens: () => clearContextTokens,
65
+ constraintPoliciesFromConfig: () => constraintPoliciesFromConfig,
65
66
  contextTokenCount: () => contextTokenCount,
66
67
  createCodexSession: () => createCodexSession,
67
68
  createCodingAgentSession: () => createCodingAgentSession,
@@ -1952,7 +1953,17 @@ function runWithContext(ctx, fn) {
1952
1953
  return getStorage().run(ctx, fn);
1953
1954
  }
1954
1955
  function runAsUser(user, fn) {
1955
- const { userId, orgId, role, projectId, requestId, policies, allowedSources, graphVersion } = user;
1956
+ const {
1957
+ userId,
1958
+ orgId,
1959
+ role,
1960
+ projectId,
1961
+ requestId,
1962
+ policies,
1963
+ constraintPolicies,
1964
+ allowedSources,
1965
+ graphVersion
1966
+ } = user;
1956
1967
  return runWithContext(
1957
1968
  // `allowedSources` is spread in only when given, so an absent restriction
1958
1969
  // stays absent rather than becoming an explicit `undefined` that a later
@@ -1962,6 +1973,7 @@ function runAsUser(user, fn) {
1962
1973
  projectId,
1963
1974
  requestId,
1964
1975
  policies,
1976
+ ...constraintPolicies?.length ? { constraintPolicies } : {},
1965
1977
  ...allowedSources !== void 0 ? { allowedSources } : {},
1966
1978
  ...graphVersion !== void 0 ? { graphVersion } : {}
1967
1979
  },
@@ -2642,42 +2654,148 @@ function buildDirectToolCacheKey(toolId, parameters) {
2642
2654
  return `et-direct:${toolId}:${stableStringify(parameters || {})}`;
2643
2655
  }
2644
2656
 
2645
- // src/handlers/request-identity.ts
2646
- function graphVersionOf(v) {
2647
- if (v === "draft") return "draft";
2648
- return Number.isInteger(v) && v > 0 ? v : void 0;
2657
+ // src/handlers/data-access/v2/policies.ts
2658
+ var CONSTRAINT_OPS = [
2659
+ "in",
2660
+ "not_in",
2661
+ "eq",
2662
+ "ne",
2663
+ "gt",
2664
+ "gte",
2665
+ "lt",
2666
+ "lte",
2667
+ "like",
2668
+ "not_like",
2669
+ "is_null",
2670
+ "is_not_null"
2671
+ ];
2672
+ var NO_VALUE_OPS = /* @__PURE__ */ new Set(["is_null", "is_not_null"]);
2673
+ function constraintPoliciesFromConfig(raw) {
2674
+ const entries = Array.isArray(raw) ? raw : [raw];
2675
+ const out = [];
2676
+ for (const entry of entries) {
2677
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
2678
+ const e = entry;
2679
+ const sourceId = typeof e.sourceId === "string" && e.sourceId ? e.sourceId : null;
2680
+ const label = typeof e.label === "string" && e.label.trim() ? e.label.trim() : void 0;
2681
+ const bad = (why) => ({ sourceId, label, invalid: why });
2682
+ let schema2;
2683
+ if (e.schema !== void 0 && e.schema !== null) {
2684
+ if (typeof e.schema !== "string" || !e.schema.trim()) {
2685
+ out.push(bad("schema must be a schema name"));
2686
+ continue;
2687
+ }
2688
+ schema2 = e.schema.trim();
2689
+ }
2690
+ let readableTables;
2691
+ let tablesBad;
2692
+ if (e.readableTables !== void 0 && e.readableTables !== null) {
2693
+ if (typeof e.readableTables !== "object" || Array.isArray(e.readableTables)) {
2694
+ out.push(bad("readableTables must be an object of table to columns"));
2695
+ continue;
2696
+ }
2697
+ readableTables = {};
2698
+ for (const [table, cols] of Object.entries(e.readableTables)) {
2699
+ if (cols === null) {
2700
+ readableTables[table] = null;
2701
+ continue;
2702
+ }
2703
+ if (!Array.isArray(cols) || cols.length === 0) {
2704
+ tablesBad = `readableTables["${table}"] must be a non-empty list or null`;
2705
+ break;
2706
+ }
2707
+ const columns = cols.filter((c) => typeof c === "string" && !!c.trim()).map((c) => c.trim());
2708
+ if (columns.length !== cols.length) {
2709
+ tablesBad = `readableTables["${table}"] has an entry that is not a column name`;
2710
+ break;
2711
+ }
2712
+ readableTables[table] = columns;
2713
+ }
2714
+ if (!tablesBad && Object.keys(readableTables).length === 0) {
2715
+ tablesBad = "readableTables names no tables \u2014 omit it to allow every table";
2716
+ }
2717
+ if (tablesBad) {
2718
+ out.push(bad(tablesBad));
2719
+ continue;
2720
+ }
2721
+ }
2722
+ const rowFilters = {};
2723
+ let filtersBad;
2724
+ const rawFilters = e.rowFilters;
2725
+ if (rawFilters !== void 0 && rawFilters !== null) {
2726
+ if (typeof rawFilters !== "object" || Array.isArray(rawFilters)) {
2727
+ filtersBad = "rowFilters must be an object keyed by table";
2728
+ } else {
2729
+ for (const [table, items] of Object.entries(rawFilters)) {
2730
+ if (readableTables && !(table in readableTables)) {
2731
+ filtersBad = `rowFilters names "${table}", which readableTables does not allow`;
2732
+ break;
2733
+ }
2734
+ if (!Array.isArray(items) || items.length === 0) {
2735
+ filtersBad = `rowFilters["${table}"] must be a non-empty list`;
2736
+ break;
2737
+ }
2738
+ const parsed = [];
2739
+ for (const item of items) {
2740
+ if (!item || typeof item !== "object") {
2741
+ filtersBad = `rowFilters["${table}"] has an entry that is not an object`;
2742
+ break;
2743
+ }
2744
+ const f = item;
2745
+ if (typeof f.column !== "string" || !f.column.trim()) {
2746
+ filtersBad = `a filter on "${table}" has no column`;
2747
+ break;
2748
+ }
2749
+ const op = typeof f.op === "string" ? f.op.toLowerCase() : "in";
2750
+ if (!CONSTRAINT_OPS.includes(op)) {
2751
+ filtersBad = `unsupported operator "${f.op}" on "${table}.${f.column}"`;
2752
+ break;
2753
+ }
2754
+ const values = Array.isArray(f.values) ? f.values : [];
2755
+ if (!NO_VALUE_OPS.has(op) && values.length === 0) {
2756
+ filtersBad = `the filter on "${table}.${f.column}" has no values`;
2757
+ break;
2758
+ }
2759
+ parsed.push({
2760
+ column: f.column.trim(),
2761
+ op,
2762
+ ...NO_VALUE_OPS.has(op) ? {} : { values },
2763
+ label: typeof f.label === "string" && f.label.trim() ? f.label.trim() : void 0
2764
+ });
2765
+ }
2766
+ if (filtersBad) break;
2767
+ rowFilters[table] = parsed;
2768
+ }
2769
+ }
2770
+ }
2771
+ if (filtersBad) {
2772
+ out.push(bad(filtersBad));
2773
+ continue;
2774
+ }
2775
+ const rawLimits = e.limits;
2776
+ const num = (v) => typeof v === "number" && Number.isInteger(v) && v > 0 ? v : void 0;
2777
+ const limits = rawLimits ? { maxRows: num(rawLimits.maxRows), maxExecutionSeconds: num(rawLimits.maxExecutionSeconds) } : void 0;
2778
+ out.push({
2779
+ sourceId,
2780
+ label,
2781
+ ...schema2 ? { schema: schema2 } : {},
2782
+ ...readableTables ? { readableTables } : {},
2783
+ ...Object.keys(rowFilters).length ? { rowFilters } : {},
2784
+ ...limits ? { limits } : {}
2785
+ });
2786
+ }
2787
+ return out;
2649
2788
  }
2789
+
2790
+ // src/handlers/data-access/shape.ts
2650
2791
  function scopedForm(config2) {
2651
2792
  if (!config2 || typeof config2 !== "object" || Array.isArray(config2)) return void 0;
2652
2793
  const c = config2;
2653
2794
  return "allowedSources" in c || "policies" in c ? c : void 0;
2654
2795
  }
2655
- function allowedSourcesFrom(value) {
2656
- if (value === void 0 || value === null) return null;
2657
- if (!Array.isArray(value)) {
2658
- if (!warnedBadSources) {
2659
- warnedBadSources = true;
2660
- logger.warn(
2661
- `[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"].`
2662
- );
2663
- }
2664
- return [];
2665
- }
2666
- const out = [];
2667
- for (const item of value) {
2668
- if (typeof item !== "string" || !item.trim()) continue;
2669
- const id = item.trim();
2670
- if (!out.includes(id)) out.push(id);
2671
- }
2672
- return out;
2673
- }
2674
- function accessFromConfig(config2) {
2675
- const scoped = scopedForm(config2);
2676
- return {
2677
- policies: policiesFromConfig(config2),
2678
- allowedSources: scoped ? allowedSourcesFrom(scoped.allowedSources) : null
2679
- };
2680
- }
2796
+
2797
+ // src/handlers/data-access/v1/policies.ts
2798
+ var warnedUnlabelled = false;
2681
2799
  function exceptionsFromConfig(raw) {
2682
2800
  if (!Array.isArray(raw)) return [];
2683
2801
  const str = (v) => typeof v === "string" && v.trim() ? v.trim() : void 0;
@@ -2756,16 +2874,55 @@ function policiesFromConfig(config2) {
2756
2874
  }
2757
2875
  return out;
2758
2876
  }
2877
+
2878
+ // src/handlers/request-identity.ts
2879
+ function graphVersionOf(v) {
2880
+ if (v === "draft") return "draft";
2881
+ return Number.isInteger(v) && v > 0 ? v : void 0;
2882
+ }
2883
+ function allowedSourcesFrom(value) {
2884
+ if (value === void 0 || value === null) return null;
2885
+ if (!Array.isArray(value)) {
2886
+ if (!warnedBadSources) {
2887
+ warnedBadSources = true;
2888
+ logger.warn(
2889
+ `[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"].`
2890
+ );
2891
+ }
2892
+ return [];
2893
+ }
2894
+ const out = [];
2895
+ for (const item of value) {
2896
+ if (typeof item !== "string" || !item.trim()) continue;
2897
+ const id = item.trim();
2898
+ if (!out.includes(id)) out.push(id);
2899
+ }
2900
+ return out;
2901
+ }
2902
+ function accessFromConfig(config2) {
2903
+ const scoped = scopedForm(config2);
2904
+ const allowedSources = scoped ? allowedSourcesFrom(scoped.allowedSources) : null;
2905
+ if (scoped?.version === 2) {
2906
+ return {
2907
+ policies: [],
2908
+ constraintPolicies: constraintPoliciesFromConfig(scoped.policies),
2909
+ allowedSources
2910
+ };
2911
+ }
2912
+ return { policies: policiesFromConfig(config2), constraintPolicies: [], allowedSources };
2913
+ }
2759
2914
  var warnedUntrusted = false;
2760
2915
  var warnedAnonymous = false;
2761
- var warnedUnlabelled = false;
2762
2916
  var warnedBadSources = false;
2763
2917
  var announcedVerified = false;
2764
2918
  var reportedIdMismatches = /* @__PURE__ */ new Set();
2765
2919
  function runWithMessageIdentity(message, fn) {
2766
2920
  const verified = message?.authContext;
2767
2921
  const requestId = message?.id;
2768
- const { policies, allowedSources } = verified ? accessFromConfig(verified.config) : accessFromConfig(message?.payload?.config);
2922
+ const { policies, constraintPolicies, allowedSources } = verified ? accessFromConfig(verified.config) : accessFromConfig(message?.payload?.config);
2923
+ logger.info(
2924
+ `[RequestIdentity] ${message?.type ?? "?"}: access from ${verified ? "authContext" : "payload"}${verified && verified.config == null ? " (none on it)" : ""}, allowedSources=${allowedSources === null ? "every source" : `[${allowedSources.join(", ") || "NONE"}]`}, ${constraintPolicies.length} constraint policy(ies), ${policies.length} row policy(ies)`
2925
+ );
2769
2926
  if (verified?.userId) {
2770
2927
  const claimedId = message?.payload?.userId;
2771
2928
  if (!announcedVerified) {
@@ -2790,6 +2947,7 @@ function runWithMessageIdentity(message, fn) {
2790
2947
  role: verified.role,
2791
2948
  requestId,
2792
2949
  policies,
2950
+ constraintPolicies,
2793
2951
  // `?? undefined` so "no restriction" leaves the key off the context
2794
2952
  // entirely; `[]` is passed through as the deny-everything it means.
2795
2953
  allowedSources: allowedSources ?? void 0,
@@ -2807,7 +2965,10 @@ function runWithMessageIdentity(message, fn) {
2807
2965
  "[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."
2808
2966
  );
2809
2967
  }
2810
- return runAsUser({ userId: claimed, requestId, policies, allowedSources: allowedSources ?? void 0 }, fn);
2968
+ return runAsUser(
2969
+ { userId: claimed, requestId, policies, constraintPolicies, allowedSources: allowedSources ?? void 0 },
2970
+ fn
2971
+ );
2811
2972
  }
2812
2973
  if (!warnedAnonymous) {
2813
2974
  warnedAnonymous = true;
@@ -30209,6 +30370,7 @@ var SuperatomSDK = class {
30209
30370
  bridgePreamble,
30210
30371
  captureContext,
30211
30372
  clearContextTokens,
30373
+ constraintPoliciesFromConfig,
30212
30374
  contextTokenCount,
30213
30375
  createCodexSession,
30214
30376
  createCodingAgentSession,
package/dist/index.mjs CHANGED
@@ -1840,7 +1840,17 @@ function runWithContext(ctx, fn) {
1840
1840
  return getStorage().run(ctx, fn);
1841
1841
  }
1842
1842
  function runAsUser(user, fn) {
1843
- const { userId, orgId, role, projectId, requestId, policies, allowedSources, graphVersion } = user;
1843
+ const {
1844
+ userId,
1845
+ orgId,
1846
+ role,
1847
+ projectId,
1848
+ requestId,
1849
+ policies,
1850
+ constraintPolicies,
1851
+ allowedSources,
1852
+ graphVersion
1853
+ } = user;
1844
1854
  return runWithContext(
1845
1855
  // `allowedSources` is spread in only when given, so an absent restriction
1846
1856
  // stays absent rather than becoming an explicit `undefined` that a later
@@ -1850,6 +1860,7 @@ function runAsUser(user, fn) {
1850
1860
  projectId,
1851
1861
  requestId,
1852
1862
  policies,
1863
+ ...constraintPolicies?.length ? { constraintPolicies } : {},
1853
1864
  ...allowedSources !== void 0 ? { allowedSources } : {},
1854
1865
  ...graphVersion !== void 0 ? { graphVersion } : {}
1855
1866
  },
@@ -2530,42 +2541,148 @@ function buildDirectToolCacheKey(toolId, parameters) {
2530
2541
  return `et-direct:${toolId}:${stableStringify(parameters || {})}`;
2531
2542
  }
2532
2543
 
2533
- // src/handlers/request-identity.ts
2534
- function graphVersionOf(v) {
2535
- if (v === "draft") return "draft";
2536
- return Number.isInteger(v) && v > 0 ? v : void 0;
2544
+ // src/handlers/data-access/v2/policies.ts
2545
+ var CONSTRAINT_OPS = [
2546
+ "in",
2547
+ "not_in",
2548
+ "eq",
2549
+ "ne",
2550
+ "gt",
2551
+ "gte",
2552
+ "lt",
2553
+ "lte",
2554
+ "like",
2555
+ "not_like",
2556
+ "is_null",
2557
+ "is_not_null"
2558
+ ];
2559
+ var NO_VALUE_OPS = /* @__PURE__ */ new Set(["is_null", "is_not_null"]);
2560
+ function constraintPoliciesFromConfig(raw) {
2561
+ const entries = Array.isArray(raw) ? raw : [raw];
2562
+ const out = [];
2563
+ for (const entry of entries) {
2564
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
2565
+ const e = entry;
2566
+ const sourceId = typeof e.sourceId === "string" && e.sourceId ? e.sourceId : null;
2567
+ const label = typeof e.label === "string" && e.label.trim() ? e.label.trim() : void 0;
2568
+ const bad = (why) => ({ sourceId, label, invalid: why });
2569
+ let schema2;
2570
+ if (e.schema !== void 0 && e.schema !== null) {
2571
+ if (typeof e.schema !== "string" || !e.schema.trim()) {
2572
+ out.push(bad("schema must be a schema name"));
2573
+ continue;
2574
+ }
2575
+ schema2 = e.schema.trim();
2576
+ }
2577
+ let readableTables;
2578
+ let tablesBad;
2579
+ if (e.readableTables !== void 0 && e.readableTables !== null) {
2580
+ if (typeof e.readableTables !== "object" || Array.isArray(e.readableTables)) {
2581
+ out.push(bad("readableTables must be an object of table to columns"));
2582
+ continue;
2583
+ }
2584
+ readableTables = {};
2585
+ for (const [table, cols] of Object.entries(e.readableTables)) {
2586
+ if (cols === null) {
2587
+ readableTables[table] = null;
2588
+ continue;
2589
+ }
2590
+ if (!Array.isArray(cols) || cols.length === 0) {
2591
+ tablesBad = `readableTables["${table}"] must be a non-empty list or null`;
2592
+ break;
2593
+ }
2594
+ const columns = cols.filter((c) => typeof c === "string" && !!c.trim()).map((c) => c.trim());
2595
+ if (columns.length !== cols.length) {
2596
+ tablesBad = `readableTables["${table}"] has an entry that is not a column name`;
2597
+ break;
2598
+ }
2599
+ readableTables[table] = columns;
2600
+ }
2601
+ if (!tablesBad && Object.keys(readableTables).length === 0) {
2602
+ tablesBad = "readableTables names no tables \u2014 omit it to allow every table";
2603
+ }
2604
+ if (tablesBad) {
2605
+ out.push(bad(tablesBad));
2606
+ continue;
2607
+ }
2608
+ }
2609
+ const rowFilters = {};
2610
+ let filtersBad;
2611
+ const rawFilters = e.rowFilters;
2612
+ if (rawFilters !== void 0 && rawFilters !== null) {
2613
+ if (typeof rawFilters !== "object" || Array.isArray(rawFilters)) {
2614
+ filtersBad = "rowFilters must be an object keyed by table";
2615
+ } else {
2616
+ for (const [table, items] of Object.entries(rawFilters)) {
2617
+ if (readableTables && !(table in readableTables)) {
2618
+ filtersBad = `rowFilters names "${table}", which readableTables does not allow`;
2619
+ break;
2620
+ }
2621
+ if (!Array.isArray(items) || items.length === 0) {
2622
+ filtersBad = `rowFilters["${table}"] must be a non-empty list`;
2623
+ break;
2624
+ }
2625
+ const parsed = [];
2626
+ for (const item of items) {
2627
+ if (!item || typeof item !== "object") {
2628
+ filtersBad = `rowFilters["${table}"] has an entry that is not an object`;
2629
+ break;
2630
+ }
2631
+ const f = item;
2632
+ if (typeof f.column !== "string" || !f.column.trim()) {
2633
+ filtersBad = `a filter on "${table}" has no column`;
2634
+ break;
2635
+ }
2636
+ const op = typeof f.op === "string" ? f.op.toLowerCase() : "in";
2637
+ if (!CONSTRAINT_OPS.includes(op)) {
2638
+ filtersBad = `unsupported operator "${f.op}" on "${table}.${f.column}"`;
2639
+ break;
2640
+ }
2641
+ const values = Array.isArray(f.values) ? f.values : [];
2642
+ if (!NO_VALUE_OPS.has(op) && values.length === 0) {
2643
+ filtersBad = `the filter on "${table}.${f.column}" has no values`;
2644
+ break;
2645
+ }
2646
+ parsed.push({
2647
+ column: f.column.trim(),
2648
+ op,
2649
+ ...NO_VALUE_OPS.has(op) ? {} : { values },
2650
+ label: typeof f.label === "string" && f.label.trim() ? f.label.trim() : void 0
2651
+ });
2652
+ }
2653
+ if (filtersBad) break;
2654
+ rowFilters[table] = parsed;
2655
+ }
2656
+ }
2657
+ }
2658
+ if (filtersBad) {
2659
+ out.push(bad(filtersBad));
2660
+ continue;
2661
+ }
2662
+ const rawLimits = e.limits;
2663
+ const num = (v) => typeof v === "number" && Number.isInteger(v) && v > 0 ? v : void 0;
2664
+ const limits = rawLimits ? { maxRows: num(rawLimits.maxRows), maxExecutionSeconds: num(rawLimits.maxExecutionSeconds) } : void 0;
2665
+ out.push({
2666
+ sourceId,
2667
+ label,
2668
+ ...schema2 ? { schema: schema2 } : {},
2669
+ ...readableTables ? { readableTables } : {},
2670
+ ...Object.keys(rowFilters).length ? { rowFilters } : {},
2671
+ ...limits ? { limits } : {}
2672
+ });
2673
+ }
2674
+ return out;
2537
2675
  }
2676
+
2677
+ // src/handlers/data-access/shape.ts
2538
2678
  function scopedForm(config2) {
2539
2679
  if (!config2 || typeof config2 !== "object" || Array.isArray(config2)) return void 0;
2540
2680
  const c = config2;
2541
2681
  return "allowedSources" in c || "policies" in c ? c : void 0;
2542
2682
  }
2543
- function allowedSourcesFrom(value) {
2544
- if (value === void 0 || value === null) return null;
2545
- if (!Array.isArray(value)) {
2546
- if (!warnedBadSources) {
2547
- warnedBadSources = true;
2548
- logger.warn(
2549
- `[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"].`
2550
- );
2551
- }
2552
- return [];
2553
- }
2554
- const out = [];
2555
- for (const item of value) {
2556
- if (typeof item !== "string" || !item.trim()) continue;
2557
- const id = item.trim();
2558
- if (!out.includes(id)) out.push(id);
2559
- }
2560
- return out;
2561
- }
2562
- function accessFromConfig(config2) {
2563
- const scoped = scopedForm(config2);
2564
- return {
2565
- policies: policiesFromConfig(config2),
2566
- allowedSources: scoped ? allowedSourcesFrom(scoped.allowedSources) : null
2567
- };
2568
- }
2683
+
2684
+ // src/handlers/data-access/v1/policies.ts
2685
+ var warnedUnlabelled = false;
2569
2686
  function exceptionsFromConfig(raw) {
2570
2687
  if (!Array.isArray(raw)) return [];
2571
2688
  const str = (v) => typeof v === "string" && v.trim() ? v.trim() : void 0;
@@ -2644,16 +2761,55 @@ function policiesFromConfig(config2) {
2644
2761
  }
2645
2762
  return out;
2646
2763
  }
2764
+
2765
+ // src/handlers/request-identity.ts
2766
+ function graphVersionOf(v) {
2767
+ if (v === "draft") return "draft";
2768
+ return Number.isInteger(v) && v > 0 ? v : void 0;
2769
+ }
2770
+ function allowedSourcesFrom(value) {
2771
+ if (value === void 0 || value === null) return null;
2772
+ if (!Array.isArray(value)) {
2773
+ if (!warnedBadSources) {
2774
+ warnedBadSources = true;
2775
+ logger.warn(
2776
+ `[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"].`
2777
+ );
2778
+ }
2779
+ return [];
2780
+ }
2781
+ const out = [];
2782
+ for (const item of value) {
2783
+ if (typeof item !== "string" || !item.trim()) continue;
2784
+ const id = item.trim();
2785
+ if (!out.includes(id)) out.push(id);
2786
+ }
2787
+ return out;
2788
+ }
2789
+ function accessFromConfig(config2) {
2790
+ const scoped = scopedForm(config2);
2791
+ const allowedSources = scoped ? allowedSourcesFrom(scoped.allowedSources) : null;
2792
+ if (scoped?.version === 2) {
2793
+ return {
2794
+ policies: [],
2795
+ constraintPolicies: constraintPoliciesFromConfig(scoped.policies),
2796
+ allowedSources
2797
+ };
2798
+ }
2799
+ return { policies: policiesFromConfig(config2), constraintPolicies: [], allowedSources };
2800
+ }
2647
2801
  var warnedUntrusted = false;
2648
2802
  var warnedAnonymous = false;
2649
- var warnedUnlabelled = false;
2650
2803
  var warnedBadSources = false;
2651
2804
  var announcedVerified = false;
2652
2805
  var reportedIdMismatches = /* @__PURE__ */ new Set();
2653
2806
  function runWithMessageIdentity(message, fn) {
2654
2807
  const verified = message?.authContext;
2655
2808
  const requestId = message?.id;
2656
- const { policies, allowedSources } = verified ? accessFromConfig(verified.config) : accessFromConfig(message?.payload?.config);
2809
+ const { policies, constraintPolicies, allowedSources } = verified ? accessFromConfig(verified.config) : accessFromConfig(message?.payload?.config);
2810
+ logger.info(
2811
+ `[RequestIdentity] ${message?.type ?? "?"}: access from ${verified ? "authContext" : "payload"}${verified && verified.config == null ? " (none on it)" : ""}, allowedSources=${allowedSources === null ? "every source" : `[${allowedSources.join(", ") || "NONE"}]`}, ${constraintPolicies.length} constraint policy(ies), ${policies.length} row policy(ies)`
2812
+ );
2657
2813
  if (verified?.userId) {
2658
2814
  const claimedId = message?.payload?.userId;
2659
2815
  if (!announcedVerified) {
@@ -2678,6 +2834,7 @@ function runWithMessageIdentity(message, fn) {
2678
2834
  role: verified.role,
2679
2835
  requestId,
2680
2836
  policies,
2837
+ constraintPolicies,
2681
2838
  // `?? undefined` so "no restriction" leaves the key off the context
2682
2839
  // entirely; `[]` is passed through as the deny-everything it means.
2683
2840
  allowedSources: allowedSources ?? void 0,
@@ -2695,7 +2852,10 @@ function runWithMessageIdentity(message, fn) {
2695
2852
  "[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."
2696
2853
  );
2697
2854
  }
2698
- return runAsUser({ userId: claimed, requestId, policies, allowedSources: allowedSources ?? void 0 }, fn);
2855
+ return runAsUser(
2856
+ { userId: claimed, requestId, policies, constraintPolicies, allowedSources: allowedSources ?? void 0 },
2857
+ fn
2858
+ );
2699
2859
  }
2700
2860
  if (!warnedAnonymous) {
2701
2861
  warnedAnonymous = true;
@@ -30096,6 +30256,7 @@ export {
30096
30256
  bridgePreamble,
30097
30257
  captureContext,
30098
30258
  clearContextTokens,
30259
+ constraintPoliciesFromConfig,
30099
30260
  contextTokenCount,
30100
30261
  createCodexSession,
30101
30262
  createCodingAgentSession,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superatomai/sdk-node",
3
- "version": "0.0.88-dsp",
3
+ "version": "0.0.89-dsp",
4
4
  "description": "Node.js TypeScript SDK for Superatom",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",