@owney/sdk 0.6.8 → 0.6.9-beta.1
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.cjs +136 -0
- package/dist/index.d.cts +39 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +136 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -660,6 +660,39 @@ function buildProtocolMergeUpdate(available, current, asset) {
|
|
|
660
660
|
};
|
|
661
661
|
}
|
|
662
662
|
|
|
663
|
+
// src/agents/zyfai/splitting.ts
|
|
664
|
+
var MAX_MIN_SPLITS = 4;
|
|
665
|
+
var MIN_FORCE_SPLITS = 2;
|
|
666
|
+
var AUTOMATIC_MIN_SPLITS = 1;
|
|
667
|
+
function toZyfaiSplitting(policy) {
|
|
668
|
+
switch (policy.splittingMode) {
|
|
669
|
+
case "none":
|
|
670
|
+
return { splitting: false };
|
|
671
|
+
case "automatic":
|
|
672
|
+
return { splitting: true, minSplits: AUTOMATIC_MIN_SPLITS };
|
|
673
|
+
case "force":
|
|
674
|
+
return {
|
|
675
|
+
splitting: true,
|
|
676
|
+
minSplits: clampForceSplits(policy.minSplits)
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
function clampForceSplits(minSplits) {
|
|
681
|
+
if (typeof minSplits !== "number" || !Number.isFinite(minSplits)) {
|
|
682
|
+
return MIN_FORCE_SPLITS;
|
|
683
|
+
}
|
|
684
|
+
const rounded = Math.round(minSplits);
|
|
685
|
+
if (rounded < MIN_FORCE_SPLITS) return MIN_FORCE_SPLITS;
|
|
686
|
+
if (rounded > MAX_MIN_SPLITS) return MAX_MIN_SPLITS;
|
|
687
|
+
return rounded;
|
|
688
|
+
}
|
|
689
|
+
function splittingNeedsUpdate(current, desired) {
|
|
690
|
+
if (!current) return true;
|
|
691
|
+
if (current.splitting !== desired.splitting) return true;
|
|
692
|
+
if (desired.minSplits === void 0) return false;
|
|
693
|
+
return current.minSplits !== desired.minSplits;
|
|
694
|
+
}
|
|
695
|
+
|
|
663
696
|
// src/agents/zyfai/zyfai.agent.ts
|
|
664
697
|
var DEFAULT_ZYFAI_RPC_URLS = {
|
|
665
698
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
@@ -672,6 +705,7 @@ var WETH_ADDRESS_BY_CHAIN = {
|
|
|
672
705
|
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
|
|
673
706
|
};
|
|
674
707
|
var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum, 1: import_chains.mainnet };
|
|
708
|
+
var SPLITTING_ASSETS = ["USDC", "WETH"];
|
|
675
709
|
function isAlreadyActiveSessionKeyError(error) {
|
|
676
710
|
const message = error instanceof Error ? error.message : String(error);
|
|
677
711
|
return /already has an active session key/i.test(message);
|
|
@@ -1036,6 +1070,35 @@ var ZyfaiAgent = class {
|
|
|
1036
1070
|
throw error;
|
|
1037
1071
|
}
|
|
1038
1072
|
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Apply the org's capital splitting policy to this user's Zyfai profile.
|
|
1075
|
+
*
|
|
1076
|
+
* Per ASSET, not per chain: Zyfai stores splitting under
|
|
1077
|
+
* `assetTypeSettings[asset]`, so one call would only configure USDC and leave a
|
|
1078
|
+
* WETH holder's real setting untouched.
|
|
1079
|
+
*
|
|
1080
|
+
* Non-fatal throughout. This is a side effect of connecting, so a Zyfai hiccup
|
|
1081
|
+
* must leave the user connected with their profile unchanged, never fail
|
|
1082
|
+
* activation.
|
|
1083
|
+
*/
|
|
1084
|
+
async applyOrgPolicy(_state, _chainId, policy) {
|
|
1085
|
+
await Promise.all(
|
|
1086
|
+
SPLITTING_ASSETS.map((asset) => this.applySplitting(asset, policy))
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
async applySplitting(asset, policy) {
|
|
1090
|
+
try {
|
|
1091
|
+
const desired = toZyfaiSplitting(policy);
|
|
1092
|
+
const current = await this.sdk.getUserDetails(asset);
|
|
1093
|
+
if (!splittingNeedsUpdate(current, desired)) return;
|
|
1094
|
+
await this.sdk.updateUserProfile({ asset, ...desired });
|
|
1095
|
+
} catch (error) {
|
|
1096
|
+
console.warn(
|
|
1097
|
+
`[zyfai] applyOrgPolicy(${asset}) failed (non-fatal):`,
|
|
1098
|
+
error instanceof Error ? error.message : String(error)
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1039
1102
|
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
1040
1103
|
try {
|
|
1041
1104
|
await this.connectFull(state, chainId);
|
|
@@ -1189,6 +1252,34 @@ var ZyfaiAgent = class {
|
|
|
1189
1252
|
|
|
1190
1253
|
// src/lib/routing-api.ts
|
|
1191
1254
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1255
|
+
async function fetchOrgAgentConfig(apiKey) {
|
|
1256
|
+
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/org-config`;
|
|
1257
|
+
try {
|
|
1258
|
+
const res = await fetch(url, {
|
|
1259
|
+
method: "GET",
|
|
1260
|
+
headers: {
|
|
1261
|
+
"Content-Type": "application/json",
|
|
1262
|
+
"x-owney-api-key": `${apiKey}`
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
if (!res.ok) {
|
|
1266
|
+
if (res.status !== 404) {
|
|
1267
|
+
console.warn(
|
|
1268
|
+
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1271
|
+
return null;
|
|
1272
|
+
}
|
|
1273
|
+
const json = await res.json();
|
|
1274
|
+
return json.success ? json.data ?? null : null;
|
|
1275
|
+
} catch (error) {
|
|
1276
|
+
console.warn(
|
|
1277
|
+
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
1278
|
+
error instanceof Error ? error.message : String(error)
|
|
1279
|
+
);
|
|
1280
|
+
return null;
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1192
1283
|
async function fetchAgentKeys(apiKey) {
|
|
1193
1284
|
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/keys`;
|
|
1194
1285
|
const res = await fetch(url, {
|
|
@@ -1802,6 +1893,12 @@ var OwneySDK = class {
|
|
|
1802
1893
|
disabledAgents = /* @__PURE__ */ new Set();
|
|
1803
1894
|
state = null;
|
|
1804
1895
|
apiKey;
|
|
1896
|
+
// The org's agent policy, fetched once per client. Applied to each agent on
|
|
1897
|
+
// activation (ROUT-229). `undefined` means "not fetched yet", `null` means
|
|
1898
|
+
// "fetched, and the partner has no policy" — which is a real answer meaning
|
|
1899
|
+
// leave every user's agent profile alone.
|
|
1900
|
+
orgAgentConfig;
|
|
1901
|
+
orgAgentConfigPromise = null;
|
|
1805
1902
|
zyfaiRpcUrls;
|
|
1806
1903
|
routingApiBaseUrl;
|
|
1807
1904
|
referralSource;
|
|
@@ -1971,6 +2068,43 @@ var OwneySDK = class {
|
|
|
1971
2068
|
}
|
|
1972
2069
|
return active;
|
|
1973
2070
|
}
|
|
2071
|
+
/**
|
|
2072
|
+
* Read the org's agent policy once and reuse it. fetchOrgAgentConfig never
|
|
2073
|
+
* throws — it degrades to null — so this cannot break activation.
|
|
2074
|
+
*/
|
|
2075
|
+
async getOrgAgentConfig() {
|
|
2076
|
+
if (this.orgAgentConfig !== void 0) return this.orgAgentConfig;
|
|
2077
|
+
if (!this.orgAgentConfigPromise) {
|
|
2078
|
+
this.orgAgentConfigPromise = fetchOrgAgentConfig(this.apiKey).then(
|
|
2079
|
+
(config) => {
|
|
2080
|
+
this.orgAgentConfig = config;
|
|
2081
|
+
return config;
|
|
2082
|
+
}
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
2085
|
+
return this.orgAgentConfigPromise;
|
|
2086
|
+
}
|
|
2087
|
+
/**
|
|
2088
|
+
* Apply the org policy to one agent, after it has activated.
|
|
2089
|
+
*
|
|
2090
|
+
* Sequenced after activation rather than alongside it because applying the
|
|
2091
|
+
* policy needs the authenticated session activation establishes. Every failure
|
|
2092
|
+
* mode is swallowed: a partner's splitting preference is not worth failing a
|
|
2093
|
+
* user's connect over.
|
|
2094
|
+
*/
|
|
2095
|
+
async applyOrgPolicyTo(agent, state, chainId) {
|
|
2096
|
+
if (!agent.applyOrgPolicy) return;
|
|
2097
|
+
try {
|
|
2098
|
+
const policy = await this.getOrgAgentConfig();
|
|
2099
|
+
if (!policy) return;
|
|
2100
|
+
await agent.applyOrgPolicy(state, chainId, policy);
|
|
2101
|
+
} catch (error) {
|
|
2102
|
+
console.warn(
|
|
2103
|
+
`[owney-sdk] applyOrgPolicy(${agent.id}) failed (non-fatal):`,
|
|
2104
|
+
error instanceof Error ? error.message : String(error)
|
|
2105
|
+
);
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
1974
2108
|
async ensureAgentsInitialized() {
|
|
1975
2109
|
if (this.agents.size > 0) return;
|
|
1976
2110
|
if (!this.initializingAgentsPromise) {
|
|
@@ -2055,6 +2189,7 @@ var OwneySDK = class {
|
|
|
2055
2189
|
Promise.all(
|
|
2056
2190
|
agents.map(async (agent) => {
|
|
2057
2191
|
await agent.activateAgent(state, chainId);
|
|
2192
|
+
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2058
2193
|
})
|
|
2059
2194
|
).catch((error) => {
|
|
2060
2195
|
console.error("activateAgent background init failed:", error);
|
|
@@ -2082,6 +2217,7 @@ var OwneySDK = class {
|
|
|
2082
2217
|
Promise.all(
|
|
2083
2218
|
enabledCompatible.map(async (agent) => {
|
|
2084
2219
|
await agent.activateAgent(state, chainId);
|
|
2220
|
+
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2085
2221
|
})
|
|
2086
2222
|
).catch((error) => {
|
|
2087
2223
|
console.error("activateAgent background init failed:", error);
|
package/dist/index.d.cts
CHANGED
|
@@ -101,6 +101,16 @@ type DepositOptions = {
|
|
|
101
101
|
onApproved?: () => void;
|
|
102
102
|
};
|
|
103
103
|
|
|
104
|
+
/**
|
|
105
|
+
* The organization's agent execution policy, or null when the partner has never
|
|
106
|
+
* configured one — in which case the agents leave the user's profile alone.
|
|
107
|
+
* Currently capital splitting only (ROUT-229).
|
|
108
|
+
*/
|
|
109
|
+
type OrgAgentConfig = {
|
|
110
|
+
splittingMode: "none" | "automatic" | "force";
|
|
111
|
+
minSplits: number | null;
|
|
112
|
+
};
|
|
113
|
+
|
|
104
114
|
interface OwneyDepositResult {
|
|
105
115
|
txHash: string;
|
|
106
116
|
smartWallet: string;
|
|
@@ -275,6 +285,19 @@ interface IAgent {
|
|
|
275
285
|
readonly supportedAssets: readonly AgentSupportedAssets[];
|
|
276
286
|
disconnect(): Promise<void>;
|
|
277
287
|
activateAgent(state: ConnectionState, chainId: number): Promise<void>;
|
|
288
|
+
/**
|
|
289
|
+
* Apply the organization's agent policy to this user's account.
|
|
290
|
+
*
|
|
291
|
+
* Optional: an agent that has no equivalent knob simply omits it, which is why
|
|
292
|
+
* this is not part of `activateAgent`'s signature. Declared on the interface
|
|
293
|
+
* rather than only on ZyfaiAgent so the contract stays agent-neutral — the
|
|
294
|
+
* ticket asks for a design that can also cover Surf, which has no adapter yet.
|
|
295
|
+
*
|
|
296
|
+
* Implementations must be **non-fatal**: this runs during activation as a side
|
|
297
|
+
* effect, so a failure has to leave the user connected and their profile
|
|
298
|
+
* unchanged rather than break the connect.
|
|
299
|
+
*/
|
|
300
|
+
applyOrgPolicy?(state: ConnectionState, chainId: number, policy: OrgAgentConfig): Promise<void>;
|
|
278
301
|
deposit(state: ConnectionState, chainId: number, amount: string, asset: OwneySupportedTokens, depositCallback?: DepositCallback): Promise<OwneyDepositResult>;
|
|
279
302
|
withdraw(state: ConnectionState, chainId: number, token: OwneySupportedTokens, amount?: string): Promise<AgentWithdrawResult>;
|
|
280
303
|
getBalances(state: ConnectionState, chainId: number): Promise<AgentBalance>;
|
|
@@ -318,6 +341,8 @@ declare class OwneySDK {
|
|
|
318
341
|
private disabledAgents;
|
|
319
342
|
private state;
|
|
320
343
|
private apiKey;
|
|
344
|
+
private orgAgentConfig;
|
|
345
|
+
private orgAgentConfigPromise;
|
|
321
346
|
private zyfaiRpcUrls?;
|
|
322
347
|
private routingApiBaseUrl?;
|
|
323
348
|
private referralSource?;
|
|
@@ -366,6 +391,20 @@ declare class OwneySDK {
|
|
|
366
391
|
private getDefaultWethSponsoredCallback;
|
|
367
392
|
private getAgent;
|
|
368
393
|
private getActiveAgents;
|
|
394
|
+
/**
|
|
395
|
+
* Read the org's agent policy once and reuse it. fetchOrgAgentConfig never
|
|
396
|
+
* throws — it degrades to null — so this cannot break activation.
|
|
397
|
+
*/
|
|
398
|
+
private getOrgAgentConfig;
|
|
399
|
+
/**
|
|
400
|
+
* Apply the org policy to one agent, after it has activated.
|
|
401
|
+
*
|
|
402
|
+
* Sequenced after activation rather than alongside it because applying the
|
|
403
|
+
* policy needs the authenticated session activation establishes. Every failure
|
|
404
|
+
* mode is swallowed: a partner's splitting preference is not worth failing a
|
|
405
|
+
* user's connect over.
|
|
406
|
+
*/
|
|
407
|
+
private applyOrgPolicyTo;
|
|
369
408
|
private ensureAgentsInitialized;
|
|
370
409
|
private createAgent;
|
|
371
410
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -101,6 +101,16 @@ type DepositOptions = {
|
|
|
101
101
|
onApproved?: () => void;
|
|
102
102
|
};
|
|
103
103
|
|
|
104
|
+
/**
|
|
105
|
+
* The organization's agent execution policy, or null when the partner has never
|
|
106
|
+
* configured one — in which case the agents leave the user's profile alone.
|
|
107
|
+
* Currently capital splitting only (ROUT-229).
|
|
108
|
+
*/
|
|
109
|
+
type OrgAgentConfig = {
|
|
110
|
+
splittingMode: "none" | "automatic" | "force";
|
|
111
|
+
minSplits: number | null;
|
|
112
|
+
};
|
|
113
|
+
|
|
104
114
|
interface OwneyDepositResult {
|
|
105
115
|
txHash: string;
|
|
106
116
|
smartWallet: string;
|
|
@@ -275,6 +285,19 @@ interface IAgent {
|
|
|
275
285
|
readonly supportedAssets: readonly AgentSupportedAssets[];
|
|
276
286
|
disconnect(): Promise<void>;
|
|
277
287
|
activateAgent(state: ConnectionState, chainId: number): Promise<void>;
|
|
288
|
+
/**
|
|
289
|
+
* Apply the organization's agent policy to this user's account.
|
|
290
|
+
*
|
|
291
|
+
* Optional: an agent that has no equivalent knob simply omits it, which is why
|
|
292
|
+
* this is not part of `activateAgent`'s signature. Declared on the interface
|
|
293
|
+
* rather than only on ZyfaiAgent so the contract stays agent-neutral — the
|
|
294
|
+
* ticket asks for a design that can also cover Surf, which has no adapter yet.
|
|
295
|
+
*
|
|
296
|
+
* Implementations must be **non-fatal**: this runs during activation as a side
|
|
297
|
+
* effect, so a failure has to leave the user connected and their profile
|
|
298
|
+
* unchanged rather than break the connect.
|
|
299
|
+
*/
|
|
300
|
+
applyOrgPolicy?(state: ConnectionState, chainId: number, policy: OrgAgentConfig): Promise<void>;
|
|
278
301
|
deposit(state: ConnectionState, chainId: number, amount: string, asset: OwneySupportedTokens, depositCallback?: DepositCallback): Promise<OwneyDepositResult>;
|
|
279
302
|
withdraw(state: ConnectionState, chainId: number, token: OwneySupportedTokens, amount?: string): Promise<AgentWithdrawResult>;
|
|
280
303
|
getBalances(state: ConnectionState, chainId: number): Promise<AgentBalance>;
|
|
@@ -318,6 +341,8 @@ declare class OwneySDK {
|
|
|
318
341
|
private disabledAgents;
|
|
319
342
|
private state;
|
|
320
343
|
private apiKey;
|
|
344
|
+
private orgAgentConfig;
|
|
345
|
+
private orgAgentConfigPromise;
|
|
321
346
|
private zyfaiRpcUrls?;
|
|
322
347
|
private routingApiBaseUrl?;
|
|
323
348
|
private referralSource?;
|
|
@@ -366,6 +391,20 @@ declare class OwneySDK {
|
|
|
366
391
|
private getDefaultWethSponsoredCallback;
|
|
367
392
|
private getAgent;
|
|
368
393
|
private getActiveAgents;
|
|
394
|
+
/**
|
|
395
|
+
* Read the org's agent policy once and reuse it. fetchOrgAgentConfig never
|
|
396
|
+
* throws — it degrades to null — so this cannot break activation.
|
|
397
|
+
*/
|
|
398
|
+
private getOrgAgentConfig;
|
|
399
|
+
/**
|
|
400
|
+
* Apply the org policy to one agent, after it has activated.
|
|
401
|
+
*
|
|
402
|
+
* Sequenced after activation rather than alongside it because applying the
|
|
403
|
+
* policy needs the authenticated session activation establishes. Every failure
|
|
404
|
+
* mode is swallowed: a partner's splitting preference is not worth failing a
|
|
405
|
+
* user's connect over.
|
|
406
|
+
*/
|
|
407
|
+
private applyOrgPolicyTo;
|
|
369
408
|
private ensureAgentsInitialized;
|
|
370
409
|
private createAgent;
|
|
371
410
|
/**
|
package/dist/index.js
CHANGED
|
@@ -628,6 +628,39 @@ function buildProtocolMergeUpdate(available, current, asset) {
|
|
|
628
628
|
};
|
|
629
629
|
}
|
|
630
630
|
|
|
631
|
+
// src/agents/zyfai/splitting.ts
|
|
632
|
+
var MAX_MIN_SPLITS = 4;
|
|
633
|
+
var MIN_FORCE_SPLITS = 2;
|
|
634
|
+
var AUTOMATIC_MIN_SPLITS = 1;
|
|
635
|
+
function toZyfaiSplitting(policy) {
|
|
636
|
+
switch (policy.splittingMode) {
|
|
637
|
+
case "none":
|
|
638
|
+
return { splitting: false };
|
|
639
|
+
case "automatic":
|
|
640
|
+
return { splitting: true, minSplits: AUTOMATIC_MIN_SPLITS };
|
|
641
|
+
case "force":
|
|
642
|
+
return {
|
|
643
|
+
splitting: true,
|
|
644
|
+
minSplits: clampForceSplits(policy.minSplits)
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
function clampForceSplits(minSplits) {
|
|
649
|
+
if (typeof minSplits !== "number" || !Number.isFinite(minSplits)) {
|
|
650
|
+
return MIN_FORCE_SPLITS;
|
|
651
|
+
}
|
|
652
|
+
const rounded = Math.round(minSplits);
|
|
653
|
+
if (rounded < MIN_FORCE_SPLITS) return MIN_FORCE_SPLITS;
|
|
654
|
+
if (rounded > MAX_MIN_SPLITS) return MAX_MIN_SPLITS;
|
|
655
|
+
return rounded;
|
|
656
|
+
}
|
|
657
|
+
function splittingNeedsUpdate(current, desired) {
|
|
658
|
+
if (!current) return true;
|
|
659
|
+
if (current.splitting !== desired.splitting) return true;
|
|
660
|
+
if (desired.minSplits === void 0) return false;
|
|
661
|
+
return current.minSplits !== desired.minSplits;
|
|
662
|
+
}
|
|
663
|
+
|
|
631
664
|
// src/agents/zyfai/zyfai.agent.ts
|
|
632
665
|
var DEFAULT_ZYFAI_RPC_URLS = {
|
|
633
666
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
@@ -640,6 +673,7 @@ var WETH_ADDRESS_BY_CHAIN = {
|
|
|
640
673
|
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
|
|
641
674
|
};
|
|
642
675
|
var VIEM_CHAIN = { 8453: base, 42161: arbitrum, 1: mainnet };
|
|
676
|
+
var SPLITTING_ASSETS = ["USDC", "WETH"];
|
|
643
677
|
function isAlreadyActiveSessionKeyError(error) {
|
|
644
678
|
const message = error instanceof Error ? error.message : String(error);
|
|
645
679
|
return /already has an active session key/i.test(message);
|
|
@@ -1004,6 +1038,35 @@ var ZyfaiAgent = class {
|
|
|
1004
1038
|
throw error;
|
|
1005
1039
|
}
|
|
1006
1040
|
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Apply the org's capital splitting policy to this user's Zyfai profile.
|
|
1043
|
+
*
|
|
1044
|
+
* Per ASSET, not per chain: Zyfai stores splitting under
|
|
1045
|
+
* `assetTypeSettings[asset]`, so one call would only configure USDC and leave a
|
|
1046
|
+
* WETH holder's real setting untouched.
|
|
1047
|
+
*
|
|
1048
|
+
* Non-fatal throughout. This is a side effect of connecting, so a Zyfai hiccup
|
|
1049
|
+
* must leave the user connected with their profile unchanged, never fail
|
|
1050
|
+
* activation.
|
|
1051
|
+
*/
|
|
1052
|
+
async applyOrgPolicy(_state, _chainId, policy) {
|
|
1053
|
+
await Promise.all(
|
|
1054
|
+
SPLITTING_ASSETS.map((asset) => this.applySplitting(asset, policy))
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
async applySplitting(asset, policy) {
|
|
1058
|
+
try {
|
|
1059
|
+
const desired = toZyfaiSplitting(policy);
|
|
1060
|
+
const current = await this.sdk.getUserDetails(asset);
|
|
1061
|
+
if (!splittingNeedsUpdate(current, desired)) return;
|
|
1062
|
+
await this.sdk.updateUserProfile({ asset, ...desired });
|
|
1063
|
+
} catch (error) {
|
|
1064
|
+
console.warn(
|
|
1065
|
+
`[zyfai] applyOrgPolicy(${asset}) failed (non-fatal):`,
|
|
1066
|
+
error instanceof Error ? error.message : String(error)
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1007
1070
|
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
1008
1071
|
try {
|
|
1009
1072
|
await this.connectFull(state, chainId);
|
|
@@ -1157,6 +1220,34 @@ var ZyfaiAgent = class {
|
|
|
1157
1220
|
|
|
1158
1221
|
// src/lib/routing-api.ts
|
|
1159
1222
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1223
|
+
async function fetchOrgAgentConfig(apiKey) {
|
|
1224
|
+
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/org-config`;
|
|
1225
|
+
try {
|
|
1226
|
+
const res = await fetch(url, {
|
|
1227
|
+
method: "GET",
|
|
1228
|
+
headers: {
|
|
1229
|
+
"Content-Type": "application/json",
|
|
1230
|
+
"x-owney-api-key": `${apiKey}`
|
|
1231
|
+
}
|
|
1232
|
+
});
|
|
1233
|
+
if (!res.ok) {
|
|
1234
|
+
if (res.status !== 404) {
|
|
1235
|
+
console.warn(
|
|
1236
|
+
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
return null;
|
|
1240
|
+
}
|
|
1241
|
+
const json = await res.json();
|
|
1242
|
+
return json.success ? json.data ?? null : null;
|
|
1243
|
+
} catch (error) {
|
|
1244
|
+
console.warn(
|
|
1245
|
+
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
1246
|
+
error instanceof Error ? error.message : String(error)
|
|
1247
|
+
);
|
|
1248
|
+
return null;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1160
1251
|
async function fetchAgentKeys(apiKey) {
|
|
1161
1252
|
const url = `${ROUTING_API_BASE_URL}/api/v1/agent/keys`;
|
|
1162
1253
|
const res = await fetch(url, {
|
|
@@ -1774,6 +1865,12 @@ var OwneySDK = class {
|
|
|
1774
1865
|
disabledAgents = /* @__PURE__ */ new Set();
|
|
1775
1866
|
state = null;
|
|
1776
1867
|
apiKey;
|
|
1868
|
+
// The org's agent policy, fetched once per client. Applied to each agent on
|
|
1869
|
+
// activation (ROUT-229). `undefined` means "not fetched yet", `null` means
|
|
1870
|
+
// "fetched, and the partner has no policy" — which is a real answer meaning
|
|
1871
|
+
// leave every user's agent profile alone.
|
|
1872
|
+
orgAgentConfig;
|
|
1873
|
+
orgAgentConfigPromise = null;
|
|
1777
1874
|
zyfaiRpcUrls;
|
|
1778
1875
|
routingApiBaseUrl;
|
|
1779
1876
|
referralSource;
|
|
@@ -1943,6 +2040,43 @@ var OwneySDK = class {
|
|
|
1943
2040
|
}
|
|
1944
2041
|
return active;
|
|
1945
2042
|
}
|
|
2043
|
+
/**
|
|
2044
|
+
* Read the org's agent policy once and reuse it. fetchOrgAgentConfig never
|
|
2045
|
+
* throws — it degrades to null — so this cannot break activation.
|
|
2046
|
+
*/
|
|
2047
|
+
async getOrgAgentConfig() {
|
|
2048
|
+
if (this.orgAgentConfig !== void 0) return this.orgAgentConfig;
|
|
2049
|
+
if (!this.orgAgentConfigPromise) {
|
|
2050
|
+
this.orgAgentConfigPromise = fetchOrgAgentConfig(this.apiKey).then(
|
|
2051
|
+
(config) => {
|
|
2052
|
+
this.orgAgentConfig = config;
|
|
2053
|
+
return config;
|
|
2054
|
+
}
|
|
2055
|
+
);
|
|
2056
|
+
}
|
|
2057
|
+
return this.orgAgentConfigPromise;
|
|
2058
|
+
}
|
|
2059
|
+
/**
|
|
2060
|
+
* Apply the org policy to one agent, after it has activated.
|
|
2061
|
+
*
|
|
2062
|
+
* Sequenced after activation rather than alongside it because applying the
|
|
2063
|
+
* policy needs the authenticated session activation establishes. Every failure
|
|
2064
|
+
* mode is swallowed: a partner's splitting preference is not worth failing a
|
|
2065
|
+
* user's connect over.
|
|
2066
|
+
*/
|
|
2067
|
+
async applyOrgPolicyTo(agent, state, chainId) {
|
|
2068
|
+
if (!agent.applyOrgPolicy) return;
|
|
2069
|
+
try {
|
|
2070
|
+
const policy = await this.getOrgAgentConfig();
|
|
2071
|
+
if (!policy) return;
|
|
2072
|
+
await agent.applyOrgPolicy(state, chainId, policy);
|
|
2073
|
+
} catch (error) {
|
|
2074
|
+
console.warn(
|
|
2075
|
+
`[owney-sdk] applyOrgPolicy(${agent.id}) failed (non-fatal):`,
|
|
2076
|
+
error instanceof Error ? error.message : String(error)
|
|
2077
|
+
);
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
1946
2080
|
async ensureAgentsInitialized() {
|
|
1947
2081
|
if (this.agents.size > 0) return;
|
|
1948
2082
|
if (!this.initializingAgentsPromise) {
|
|
@@ -2027,6 +2161,7 @@ var OwneySDK = class {
|
|
|
2027
2161
|
Promise.all(
|
|
2028
2162
|
agents.map(async (agent) => {
|
|
2029
2163
|
await agent.activateAgent(state, chainId);
|
|
2164
|
+
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2030
2165
|
})
|
|
2031
2166
|
).catch((error) => {
|
|
2032
2167
|
console.error("activateAgent background init failed:", error);
|
|
@@ -2054,6 +2189,7 @@ var OwneySDK = class {
|
|
|
2054
2189
|
Promise.all(
|
|
2055
2190
|
enabledCompatible.map(async (agent) => {
|
|
2056
2191
|
await agent.activateAgent(state, chainId);
|
|
2192
|
+
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
2057
2193
|
})
|
|
2058
2194
|
).catch((error) => {
|
|
2059
2195
|
console.error("activateAgent background init failed:", error);
|