@supercuts-walrus/backend 0.1.1 → 0.1.3

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 (54) hide show
  1. package/README.md +28 -5
  2. package/config/phase1.testnet.json +20 -0
  3. package/config/proving-manifest.json +11 -0
  4. package/dist/buyer-setup.js +27 -13
  5. package/dist/cli.js +10 -2
  6. package/dist/dashboard.js +1 -1
  7. package/dist/deal-adapter.js +0 -2
  8. package/dist/deal-engine.d.ts +13 -0
  9. package/dist/deal-engine.js +64 -39
  10. package/dist/deal.d.ts +35 -0
  11. package/dist/deal.js +9 -3
  12. package/dist/embedding-adapter.d.ts +26 -0
  13. package/dist/embedding-adapter.js +116 -0
  14. package/dist/facilitator.js +2 -1
  15. package/dist/funding.js +10 -1
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.js +1 -0
  18. package/dist/live-deal-ports.d.ts +2 -1
  19. package/dist/live-deal-ports.js +31 -5
  20. package/dist/live-runtime.d.ts +1 -1
  21. package/dist/live-runtime.js +27 -11
  22. package/dist/live-seller-transport.js +5 -1
  23. package/dist/main-module.d.ts +5 -0
  24. package/dist/main-module.js +16 -0
  25. package/dist/mandate.js +1 -1
  26. package/dist/mcp-bootstrap.js +3 -3
  27. package/dist/mcp.js +2 -0
  28. package/dist/memory-scorecard.d.ts +32 -0
  29. package/dist/memory-scorecard.js +76 -0
  30. package/dist/memwal.d.ts +28 -0
  31. package/dist/memwal.js +81 -2
  32. package/dist/onboarding-doctor.js +12 -5
  33. package/dist/phase3.d.ts +43 -0
  34. package/dist/phase3.js +147 -32
  35. package/dist/role-lock.d.ts +1 -1
  36. package/dist/role-lock.js +1 -1
  37. package/dist/seam.js +2 -1
  38. package/dist/seller-catalog-generate.js +4 -4
  39. package/dist/seller-directory-cli.js +2 -1
  40. package/dist/seller-live-cli.js +10 -1
  41. package/dist/seller-provision.js +15 -1
  42. package/dist/seller-research.d.ts +50 -0
  43. package/dist/seller-research.js +210 -0
  44. package/dist/seller-scaffold.d.ts +1 -0
  45. package/dist/seller-scaffold.js +35 -0
  46. package/dist/seller-service.d.ts +1 -1
  47. package/dist/seller-service.js +8 -20
  48. package/dist/seller-setup.d.ts +3 -0
  49. package/dist/seller-setup.js +109 -0
  50. package/dist/settlement.d.ts +32 -3
  51. package/dist/settlement.js +56 -11
  52. package/dist/testnet-defaults.d.ts +21 -0
  53. package/dist/testnet-defaults.js +26 -0
  54. package/package.json +4 -2
@@ -25,6 +25,10 @@ export interface SettlementMemoryV1 {
25
25
  reliability?: number;
26
26
  quality?: number;
27
27
  outcome?: "succeeded" | "failed" | "unresolved";
28
+ amount?: string;
29
+ latencyMs?: number;
30
+ rail?: CapabilityRail;
31
+ periodMs?: number;
28
32
  };
29
33
  }
30
34
  export interface SettlementCitation {
@@ -33,7 +37,7 @@ export interface SettlementCitation {
33
37
  provenance: SettlementMemoryProvenance;
34
38
  distance: number;
35
39
  }
36
- export type SettlementReasonCode = "MANDATE_DEFAULTS_APPLIED" | "MEMORY_PRIVACY_APPLIED" | "MEMORY_BUDGET_APPLIED" | "MEMORY_OUTCOME_APPLIED" | "MEMORY_LOW_RELEVANCE_IGNORED" | "MEMORY_UNTRUSTED_ADVISORY" | "OWNER_POLICY_CONFLICT" | "RISK_LOW" | "RISK_MEDIUM" | "RISK_REVIEW_REQUIRED" | "RAIL_X402_SELECTED" | "RAIL_SHIELDED_SELECTED" | "REQUESTED_AMOUNT_CLAMPED" | "OWNER_REVIEW_APPROVED";
40
+ export type SettlementReasonCode = "MANDATE_DEFAULTS_APPLIED" | "MEMORY_PRIVACY_APPLIED" | "MEMORY_BUDGET_APPLIED" | "MEMORY_OUTCOME_APPLIED" | "MEMORY_LOW_RELEVANCE_IGNORED" | "MEMORY_UNTRUSTED_ADVISORY" | "OWNER_POLICY_CONFLICT" | "RISK_LOW" | "RISK_MEDIUM" | "RISK_REVIEW_REQUIRED" | "RAIL_X402_SELECTED" | "RAIL_SHIELDED_SELECTED" | "REQUESTED_AMOUNT_CLAMPED" | "OWNER_REVIEW_APPROVED" | "MEMORY_RELIABILITY_LEARNED" | "MEMORY_SELLER_DEMOTED" | "MEMORY_SPEND_LIMIT_REACHED";
37
41
  export interface SettlementPlanV1 {
38
42
  version: typeof SETTLEMENT_PLAN_VERSION;
39
43
  planHash: string;
@@ -81,7 +85,7 @@ export declare function canonicalJson(value: unknown): string;
81
85
  export declare const settlementMandateHash: (mandate: PlanningMandate) => string;
82
86
  export declare function settlementPlanHash(plan: Omit<SettlementPlanV1, "planHash">): string;
83
87
  export declare function validateSettlementMemory(value: unknown, assignedProvenance?: SettlementMemoryProvenance): asserts value is SettlementMemoryV1;
84
- export declare function createSettlementPlan(input: {
88
+ export interface PlanningInput {
85
89
  operationId: string;
86
90
  mandate: PlanningMandate;
87
91
  manifests: CapabilityManifest[];
@@ -91,5 +95,30 @@ export declare function createSettlementPlan(input: {
91
95
  recalled?: RecalledSettlementMemory[];
92
96
  maxMemoryDistance?: number;
93
97
  now?: number;
94
- }): SettlementPlanV1;
98
+ }
99
+ /**
100
+ * Trusted typed memories (owner policy or verified outcome) are matched by their structured scope, so a
101
+ * semantic distance cutoff would only drop real evidence: embeddings of JSON records rank far from scope
102
+ * queries. Advisory and legacy text still needs semantic relevance.
103
+ */
104
+ export declare function isRelevantMemory(item: RecalledSettlementMemory, maxDistance: number): boolean;
105
+ export declare function createSettlementPlan(input: PlanningInput): SettlementPlanV1;
95
106
  export declare function validateSettlementPlan(value: unknown): asserts value is SettlementPlanV1;
107
+ export interface MemoryDecision {
108
+ sellerId: string;
109
+ capabilityId: string;
110
+ rail: CapabilityRail;
111
+ riskLevel: SettlementRisk;
112
+ maximumAmount: string;
113
+ }
114
+ export interface MemoryInfluence {
115
+ changedSeller: boolean;
116
+ changedRail: boolean;
117
+ changedRisk: boolean;
118
+ changedMaximum: boolean;
119
+ withoutMemory?: MemoryDecision;
120
+ withMemory: MemoryDecision;
121
+ citedBlobIds: string[];
122
+ }
123
+ /** Counterfactual: what the same mandate would have paid without any recalled memory. Not part of the plan hash. */
124
+ export declare function explainMemoryInfluence(input: PlanningInput, plan: SettlementPlanV1): MemoryInfluence;
@@ -1,5 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { fail } from "./errors.js";
3
+ import { buildScorecard, spentSince } from "./memory-scorecard.js";
3
4
  export const SETTLEMENT_PLAN_VERSION = "supercuts.settlement-plan.v1";
4
5
  export const SETTLEMENT_MEMORY_VERSION = "supercuts.settlement-memory.v1";
5
6
  export function canonicalJson(value) {
@@ -38,7 +39,7 @@ export function validateSettlementMemory(value, assignedProvenance) {
38
39
  fail("SETTLEMENT_MEMORY_INVALID", "memory observation must be a short non-empty string");
39
40
  const scope = raw.scope, signal = raw.signal;
40
41
  exactKeys(scope, ["counterparty", "capabilityId", "capabilityClass", "network", "asset"]);
41
- exactKeys(signal, ["requiresShielded", "maximumAmount", "reliability", "quality", "outcome"]);
42
+ exactKeys(signal, ["requiresShielded", "maximumAmount", "reliability", "quality", "outcome", "amount", "latencyMs", "rail", "periodMs"]);
42
43
  for (const item of Object.values(scope))
43
44
  if (typeof item !== "string" || !item || item.length > 1024)
44
45
  fail("SETTLEMENT_MEMORY_INVALID", "memory scope fields must be non-empty strings");
@@ -51,6 +52,13 @@ export function validateSettlementMemory(value, assignedProvenance) {
51
52
  fail("SETTLEMENT_MEMORY_INVALID", "memory scores must be finite values in [0,1]");
52
53
  if (signal.outcome !== undefined && !["succeeded", "failed", "unresolved"].includes(signal.outcome))
53
54
  fail("SETTLEMENT_MEMORY_INVALID", "memory outcome is invalid");
55
+ if (signal.amount !== undefined && !unsigned(signal.amount) || signal.rail !== undefined && !["x402", "shielded"].includes(signal.rail))
56
+ fail("SETTLEMENT_MEMORY_INVALID", "memory payment amount or rail is invalid");
57
+ for (const value of [signal.latencyMs, signal.periodMs])
58
+ if (value !== undefined && (!Number.isSafeInteger(value) || value < 0))
59
+ fail("SETTLEMENT_MEMORY_INVALID", "memory durations must be non-negative integers");
60
+ if (signal.periodMs !== undefined && (raw.kind !== "budget_limit" || signal.periodMs === 0))
61
+ fail("SETTLEMENT_MEMORY_INVALID", "only budget limits may declare a positive period");
54
62
  const required = { privacy_rule: "requiresShielded", budget_limit: "maximumAmount", reliability: "reliability", quality: "quality", outcome: "outcome" };
55
63
  if (signal[required[raw.kind]] === undefined)
56
64
  fail("SETTLEMENT_MEMORY_INVALID", "memory kind does not have its required signal");
@@ -64,6 +72,18 @@ function specificity(scope, manifest) {
64
72
  return -1;
65
73
  return scope.capabilityId ? 4 : scope.capabilityClass ? 3 : scope.counterparty ? 2 : 1;
66
74
  }
75
+ /**
76
+ * Trusted typed memories (owner policy or verified outcome) are matched by their structured scope, so a
77
+ * semantic distance cutoff would only drop real evidence: embeddings of JSON records rank far from scope
78
+ * queries. Advisory and legacy text still needs semantic relevance.
79
+ */
80
+ export function isRelevantMemory(item, maxDistance) {
81
+ if (!Number.isFinite(item.distance) || item.distance < 0)
82
+ return false;
83
+ if (item.memory && (item.memory.provenance === "owner_policy" || item.memory.provenance === "verified_outcome"))
84
+ return true;
85
+ return item.distance <= maxDistance;
86
+ }
67
87
  export function createSettlementPlan(input) {
68
88
  const now = input.now ?? Date.now(), maxDistance = input.maxMemoryDistance ?? 0.35;
69
89
  if (!input.operationId || input.operationId.length > 256 || !input.manifests.length)
@@ -72,8 +92,9 @@ export function createSettlementPlan(input) {
72
92
  fail("SETTLEMENT_PLAN_INVALID", "requestedAmount must be canonical unsigned base units");
73
93
  if (!Number.isFinite(maxDistance) || maxDistance < 0 || maxDistance > 1 || now >= input.mandate.expiresAt)
74
94
  fail("SETTLEMENT_PLAN_DENIED", "planning limits or owner mandate are invalid");
75
- const ignored = (input.recalled ?? []).filter((item) => !Number.isFinite(item.distance) || item.distance < 0 || item.distance > maxDistance);
76
- const recalled = (input.recalled ?? []).filter((item) => Number.isFinite(item.distance) && item.distance >= 0 && item.distance <= maxDistance);
95
+ const relevant = (item) => isRelevantMemory(item, maxDistance);
96
+ const ignored = (input.recalled ?? []).filter((item) => !relevant(item));
97
+ const recalled = (input.recalled ?? []).filter(relevant);
77
98
  for (const item of recalled)
78
99
  if (item.memory)
79
100
  validateSettlementMemory(item.memory);
@@ -99,19 +120,30 @@ export function createSettlementPlan(input) {
99
120
  const rails = manifest.supportedRails.filter((rail) => (!input.mandate.allowedRails || input.mandate.allowedRails.includes(rail)) && (!requiresShielded || rail === "shielded") && (input.mandate.version !== "supercuts.mandate.v2" || rail !== "x402" || input.mandate.allowPublicX402 === true) && (!input.requestedRail || rail === input.requestedRail));
100
121
  if (!rails.length)
101
122
  continue;
102
- const budgets = trusted.filter((item) => item.memory.kind === "budget_limit").map((item) => BigInt(item.memory.signal.maximumAmount));
103
- const maximum = [BigInt(manifest.priceBand.maximum), BigInt(input.mandate.perDealCeiling), ...budgets].reduce((a, b) => a < b ? a : b);
104
- if (maximum < BigInt(manifest.priceBand.minimum))
123
+ const budgetMemories = trusted.filter((item) => item.memory.kind === "budget_limit").map((item) => item.memory);
124
+ const budgets = budgetMemories.filter((item) => item.signal.periodMs === undefined).map((item) => BigInt(item.signal.maximumAmount));
125
+ // Periodic owner budgets subtract the verified spend that Walrus Memory remembers for the same scope.
126
+ const remaining = budgetMemories.filter((item) => item.signal.periodMs !== undefined).map((item) => { const limit = BigInt(item.signal.maximumAmount), spent = spentSince(recalled, item.scope, now - item.signal.periodMs); return limit > spent ? limit - spent : 0n; });
127
+ const minimumPrice = BigInt(manifest.priceBand.minimum);
128
+ let maximum = [BigInt(manifest.priceBand.maximum), BigInt(input.mandate.perDealCeiling), ...budgets, ...remaining].reduce((a, b) => a < b ? a : b);
129
+ const spendLimited = maximum < minimumPrice && remaining.some((value) => value < minimumPrice) && [BigInt(manifest.priceBand.maximum), BigInt(input.mandate.perDealCeiling), ...budgets].every((value) => value >= minimumPrice);
130
+ if (maximum < minimumPrice && !spendLimited)
105
131
  continue;
106
- const reliability = latest("reliability")[0]?.signal.reliability ?? 0.5, quality = latest("quality")[0]?.signal.quality ?? 0.5, outcome = latest("outcome")[0]?.signal.outcome;
107
- const risk = conflict || outcome === "failed" || outcome === "unresolved" || reliability < 0.5 ? "review_required" : reliability >= 0.8 ? "low" : "medium";
132
+ if (spendLimited)
133
+ maximum = minimumPrice;
134
+ const card = buildScorecard(recalled, { counterparty: manifest.sellerId, capabilityClass: manifest.capability }, now);
135
+ const explicit = latest("reliability")[0];
136
+ const reliability = explicit?.provenance === "owner_policy" ? explicit.signal.reliability : card.observations ? card.reliability : explicit?.signal.reliability ?? 0.5;
137
+ const quality = latest("quality")[0]?.signal.quality ?? 0.5, outcome = card.lastOutcome ?? latest("outcome")[0]?.signal.outcome;
138
+ const risk = conflict || spendLimited || outcome === "unresolved" || reliability < 0.5 ? "review_required" : reliability >= 0.8 ? "low" : "medium";
108
139
  for (const rail of rails)
109
- candidates.push({ manifest, rail, reliability, quality, maximum, risk, citations, conflict, reasons: ["MANDATE_DEFAULTS_APPLIED", ...(policies.length ? ["MEMORY_PRIVACY_APPLIED"] : []), ...(budgets.length ? ["MEMORY_BUDGET_APPLIED"] : []), ...(outcome ? ["MEMORY_OUTCOME_APPLIED"] : []), ...(citations.some((c) => ["agent_observation", "legacy_untrusted"].includes(c.provenance)) ? ["MEMORY_UNTRUSTED_ADVISORY"] : []), ...(ignored.length ? ["MEMORY_LOW_RELEVANCE_IGNORED"] : [])] });
140
+ candidates.push({ manifest, rail, reliability, quality, maximum, risk, citations, conflict, card, reasons: ["MANDATE_DEFAULTS_APPLIED", ...(policies.length ? ["MEMORY_PRIVACY_APPLIED"] : []), ...(budgetMemories.length ? ["MEMORY_BUDGET_APPLIED"] : []), ...(spendLimited ? ["MEMORY_SPEND_LIMIT_REACHED"] : []), ...(outcome ? ["MEMORY_OUTCOME_APPLIED"] : []), ...(card.observations ? ["MEMORY_RELIABILITY_LEARNED"] : []), ...(citations.some((c) => ["agent_observation", "legacy_untrusted"].includes(c.provenance)) ? ["MEMORY_UNTRUSTED_ADVISORY"] : []), ...(ignored.length ? ["MEMORY_LOW_RELEVANCE_IGNORED"] : [])] });
110
141
  }
111
- candidates.sort((a, b) => b.reliability - a.reliability || b.quality - a.quality || (a.maximum < b.maximum ? -1 : a.maximum > b.maximum ? 1 : 0) || a.manifest.capabilityId.localeCompare(b.manifest.capabilityId) || (a.rail === b.rail ? 0 : input.mandate.version === "supercuts.mandate.v2" ? a.rail === "shielded" ? -1 : 1 : a.rail === "x402" ? -1 : 1));
142
+ candidates.sort((a, b) => Number(a.risk === "review_required") - Number(b.risk === "review_required") || b.reliability - a.reliability || b.quality - a.quality || (a.maximum < b.maximum ? -1 : a.maximum > b.maximum ? 1 : 0) || a.manifest.capabilityId.localeCompare(b.manifest.capabilityId) || (a.rail === b.rail ? 0 : input.mandate.version === "supercuts.mandate.v2" ? a.rail === "shielded" ? -1 : 1 : a.rail === "x402" ? -1 : 1));
112
143
  const selected = candidates[0] ?? fail("SETTLEMENT_PLAN_DENIED", "no capability remains within the owner mandate, privacy rules, and price bounds");
113
144
  const minimum = BigInt(selected.manifest.priceBand.minimum), desired = input.requestedAmount === undefined ? minimum : BigInt(input.requestedAmount), opening = desired < minimum ? minimum : desired > selected.maximum ? selected.maximum : desired;
114
- const reasons = [...selected.reasons, ...(selected.conflict ? ["OWNER_POLICY_CONFLICT"] : []), ...(opening !== desired ? ["REQUESTED_AMOUNT_CLAMPED"] : []), selected.rail === "shielded" ? "RAIL_SHIELDED_SELECTED" : "RAIL_X402_SELECTED", selected.risk === "low" ? "RISK_LOW" : selected.risk === "medium" ? "RISK_MEDIUM" : "RISK_REVIEW_REQUIRED"];
145
+ const demoted = candidates.some((item) => item.manifest.sellerId !== selected.manifest.sellerId && item.card.observations > 0 && item.reliability < selected.reliability);
146
+ const reasons = [...selected.reasons, ...(demoted ? ["MEMORY_SELLER_DEMOTED"] : []), ...(selected.conflict ? ["OWNER_POLICY_CONFLICT"] : []), ...(opening !== desired ? ["REQUESTED_AMOUNT_CLAMPED"] : []), selected.rail === "shielded" ? "RAIL_SHIELDED_SELECTED" : "RAIL_X402_SELECTED", selected.risk === "low" ? "RISK_LOW" : selected.risk === "medium" ? "RISK_MEDIUM" : "RISK_REVIEW_REQUIRED"];
115
147
  const withoutHash = { version: SETTLEMENT_PLAN_VERSION, operationId: input.operationId, status: selected.risk === "review_required" ? "review_required" : "approved", mandateHash: settlementMandateHash(input.mandate), manifestHash: selected.manifest.manifestHash, capabilityId: selected.manifest.capabilityId, capabilityClass: selected.manifest.capability, sellerId: selected.manifest.sellerId, endpoint: selected.manifest.endpoint, network: "sui:testnet", asset: selected.manifest.asset, rail: selected.rail, openingAmount: opening.toString(), maximumAmount: selected.maximum.toString(), manifestMinimum: selected.manifest.priceBand.minimum, manifestMaximum: selected.manifest.priceBand.maximum, riskLevel: selected.risk, createdAt: now, expiresAt: Math.min(now + 300_000, input.mandate.expiresAt, selected.manifest.expiresAt), citations: selected.citations.sort((a, b) => a.blobId.localeCompare(b.blobId)), reasonCodes: [...new Set(reasons)] };
116
148
  return { ...withoutHash, planHash: settlementPlanHash(withoutHash) };
117
149
  }
@@ -139,3 +171,16 @@ export function validateSettlementPlan(value) {
139
171
  if (!Array.isArray(plan.reasonCodes) || !Array.isArray(plan.citations) || plan.citations.some((citation) => !object(citation) || Object.keys(citation).some((key) => !["blobId", "kind", "provenance", "distance"].includes(key)) || typeof citation.blobId !== "string" || !citation.blobId || typeof citation.distance !== "number" || !Number.isFinite(citation.distance) || citation.distance < 0 || citation.distance > 1))
140
172
  fail("SETTLEMENT_PLAN_INVALID", "settlement plan citations or reasons are invalid");
141
173
  }
174
+ const decision = (plan) => ({ sellerId: plan.sellerId, capabilityId: plan.capabilityId, rail: plan.rail, riskLevel: plan.riskLevel, maximumAmount: plan.maximumAmount });
175
+ /** Counterfactual: what the same mandate would have paid without any recalled memory. Not part of the plan hash. */
176
+ export function explainMemoryInfluence(input, plan) {
177
+ let withoutMemory;
178
+ try {
179
+ withoutMemory = decision(createSettlementPlan({ ...input, recalled: [], now: plan.createdAt }));
180
+ }
181
+ catch {
182
+ withoutMemory = undefined;
183
+ }
184
+ const withMemory = decision(plan);
185
+ return { changedSeller: withoutMemory?.sellerId !== withMemory.sellerId, changedRail: withoutMemory?.rail !== withMemory.rail, changedRisk: withoutMemory?.riskLevel !== withMemory.riskLevel, changedMaximum: withoutMemory?.maximumAmount !== withMemory.maximumAmount, ...(withoutMemory ? { withoutMemory } : {}), withMemory, citedBlobIds: plan.citations.map((item) => item.blobId) };
186
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Public Sui Testnet, Walrus Testnet, and hosted Supercuts endpoints used when an owner leaves a setup field blank.
3
+ * None of these values are credentials; owners can still override every one in setup JSON or the prompts.
4
+ */
5
+ export declare const TESTNET_DEFAULTS: {
6
+ readonly writeGrpc: "https://fullnode.testnet.sui.io:443";
7
+ readonly tatumGrpc: "https://sui-testnet-grpc.gateway.tatum.io:443";
8
+ readonly walrusPublisher: "https://publisher.walrus-testnet.walrus.space";
9
+ readonly walrusAggregator: "https://aggregator.walrus-testnet.walrus.space";
10
+ readonly directoryUrl: "https://supercuts-sellers-testnet.onrender.com";
11
+ };
12
+ /** Pinned experimental v2 Testnet deployment metadata shipped inside the npm package. */
13
+ export declare function bundledDeploymentConfig(): string;
14
+ /** Fills blank endpoint fields with the public Testnet defaults. */
15
+ export declare function withTestnetDefaults<T extends {
16
+ deploymentConfig?: string;
17
+ writeGrpc?: string;
18
+ tatumGrpc?: string;
19
+ walrusPublisher?: string;
20
+ walrusAggregator?: string;
21
+ }>(config: T): T;
@@ -0,0 +1,26 @@
1
+ import { dirname, join } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ /**
4
+ * Public Sui Testnet, Walrus Testnet, and hosted Supercuts endpoints used when an owner leaves a setup field blank.
5
+ * None of these values are credentials; owners can still override every one in setup JSON or the prompts.
6
+ */
7
+ export const TESTNET_DEFAULTS = {
8
+ writeGrpc: "https://fullnode.testnet.sui.io:443",
9
+ tatumGrpc: "https://sui-testnet-grpc.gateway.tatum.io:443",
10
+ walrusPublisher: "https://publisher.walrus-testnet.walrus.space",
11
+ walrusAggregator: "https://aggregator.walrus-testnet.walrus.space",
12
+ directoryUrl: "https://supercuts-sellers-testnet.onrender.com",
13
+ };
14
+ /** Pinned experimental v2 Testnet deployment metadata shipped inside the npm package. */
15
+ export function bundledDeploymentConfig() {
16
+ return join(dirname(fileURLToPath(import.meta.url)), "../config/phase1.testnet.json");
17
+ }
18
+ /** Fills blank endpoint fields with the public Testnet defaults. */
19
+ export function withTestnetDefaults(config) {
20
+ config.deploymentConfig ||= bundledDeploymentConfig();
21
+ config.writeGrpc ||= TESTNET_DEFAULTS.writeGrpc;
22
+ config.tatumGrpc ||= TESTNET_DEFAULTS.tatumGrpc;
23
+ config.walrusPublisher ||= TESTNET_DEFAULTS.walrusPublisher;
24
+ config.walrusAggregator ||= TESTNET_DEFAULTS.walrusAggregator;
25
+ return config;
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supercuts-walrus/backend",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -25,10 +25,12 @@
25
25
  "supercuts-seller-v2-provision": "dist/seller-v2-provision.js",
26
26
  "supercuts-hosted-exit": "dist/hosted-exit-cli.js",
27
27
  "supercuts-hosted-seller-import": "dist/hosted-seller-import.js",
28
- "supercuts-seller-directory": "dist/seller-directory-cli.js"
28
+ "supercuts-seller-directory": "dist/seller-directory-cli.js",
29
+ "supercuts-embedding-adapter": "dist/embedding-adapter.js"
29
30
  },
30
31
  "files": [
31
32
  "dist",
33
+ "config",
32
34
  "README.md"
33
35
  ],
34
36
  "license": "Apache-2.0",