@lifi/composer-sdk 0.8.1 → 0.9.0
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/README.md +3 -2
- package/dist/_virtual/_rolldown/runtime.cjs +33 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/authoring/FlowBuilderCore.cjs +102 -120
- package/dist/authoring/FlowBuilderCore.cjs.map +1 -1
- package/dist/authoring/FlowBuilderCore.d.cts +58 -61
- package/dist/authoring/FlowBuilderCore.d.ts +58 -61
- package/dist/authoring/FlowBuilderCore.js +99 -97
- package/dist/authoring/FlowBuilderCore.js.map +1 -1
- package/dist/authoring/handles.cjs +25 -40
- package/dist/authoring/handles.cjs.map +1 -1
- package/dist/authoring/handles.d.cts +33 -34
- package/dist/authoring/handles.d.ts +33 -34
- package/dist/authoring/handles.js +21 -13
- package/dist/authoring/handles.js.map +1 -1
- package/dist/authoring/raw.cjs +85 -44
- package/dist/authoring/raw.cjs.map +1 -1
- package/dist/authoring/raw.d.cts +8 -8
- package/dist/authoring/raw.d.ts +8 -8
- package/dist/authoring/raw.js +83 -19
- package/dist/authoring/raw.js.map +1 -1
- package/dist/authoring/signatureArgs.cjs +81 -103
- package/dist/authoring/signatureArgs.cjs.map +1 -1
- package/dist/authoring/signatureArgs.d.cts +63 -64
- package/dist/authoring/signatureArgs.d.ts +63 -64
- package/dist/authoring/signatureArgs.js +76 -75
- package/dist/authoring/signatureArgs.js.map +1 -1
- package/dist/client.cjs +172 -220
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +131 -131
- package/dist/client.d.ts +131 -131
- package/dist/client.js +165 -198
- package/dist/client.js.map +1 -1
- package/dist/discovery.cjs +0 -17
- package/dist/discovery.d.cts +57 -56
- package/dist/discovery.d.ts +57 -56
- package/dist/discovery.js +1 -1
- package/dist/errors.cjs +211 -159
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +84 -84
- package/dist/errors.d.ts +84 -84
- package/dist/errors.js +201 -120
- package/dist/errors.js.map +1 -1
- package/dist/generated/config.generated.cjs +0 -17
- package/dist/generated/config.generated.d.cts +804 -936
- package/dist/generated/config.generated.d.ts +804 -936
- package/dist/generated/config.generated.js +1 -1
- package/dist/generated/guards.generated.cjs +25 -35
- package/dist/generated/guards.generated.cjs.map +1 -1
- package/dist/generated/guards.generated.d.cts +20 -4
- package/dist/generated/guards.generated.d.ts +20 -4
- package/dist/generated/guards.generated.js +19 -11
- package/dist/generated/guards.generated.js.map +1 -1
- package/dist/generated/materialisers.generated.cjs +25 -35
- package/dist/generated/materialisers.generated.cjs.map +1 -1
- package/dist/generated/materialisers.generated.d.cts +17 -4
- package/dist/generated/materialisers.generated.d.ts +17 -4
- package/dist/generated/materialisers.generated.js +19 -11
- package/dist/generated/materialisers.generated.js.map +1 -1
- package/dist/generated/operations.generated.cjs +236 -277
- package/dist/generated/operations.generated.cjs.map +1 -1
- package/dist/generated/operations.generated.d.cts +719 -708
- package/dist/generated/operations.generated.d.ts +719 -708
- package/dist/generated/operations.generated.js +235 -256
- package/dist/generated/operations.generated.js.map +1 -1
- package/dist/generated/preconditions.generated.cjs +25 -35
- package/dist/generated/preconditions.generated.cjs.map +1 -1
- package/dist/generated/preconditions.generated.d.cts +17 -4
- package/dist/generated/preconditions.generated.d.ts +17 -4
- package/dist/generated/preconditions.generated.js +19 -11
- package/dist/generated/preconditions.generated.js.map +1 -1
- package/dist/index.cjs +131 -97
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -43
- package/dist/index.d.ts +29 -43
- package/dist/index.js +96 -45
- package/dist/index.js.map +1 -1
- package/dist/outputs.cjs +11 -32
- package/dist/outputs.cjs.map +1 -1
- package/dist/outputs.d.cts +5 -5
- package/dist/outputs.d.ts +5 -5
- package/dist/outputs.js +10 -8
- package/dist/outputs.js.map +1 -1
- package/dist/raw.cjs +21 -33
- package/dist/raw.cjs.map +1 -1
- package/dist/raw.d.cts +8 -4
- package/dist/raw.d.ts +8 -4
- package/dist/raw.js +12 -7
- package/dist/raw.js.map +1 -1
- package/dist/reachability.cjs +82 -112
- package/dist/reachability.cjs.map +1 -1
- package/dist/reachability.d.cts +33 -59
- package/dist/reachability.d.ts +33 -59
- package/dist/reachability.js +81 -88
- package/dist/reachability.js.map +1 -1
- package/dist/resources.cjs +47 -32
- package/dist/resources.cjs.map +1 -1
- package/dist/resources.d.cts +50 -3
- package/dist/resources.d.ts +50 -3
- package/dist/resources.js +42 -9
- package/dist/resources.js.map +1 -1
- package/dist/responseSchemas.cjs +99 -111
- package/dist/responseSchemas.cjs.map +1 -1
- package/dist/responseSchemas.d.cts +34 -34
- package/dist/responseSchemas.d.ts +34 -34
- package/dist/responseSchemas.js +85 -66
- package/dist/responseSchemas.js.map +1 -1
- package/dist/routeAmount.cjs +61 -31
- package/dist/routeAmount.cjs.map +1 -1
- package/dist/routeAmount.d.cts +52 -2
- package/dist/routeAmount.d.ts +52 -2
- package/dist/routeAmount.js +56 -8
- package/dist/routeAmount.js.map +1 -1
- package/dist/run/inputs.cjs +56 -48
- package/dist/run/inputs.cjs.map +1 -1
- package/dist/run/inputs.d.cts +70 -74
- package/dist/run/inputs.d.ts +70 -74
- package/dist/run/inputs.js +54 -23
- package/dist/run/inputs.js.map +1 -1
- package/dist/run/simulate.cjs +38 -43
- package/dist/run/simulate.cjs.map +1 -1
- package/dist/run/simulate.d.cts +36 -36
- package/dist/run/simulate.d.ts +36 -36
- package/dist/run/simulate.js +37 -19
- package/dist/run/simulate.js.map +1 -1
- package/dist/sdk.cjs +55 -66
- package/dist/sdk.cjs.map +1 -1
- package/dist/sdk.d.cts +108 -111
- package/dist/sdk.d.ts +108 -111
- package/dist/sdk.js +52 -44
- package/dist/sdk.js.map +1 -1
- package/dist/types.cjs +0 -17
- package/dist/types.d.cts +22 -22
- package/dist/types.d.ts +22 -22
- package/dist/types.js +1 -1
- package/package.json +4 -4
- package/src/client.ts +2 -2
- package/src/examples/aaveClaimRewards.ts +2 -1
- package/src/examples/emitCustomEvent.ts +1 -2
- package/src/examples/run.ts +1 -1
- package/src/examples/transferTokens.ts +21 -17
- package/src/generated/config.generated.ts +20 -9
- package/src/generated/operations.generated.ts +28 -5
- package/dist/discovery.cjs.map +0 -1
- package/dist/discovery.js.map +0 -1
- package/dist/generated/config.generated.cjs.map +0 -1
- package/dist/generated/config.generated.js.map +0 -1
- package/dist/guards.generated-CDCgYGZo.d.cts +0 -24
- package/dist/guards.generated-CdYcs4h0.d.ts +0 -24
- package/dist/materialisers.generated-BMkBQgWZ.d.ts +0 -24
- package/dist/materialisers.generated-BWq5oePO.d.cts +0 -24
- package/dist/preconditions.generated-DblS13Wq.d.cts +0 -24
- package/dist/preconditions.generated-U7YpVh30.d.ts +0 -24
- package/dist/raw-BvRghN3r.d.ts +0 -20
- package/dist/raw-s1rer8X3.d.cts +0 -20
- package/dist/resources-BKlFxjo8.d.cts +0 -56
- package/dist/resources-CYis1_DS.d.ts +0 -56
- package/dist/routeAmount-DdbJYJyM.d.cts +0 -55
- package/dist/routeAmount-DdbJYJyM.d.ts +0 -55
- package/dist/types.cjs.map +0 -1
- package/dist/types.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/reachability.ts"],"sourcesContent":["/**\n * Client-side reachability over the zap-pack catalog.\n *\n * `GET /compose/zap-packs` lists single routing edges. `POST /compose/route`\n * chains up to the server's hop budget of them, so the set of routable pairs\n * is the closure of the catalog, not the catalog itself. This module computes\n * that closure locally with the planner's admissibility rule, so an integrator\n * can offer every pair `route` connects without a request per pair.\n *\n * The rule, mirrored from the server's route search:\n *\n * - every edge except the last must leave its output in the proxy for the\n * next edge to consume: no `availability`, no `recipient: 'required'`\n * - the last edge must be synchronous, or `availability: 'future'` when the\n * caller opts into `allowAsyncRoutes`\n * - a route never visits the same token twice\n *\n * Amount bounds (`inAmountMin` / `inAmountMax`) on an intermediate edge\n * cannot be checked without an amount, so a pair reported here is routable\n * structurally, exactly as a listed edge is. Routes that open with a\n * `lifi.swap` are not enumerable and are not reported. The server also\n * drops blacklisted tokens as intermediates, which is server-side config\n * this module cannot see, so a reported pair may still answer\n * `no_route_error`.\n */\n\nimport type { ZapPackEdge, ZapPackOverview } from './discovery.js';\n\n/** A token identified by address and chain. */\nexport interface TokenRef {\n readonly address: string;\n readonly chainId: number;\n}\n\n/** A from/to pair `POST /compose/route` can connect through the catalog. */\nexport interface RoutablePair {\n readonly in: TokenRef;\n readonly out: TokenRef;\n /** Catalog edges on the shortest admissible route; `1` is a listed edge. */\n readonly hops: number;\n}\n\nexport interface ReachabilityOptions {\n /**\n * Hop budget. The server's `no_route_error` reports its effective value in\n * `details.maxHops`; the deployment default is 2.\n */\n readonly maxHops?: number;\n /**\n * Admit a route whose last edge has `availability: 'future'`. Mirrors the\n * `allowAsyncRoutes` request option; such a pair is a `no_route_error`\n * without it.\n */\n readonly allowAsyncRoutes?: boolean;\n}\n\nexport interface Reachability {\n readonly maxHops: number;\n /** Whether `route` can connect `from` to `to` through the catalog. */\n readonly canRoute: (from: TokenRef, to: TokenRef) => boolean;\n /** Every pair starting at `from`, shortest routes first. */\n readonly routableFrom: (from: TokenRef) => readonly RoutablePair[];\n /** Every routable pair in the catalog. */\n readonly pairs: () => readonly RoutablePair[];\n}\n\nconst DEFAULT_MAX_HOPS = 2;\n\nconst tokenKey = (token: TokenRef): string =>\n `${token.chainId}:${token.address.toLowerCase()}`;\n\nconst isSync = (edge: ZapPackEdge): boolean => edge.availability === undefined;\n\n// The output stays in the proxy, so a following edge can consume it.\nconst isProxyHeld = (edge: ZapPackEdge): boolean =>\n isSync(edge) && edge.recipient !== 'required';\n\n// One edge out of a frontier token. Records the pair it completes, and returns\n// its output when a further hop may consume it (proxy-held) and no shorter\n// path already expanded that token.\nconst visitEdge = ({\n edge,\n from,\n depth,\n sourceKey,\n isTerminal,\n found,\n expanded,\n}: {\n readonly edge: ZapPackEdge;\n readonly from: TokenRef;\n readonly depth: number;\n readonly sourceKey: string;\n readonly isTerminal: (edge: ZapPackEdge) => boolean;\n readonly found: Map<string, RoutablePair>;\n readonly expanded: Set<string>;\n}): TokenRef | undefined => {\n const key = tokenKey(edge.out);\n if (key === sourceKey) return undefined;\n if (isTerminal(edge) && !found.has(key)) {\n found.set(key, { in: from, out: edge.out, hops: depth });\n }\n if (!isProxyHeld(edge) || expanded.has(key)) return undefined;\n expanded.add(key);\n return edge.out;\n};\n\n// Every pair reachable from one token within `maxHops`, breadth-first so the\n// recorded hop count is the shortest one.\nconst closureFrom = ({\n byIn,\n from,\n maxHops,\n isTerminal,\n}: {\n readonly byIn: ReadonlyMap<string, readonly ZapPackEdge[]>;\n readonly from: TokenRef;\n readonly maxHops: number;\n readonly isTerminal: (edge: ZapPackEdge) => boolean;\n}): Map<string, RoutablePair> => {\n const sourceKey = tokenKey(from);\n const found = new Map<string, RoutablePair>();\n const expanded = new Set<string>([sourceKey]);\n let frontier: readonly TokenRef[] = [from];\n for (let depth = 1; depth <= maxHops && frontier.length > 0; depth++) {\n const next: TokenRef[] = [];\n for (const node of frontier) {\n for (const edge of byIn.get(tokenKey(node)) ?? []) {\n const out = visitEdge({\n edge,\n from,\n depth,\n sourceKey,\n isTerminal,\n found,\n expanded,\n });\n if (out) next.push(out);\n }\n }\n frontier = next;\n }\n return found;\n};\n\nconst indexByIn = (\n packs: readonly ZapPackOverview[],\n): Map<string, ZapPackEdge[]> => {\n const byIn = new Map<string, ZapPackEdge[]>();\n for (const pack of packs) {\n for (const edge of pack.edges) {\n const key = tokenKey(edge.in);\n const list = byIn.get(key);\n if (list) list.push(edge);\n else byIn.set(key, [edge]);\n }\n }\n return byIn;\n};\n\n/**\n * Builds a reachability index over the packs returned by\n * {@link ComposeClient.getZapPacks}. Per-source closures are computed on\n * first use and memoised, so `canRoute` on a handful of pairs stays cheap\n * while `pairs()` enumerates everything.\n */\nexport const buildReachability = (\n packs: readonly ZapPackOverview[],\n options: ReachabilityOptions = {},\n): Reachability => {\n const maxHops = options.maxHops ?? DEFAULT_MAX_HOPS;\n const allowAsync = options.allowAsyncRoutes ?? false;\n const isTerminal = (edge: ZapPackEdge): boolean =>\n isSync(edge) || (allowAsync && edge.availability === 'future');\n\n const byIn = indexByIn(packs);\n const memo = new Map<string, Map<string, RoutablePair>>();\n const closure = (from: TokenRef): Map<string, RoutablePair> => {\n const key = tokenKey(from);\n const cached = memo.get(key);\n if (cached) return cached;\n const computed = closureFrom({ byIn, from, maxHops, isTerminal });\n memo.set(key, computed);\n return computed;\n };\n\n return {\n maxHops,\n canRoute: (from, to) => closure(from).has(tokenKey(to)),\n routableFrom: (from) => [...closure(from).values()],\n pairs: () => {\n const sources = new Map<string, TokenRef>();\n for (const pack of packs) {\n for (const edge of pack.edges) sources.set(tokenKey(edge.in), edge.in);\n }\n const all: RoutablePair[] = [];\n for (const source of sources.values()) {\n all.push(...closure(source).values());\n }\n return all;\n },\n };\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"reachability.cjs","names":[],"sources":["../src/reachability.ts"],"sourcesContent":["/**\n * Client-side reachability over the zap-pack catalog.\n *\n * `GET /compose/zap-packs` lists single routing edges. `POST /compose/route`\n * chains up to the server's hop budget of them, so the set of routable pairs\n * is the closure of the catalog, not the catalog itself. This module computes\n * that closure locally with the planner's admissibility rule, so an integrator\n * can offer every pair `route` connects without a request per pair.\n *\n * The rule, mirrored from the server's route search:\n *\n * - every edge except the last must leave its output in the proxy for the\n * next edge to consume: no `availability`, no `recipient: 'required'`\n * - the last edge must be synchronous, or `availability: 'future'` when the\n * caller opts into `allowAsyncRoutes`\n * - a route never visits the same token twice\n *\n * Amount bounds (`inAmountMin` / `inAmountMax`) on an intermediate edge\n * cannot be checked without an amount, so a pair reported here is routable\n * structurally, exactly as a listed edge is. Routes that open with a\n * `lifi.swap` are not enumerable and are not reported. The server also\n * drops blacklisted tokens as intermediates, which is server-side config\n * this module cannot see, so a reported pair may still answer\n * `no_route_error`.\n */\n\nimport type { ZapPackEdge, ZapPackOverview } from './discovery.js';\n\n/** A token identified by address and chain. */\nexport interface TokenRef {\n readonly address: string;\n readonly chainId: number;\n}\n\n/** A from/to pair `POST /compose/route` can connect through the catalog. */\nexport interface RoutablePair {\n readonly in: TokenRef;\n readonly out: TokenRef;\n /** Catalog edges on the shortest admissible route; `1` is a listed edge. */\n readonly hops: number;\n}\n\nexport interface ReachabilityOptions {\n /**\n * Hop budget. The server's `no_route_error` reports its effective value in\n * `details.maxHops`; the deployment default is 2.\n */\n readonly maxHops?: number;\n /**\n * Admit a route whose last edge has `availability: 'future'`. Mirrors the\n * `allowAsyncRoutes` request option; such a pair is a `no_route_error`\n * without it.\n */\n readonly allowAsyncRoutes?: boolean;\n}\n\nexport interface Reachability {\n readonly maxHops: number;\n /** Whether `route` can connect `from` to `to` through the catalog. */\n readonly canRoute: (from: TokenRef, to: TokenRef) => boolean;\n /** Every pair starting at `from`, shortest routes first. */\n readonly routableFrom: (from: TokenRef) => readonly RoutablePair[];\n /** Every routable pair in the catalog. */\n readonly pairs: () => readonly RoutablePair[];\n}\n\nconst DEFAULT_MAX_HOPS = 2;\n\nconst tokenKey = (token: TokenRef): string =>\n `${token.chainId}:${token.address.toLowerCase()}`;\n\nconst isSync = (edge: ZapPackEdge): boolean => edge.availability === undefined;\n\n// The output stays in the proxy, so a following edge can consume it.\nconst isProxyHeld = (edge: ZapPackEdge): boolean =>\n isSync(edge) && edge.recipient !== 'required';\n\n// One edge out of a frontier token. Records the pair it completes, and returns\n// its output when a further hop may consume it (proxy-held) and no shorter\n// path already expanded that token.\nconst visitEdge = ({\n edge,\n from,\n depth,\n sourceKey,\n isTerminal,\n found,\n expanded,\n}: {\n readonly edge: ZapPackEdge;\n readonly from: TokenRef;\n readonly depth: number;\n readonly sourceKey: string;\n readonly isTerminal: (edge: ZapPackEdge) => boolean;\n readonly found: Map<string, RoutablePair>;\n readonly expanded: Set<string>;\n}): TokenRef | undefined => {\n const key = tokenKey(edge.out);\n if (key === sourceKey) return undefined;\n if (isTerminal(edge) && !found.has(key)) {\n found.set(key, { in: from, out: edge.out, hops: depth });\n }\n if (!isProxyHeld(edge) || expanded.has(key)) return undefined;\n expanded.add(key);\n return edge.out;\n};\n\n// Every pair reachable from one token within `maxHops`, breadth-first so the\n// recorded hop count is the shortest one.\nconst closureFrom = ({\n byIn,\n from,\n maxHops,\n isTerminal,\n}: {\n readonly byIn: ReadonlyMap<string, readonly ZapPackEdge[]>;\n readonly from: TokenRef;\n readonly maxHops: number;\n readonly isTerminal: (edge: ZapPackEdge) => boolean;\n}): Map<string, RoutablePair> => {\n const sourceKey = tokenKey(from);\n const found = new Map<string, RoutablePair>();\n const expanded = new Set<string>([sourceKey]);\n let frontier: readonly TokenRef[] = [from];\n for (let depth = 1; depth <= maxHops && frontier.length > 0; depth++) {\n const next: TokenRef[] = [];\n for (const node of frontier) {\n for (const edge of byIn.get(tokenKey(node)) ?? []) {\n const out = visitEdge({\n edge,\n from,\n depth,\n sourceKey,\n isTerminal,\n found,\n expanded,\n });\n if (out) next.push(out);\n }\n }\n frontier = next;\n }\n return found;\n};\n\nconst indexByIn = (\n packs: readonly ZapPackOverview[],\n): Map<string, ZapPackEdge[]> => {\n const byIn = new Map<string, ZapPackEdge[]>();\n for (const pack of packs) {\n for (const edge of pack.edges) {\n const key = tokenKey(edge.in);\n const list = byIn.get(key);\n if (list) list.push(edge);\n else byIn.set(key, [edge]);\n }\n }\n return byIn;\n};\n\n/**\n * Builds a reachability index over the packs returned by\n * {@link ComposeClient.getZapPacks}. Per-source closures are computed on\n * first use and memoised, so `canRoute` on a handful of pairs stays cheap\n * while `pairs()` enumerates everything.\n */\nexport const buildReachability = (\n packs: readonly ZapPackOverview[],\n options: ReachabilityOptions = {},\n): Reachability => {\n const maxHops = options.maxHops ?? DEFAULT_MAX_HOPS;\n const allowAsync = options.allowAsyncRoutes ?? false;\n const isTerminal = (edge: ZapPackEdge): boolean =>\n isSync(edge) || (allowAsync && edge.availability === 'future');\n\n const byIn = indexByIn(packs);\n const memo = new Map<string, Map<string, RoutablePair>>();\n const closure = (from: TokenRef): Map<string, RoutablePair> => {\n const key = tokenKey(from);\n const cached = memo.get(key);\n if (cached) return cached;\n const computed = closureFrom({ byIn, from, maxHops, isTerminal });\n memo.set(key, computed);\n return computed;\n };\n\n return {\n maxHops,\n canRoute: (from, to) => closure(from).has(tokenKey(to)),\n routableFrom: (from) => [...closure(from).values()],\n pairs: () => {\n const sources = new Map<string, TokenRef>();\n for (const pack of packs) {\n for (const edge of pack.edges) sources.set(tokenKey(edge.in), edge.in);\n }\n const all: RoutablePair[] = [];\n for (const source of sources.values()) {\n all.push(...closure(source).values());\n }\n return all;\n },\n };\n};\n"],"mappings":";;AAkEA,MAAM,mBAAmB;AAEzB,MAAM,YAAY,UAChB,GAAG,MAAM,QAAQ,GAAG,MAAM,QAAQ,YAAY;AAEhD,MAAM,UAAU,SAA+B,KAAK,iBAAiB,KAAA;AAGrE,MAAM,eAAe,SACnB,OAAO,IAAI,KAAK,KAAK,cAAc;AAKrC,MAAM,aAAa,EACjB,MACA,MACA,OACA,WACA,YACA,OACA,eAS0B;CAC1B,MAAM,MAAM,SAAS,KAAK,GAAG;CAC7B,IAAI,QAAQ,WAAW,OAAO,KAAA;CAC9B,IAAI,WAAW,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,GACpC,MAAM,IAAI,KAAK;EAAE,IAAI;EAAM,KAAK,KAAK;EAAK,MAAM;CAAM,CAAC;CAEzD,IAAI,CAAC,YAAY,IAAI,KAAK,SAAS,IAAI,GAAG,GAAG,OAAO,KAAA;CACpD,SAAS,IAAI,GAAG;CAChB,OAAO,KAAK;AACd;AAIA,MAAM,eAAe,EACnB,MACA,MACA,SACA,iBAM+B;CAC/B,MAAM,YAAY,SAAS,IAAI;CAC/B,MAAM,wBAAQ,IAAI,IAA0B;CAC5C,MAAM,2BAAW,IAAI,IAAY,CAAC,SAAS,CAAC;CAC5C,IAAI,WAAgC,CAAC,IAAI;CACzC,KAAK,IAAI,QAAQ,GAAG,SAAS,WAAW,SAAS,SAAS,GAAG,SAAS;EACpE,MAAM,OAAmB,CAAC;EAC1B,KAAK,MAAM,QAAQ,UACjB,KAAK,MAAM,QAAQ,KAAK,IAAI,SAAS,IAAI,CAAC,KAAK,CAAC,GAAG;GACjD,MAAM,MAAM,UAAU;IACpB;IACA;IACA;IACA;IACA;IACA;IACA;GACF,CAAC;GACD,IAAI,KAAK,KAAK,KAAK,GAAG;EACxB;EAEF,WAAW;CACb;CACA,OAAO;AACT;AAEA,MAAM,aACJ,UAC+B;CAC/B,MAAM,uBAAO,IAAI,IAA2B;CAC5C,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,QAAQ,KAAK,OAAO;EAC7B,MAAM,MAAM,SAAS,KAAK,EAAE;EAC5B,MAAM,OAAO,KAAK,IAAI,GAAG;EACzB,IAAI,MAAM,KAAK,KAAK,IAAI;OACnB,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC;CAC3B;CAEF,OAAO;AACT;;;;;;;AAQA,MAAa,qBACX,OACA,UAA+B,CAAC,MACf;CACjB,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,aAAa,QAAQ,oBAAoB;CAC/C,MAAM,cAAc,SAClB,OAAO,IAAI,KAAM,cAAc,KAAK,iBAAiB;CAEvD,MAAM,OAAO,UAAU,KAAK;CAC5B,MAAM,uBAAO,IAAI,IAAuC;CACxD,MAAM,WAAW,SAA8C;EAC7D,MAAM,MAAM,SAAS,IAAI;EACzB,MAAM,SAAS,KAAK,IAAI,GAAG;EAC3B,IAAI,QAAQ,OAAO;EACnB,MAAM,WAAW,YAAY;GAAE;GAAM;GAAM;GAAS;EAAW,CAAC;EAChE,KAAK,IAAI,KAAK,QAAQ;EACtB,OAAO;CACT;CAEA,OAAO;EACL;EACA,WAAW,MAAM,OAAO,QAAQ,IAAI,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC;EACtD,eAAe,SAAS,CAAC,GAAG,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC;EAClD,aAAa;GACX,MAAM,0BAAU,IAAI,IAAsB;GAC1C,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,QAAQ,KAAK,OAAO,QAAQ,IAAI,SAAS,KAAK,EAAE,GAAG,KAAK,EAAE;GAEvE,MAAM,MAAsB,CAAC;GAC7B,KAAK,MAAM,UAAU,QAAQ,OAAO,GAClC,IAAI,KAAK,GAAG,QAAQ,MAAM,CAAC,CAAC,OAAO,CAAC;GAEtC,OAAO;EACT;CACF;AACF"}
|
package/dist/reachability.d.cts
CHANGED
|
@@ -1,64 +1,38 @@
|
|
|
1
|
-
import { ZapPackOverview } from
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Client-side reachability over the zap-pack catalog.
|
|
5
|
-
*
|
|
6
|
-
* `GET /compose/zap-packs` lists single routing edges. `POST /compose/route`
|
|
7
|
-
* chains up to the server's hop budget of them, so the set of routable pairs
|
|
8
|
-
* is the closure of the catalog, not the catalog itself. This module computes
|
|
9
|
-
* that closure locally with the planner's admissibility rule, so an integrator
|
|
10
|
-
* can offer every pair `route` connects without a request per pair.
|
|
11
|
-
*
|
|
12
|
-
* The rule, mirrored from the server's route search:
|
|
13
|
-
*
|
|
14
|
-
* - every edge except the last must leave its output in the proxy for the
|
|
15
|
-
* next edge to consume: no `availability`, no `recipient: 'required'`
|
|
16
|
-
* - the last edge must be synchronous, or `availability: 'future'` when the
|
|
17
|
-
* caller opts into `allowAsyncRoutes`
|
|
18
|
-
* - a route never visits the same token twice
|
|
19
|
-
*
|
|
20
|
-
* Amount bounds (`inAmountMin` / `inAmountMax`) on an intermediate edge
|
|
21
|
-
* cannot be checked without an amount, so a pair reported here is routable
|
|
22
|
-
* structurally, exactly as a listed edge is. Routes that open with a
|
|
23
|
-
* `lifi.swap` are not enumerable and are not reported. The server also
|
|
24
|
-
* drops blacklisted tokens as intermediates, which is server-side config
|
|
25
|
-
* this module cannot see, so a reported pair may still answer
|
|
26
|
-
* `no_route_error`.
|
|
27
|
-
*/
|
|
28
|
-
|
|
1
|
+
import { ZapPackOverview } from "./discovery.cjs";
|
|
2
|
+
//#region src/reachability.d.ts
|
|
29
3
|
/** A token identified by address and chain. */
|
|
30
|
-
interface TokenRef {
|
|
31
|
-
|
|
32
|
-
|
|
4
|
+
export interface TokenRef {
|
|
5
|
+
readonly address: string;
|
|
6
|
+
readonly chainId: number;
|
|
33
7
|
}
|
|
34
8
|
/** A from/to pair `POST /compose/route` can connect through the catalog. */
|
|
35
|
-
interface RoutablePair {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
9
|
+
export interface RoutablePair {
|
|
10
|
+
readonly in: TokenRef;
|
|
11
|
+
readonly out: TokenRef;
|
|
12
|
+
/** Catalog edges on the shortest admissible route; `1` is a listed edge. */
|
|
13
|
+
readonly hops: number;
|
|
40
14
|
}
|
|
41
|
-
interface ReachabilityOptions {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
15
|
+
export interface ReachabilityOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Hop budget. The server's `no_route_error` reports its effective value in
|
|
18
|
+
* `details.maxHops`; the deployment default is 2.
|
|
19
|
+
*/
|
|
20
|
+
readonly maxHops?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Admit a route whose last edge has `availability: 'future'`. Mirrors the
|
|
23
|
+
* `allowAsyncRoutes` request option; such a pair is a `no_route_error`
|
|
24
|
+
* without it.
|
|
25
|
+
*/
|
|
26
|
+
readonly allowAsyncRoutes?: boolean;
|
|
53
27
|
}
|
|
54
|
-
interface Reachability {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
28
|
+
export interface Reachability {
|
|
29
|
+
readonly maxHops: number;
|
|
30
|
+
/** Whether `route` can connect `from` to `to` through the catalog. */
|
|
31
|
+
readonly canRoute: (from: TokenRef, to: TokenRef) => boolean;
|
|
32
|
+
/** Every pair starting at `from`, shortest routes first. */
|
|
33
|
+
readonly routableFrom: (from: TokenRef) => readonly RoutablePair[];
|
|
34
|
+
/** Every routable pair in the catalog. */
|
|
35
|
+
readonly pairs: () => readonly RoutablePair[];
|
|
62
36
|
}
|
|
63
37
|
/**
|
|
64
38
|
* Builds a reachability index over the packs returned by
|
|
@@ -66,6 +40,6 @@ interface Reachability {
|
|
|
66
40
|
* first use and memoised, so `canRoute` on a handful of pairs stays cheap
|
|
67
41
|
* while `pairs()` enumerates everything.
|
|
68
42
|
*/
|
|
69
|
-
declare const buildReachability: (packs: readonly ZapPackOverview[], options?: ReachabilityOptions) => Reachability;
|
|
70
|
-
|
|
71
|
-
|
|
43
|
+
export declare const buildReachability: (packs: readonly ZapPackOverview[], options?: ReachabilityOptions) => Reachability;
|
|
44
|
+
//#endregion
|
|
45
|
+
//# sourceMappingURL=reachability.d.cts.map
|
package/dist/reachability.d.ts
CHANGED
|
@@ -1,64 +1,38 @@
|
|
|
1
|
-
import { ZapPackOverview } from
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Client-side reachability over the zap-pack catalog.
|
|
5
|
-
*
|
|
6
|
-
* `GET /compose/zap-packs` lists single routing edges. `POST /compose/route`
|
|
7
|
-
* chains up to the server's hop budget of them, so the set of routable pairs
|
|
8
|
-
* is the closure of the catalog, not the catalog itself. This module computes
|
|
9
|
-
* that closure locally with the planner's admissibility rule, so an integrator
|
|
10
|
-
* can offer every pair `route` connects without a request per pair.
|
|
11
|
-
*
|
|
12
|
-
* The rule, mirrored from the server's route search:
|
|
13
|
-
*
|
|
14
|
-
* - every edge except the last must leave its output in the proxy for the
|
|
15
|
-
* next edge to consume: no `availability`, no `recipient: 'required'`
|
|
16
|
-
* - the last edge must be synchronous, or `availability: 'future'` when the
|
|
17
|
-
* caller opts into `allowAsyncRoutes`
|
|
18
|
-
* - a route never visits the same token twice
|
|
19
|
-
*
|
|
20
|
-
* Amount bounds (`inAmountMin` / `inAmountMax`) on an intermediate edge
|
|
21
|
-
* cannot be checked without an amount, so a pair reported here is routable
|
|
22
|
-
* structurally, exactly as a listed edge is. Routes that open with a
|
|
23
|
-
* `lifi.swap` are not enumerable and are not reported. The server also
|
|
24
|
-
* drops blacklisted tokens as intermediates, which is server-side config
|
|
25
|
-
* this module cannot see, so a reported pair may still answer
|
|
26
|
-
* `no_route_error`.
|
|
27
|
-
*/
|
|
28
|
-
|
|
1
|
+
import { ZapPackOverview } from "./discovery.js";
|
|
2
|
+
//#region src/reachability.d.ts
|
|
29
3
|
/** A token identified by address and chain. */
|
|
30
|
-
interface TokenRef {
|
|
31
|
-
|
|
32
|
-
|
|
4
|
+
export interface TokenRef {
|
|
5
|
+
readonly address: string;
|
|
6
|
+
readonly chainId: number;
|
|
33
7
|
}
|
|
34
8
|
/** A from/to pair `POST /compose/route` can connect through the catalog. */
|
|
35
|
-
interface RoutablePair {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
9
|
+
export interface RoutablePair {
|
|
10
|
+
readonly in: TokenRef;
|
|
11
|
+
readonly out: TokenRef;
|
|
12
|
+
/** Catalog edges on the shortest admissible route; `1` is a listed edge. */
|
|
13
|
+
readonly hops: number;
|
|
40
14
|
}
|
|
41
|
-
interface ReachabilityOptions {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
15
|
+
export interface ReachabilityOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Hop budget. The server's `no_route_error` reports its effective value in
|
|
18
|
+
* `details.maxHops`; the deployment default is 2.
|
|
19
|
+
*/
|
|
20
|
+
readonly maxHops?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Admit a route whose last edge has `availability: 'future'`. Mirrors the
|
|
23
|
+
* `allowAsyncRoutes` request option; such a pair is a `no_route_error`
|
|
24
|
+
* without it.
|
|
25
|
+
*/
|
|
26
|
+
readonly allowAsyncRoutes?: boolean;
|
|
53
27
|
}
|
|
54
|
-
interface Reachability {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
28
|
+
export interface Reachability {
|
|
29
|
+
readonly maxHops: number;
|
|
30
|
+
/** Whether `route` can connect `from` to `to` through the catalog. */
|
|
31
|
+
readonly canRoute: (from: TokenRef, to: TokenRef) => boolean;
|
|
32
|
+
/** Every pair starting at `from`, shortest routes first. */
|
|
33
|
+
readonly routableFrom: (from: TokenRef) => readonly RoutablePair[];
|
|
34
|
+
/** Every routable pair in the catalog. */
|
|
35
|
+
readonly pairs: () => readonly RoutablePair[];
|
|
62
36
|
}
|
|
63
37
|
/**
|
|
64
38
|
* Builds a reachability index over the packs returned by
|
|
@@ -66,6 +40,6 @@ interface Reachability {
|
|
|
66
40
|
* first use and memoised, so `canRoute` on a handful of pairs stays cheap
|
|
67
41
|
* while `pairs()` enumerates everything.
|
|
68
42
|
*/
|
|
69
|
-
declare const buildReachability: (packs: readonly ZapPackOverview[], options?: ReachabilityOptions) => Reachability;
|
|
70
|
-
|
|
71
|
-
|
|
43
|
+
export declare const buildReachability: (packs: readonly ZapPackOverview[], options?: ReachabilityOptions) => Reachability;
|
|
44
|
+
//#endregion
|
|
45
|
+
//# sourceMappingURL=reachability.d.ts.map
|
package/dist/reachability.js
CHANGED
|
@@ -1,99 +1,92 @@
|
|
|
1
|
+
//#region src/reachability.ts
|
|
1
2
|
const DEFAULT_MAX_HOPS = 2;
|
|
2
3
|
const tokenKey = (token) => `${token.chainId}:${token.address.toLowerCase()}`;
|
|
3
4
|
const isSync = (edge) => edge.availability === void 0;
|
|
4
5
|
const isProxyHeld = (edge) => isSync(edge) && edge.recipient !== "required";
|
|
5
|
-
const visitEdge = ({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (isTerminal(edge) && !found.has(key)) {
|
|
17
|
-
found.set(key, { in: from, out: edge.out, hops: depth });
|
|
18
|
-
}
|
|
19
|
-
if (!isProxyHeld(edge) || expanded.has(key)) return void 0;
|
|
20
|
-
expanded.add(key);
|
|
21
|
-
return edge.out;
|
|
6
|
+
const visitEdge = ({ edge, from, depth, sourceKey, isTerminal, found, expanded }) => {
|
|
7
|
+
const key = tokenKey(edge.out);
|
|
8
|
+
if (key === sourceKey) return void 0;
|
|
9
|
+
if (isTerminal(edge) && !found.has(key)) found.set(key, {
|
|
10
|
+
in: from,
|
|
11
|
+
out: edge.out,
|
|
12
|
+
hops: depth
|
|
13
|
+
});
|
|
14
|
+
if (!isProxyHeld(edge) || expanded.has(key)) return void 0;
|
|
15
|
+
expanded.add(key);
|
|
16
|
+
return edge.out;
|
|
22
17
|
};
|
|
23
|
-
const closureFrom = ({
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
});
|
|
46
|
-
if (out) next.push(out);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
frontier = next;
|
|
50
|
-
}
|
|
51
|
-
return found;
|
|
18
|
+
const closureFrom = ({ byIn, from, maxHops, isTerminal }) => {
|
|
19
|
+
const sourceKey = tokenKey(from);
|
|
20
|
+
const found = /* @__PURE__ */ new Map();
|
|
21
|
+
const expanded = /* @__PURE__ */ new Set([sourceKey]);
|
|
22
|
+
let frontier = [from];
|
|
23
|
+
for (let depth = 1; depth <= maxHops && frontier.length > 0; depth++) {
|
|
24
|
+
const next = [];
|
|
25
|
+
for (const node of frontier) for (const edge of byIn.get(tokenKey(node)) ?? []) {
|
|
26
|
+
const out = visitEdge({
|
|
27
|
+
edge,
|
|
28
|
+
from,
|
|
29
|
+
depth,
|
|
30
|
+
sourceKey,
|
|
31
|
+
isTerminal,
|
|
32
|
+
found,
|
|
33
|
+
expanded
|
|
34
|
+
});
|
|
35
|
+
if (out) next.push(out);
|
|
36
|
+
}
|
|
37
|
+
frontier = next;
|
|
38
|
+
}
|
|
39
|
+
return found;
|
|
52
40
|
};
|
|
53
41
|
const indexByIn = (packs) => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
return byIn;
|
|
42
|
+
const byIn = /* @__PURE__ */ new Map();
|
|
43
|
+
for (const pack of packs) for (const edge of pack.edges) {
|
|
44
|
+
const key = tokenKey(edge.in);
|
|
45
|
+
const list = byIn.get(key);
|
|
46
|
+
if (list) list.push(edge);
|
|
47
|
+
else byIn.set(key, [edge]);
|
|
48
|
+
}
|
|
49
|
+
return byIn;
|
|
64
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* Builds a reachability index over the packs returned by
|
|
53
|
+
* {@link ComposeClient.getZapPacks}. Per-source closures are computed on
|
|
54
|
+
* first use and memoised, so `canRoute` on a handful of pairs stays cheap
|
|
55
|
+
* while `pairs()` enumerates everything.
|
|
56
|
+
*/
|
|
65
57
|
const buildReachability = (packs, options = {}) => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
};
|
|
96
|
-
export {
|
|
97
|
-
buildReachability
|
|
58
|
+
const maxHops = options.maxHops ?? DEFAULT_MAX_HOPS;
|
|
59
|
+
const allowAsync = options.allowAsyncRoutes ?? false;
|
|
60
|
+
const isTerminal = (edge) => isSync(edge) || allowAsync && edge.availability === "future";
|
|
61
|
+
const byIn = indexByIn(packs);
|
|
62
|
+
const memo = /* @__PURE__ */ new Map();
|
|
63
|
+
const closure = (from) => {
|
|
64
|
+
const key = tokenKey(from);
|
|
65
|
+
const cached = memo.get(key);
|
|
66
|
+
if (cached) return cached;
|
|
67
|
+
const computed = closureFrom({
|
|
68
|
+
byIn,
|
|
69
|
+
from,
|
|
70
|
+
maxHops,
|
|
71
|
+
isTerminal
|
|
72
|
+
});
|
|
73
|
+
memo.set(key, computed);
|
|
74
|
+
return computed;
|
|
75
|
+
};
|
|
76
|
+
return {
|
|
77
|
+
maxHops,
|
|
78
|
+
canRoute: (from, to) => closure(from).has(tokenKey(to)),
|
|
79
|
+
routableFrom: (from) => [...closure(from).values()],
|
|
80
|
+
pairs: () => {
|
|
81
|
+
const sources = /* @__PURE__ */ new Map();
|
|
82
|
+
for (const pack of packs) for (const edge of pack.edges) sources.set(tokenKey(edge.in), edge.in);
|
|
83
|
+
const all = [];
|
|
84
|
+
for (const source of sources.values()) all.push(...closure(source).values());
|
|
85
|
+
return all;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
98
88
|
};
|
|
89
|
+
//#endregion
|
|
90
|
+
export { buildReachability };
|
|
91
|
+
|
|
99
92
|
//# sourceMappingURL=reachability.js.map
|
package/dist/reachability.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/reachability.ts"],"sourcesContent":["/**\n * Client-side reachability over the zap-pack catalog.\n *\n * `GET /compose/zap-packs` lists single routing edges. `POST /compose/route`\n * chains up to the server's hop budget of them, so the set of routable pairs\n * is the closure of the catalog, not the catalog itself. This module computes\n * that closure locally with the planner's admissibility rule, so an integrator\n * can offer every pair `route` connects without a request per pair.\n *\n * The rule, mirrored from the server's route search:\n *\n * - every edge except the last must leave its output in the proxy for the\n * next edge to consume: no `availability`, no `recipient: 'required'`\n * - the last edge must be synchronous, or `availability: 'future'` when the\n * caller opts into `allowAsyncRoutes`\n * - a route never visits the same token twice\n *\n * Amount bounds (`inAmountMin` / `inAmountMax`) on an intermediate edge\n * cannot be checked without an amount, so a pair reported here is routable\n * structurally, exactly as a listed edge is. Routes that open with a\n * `lifi.swap` are not enumerable and are not reported. The server also\n * drops blacklisted tokens as intermediates, which is server-side config\n * this module cannot see, so a reported pair may still answer\n * `no_route_error`.\n */\n\nimport type { ZapPackEdge, ZapPackOverview } from './discovery.js';\n\n/** A token identified by address and chain. */\nexport interface TokenRef {\n readonly address: string;\n readonly chainId: number;\n}\n\n/** A from/to pair `POST /compose/route` can connect through the catalog. */\nexport interface RoutablePair {\n readonly in: TokenRef;\n readonly out: TokenRef;\n /** Catalog edges on the shortest admissible route; `1` is a listed edge. */\n readonly hops: number;\n}\n\nexport interface ReachabilityOptions {\n /**\n * Hop budget. The server's `no_route_error` reports its effective value in\n * `details.maxHops`; the deployment default is 2.\n */\n readonly maxHops?: number;\n /**\n * Admit a route whose last edge has `availability: 'future'`. Mirrors the\n * `allowAsyncRoutes` request option; such a pair is a `no_route_error`\n * without it.\n */\n readonly allowAsyncRoutes?: boolean;\n}\n\nexport interface Reachability {\n readonly maxHops: number;\n /** Whether `route` can connect `from` to `to` through the catalog. */\n readonly canRoute: (from: TokenRef, to: TokenRef) => boolean;\n /** Every pair starting at `from`, shortest routes first. */\n readonly routableFrom: (from: TokenRef) => readonly RoutablePair[];\n /** Every routable pair in the catalog. */\n readonly pairs: () => readonly RoutablePair[];\n}\n\nconst DEFAULT_MAX_HOPS = 2;\n\nconst tokenKey = (token: TokenRef): string =>\n `${token.chainId}:${token.address.toLowerCase()}`;\n\nconst isSync = (edge: ZapPackEdge): boolean => edge.availability === undefined;\n\n// The output stays in the proxy, so a following edge can consume it.\nconst isProxyHeld = (edge: ZapPackEdge): boolean =>\n isSync(edge) && edge.recipient !== 'required';\n\n// One edge out of a frontier token. Records the pair it completes, and returns\n// its output when a further hop may consume it (proxy-held) and no shorter\n// path already expanded that token.\nconst visitEdge = ({\n edge,\n from,\n depth,\n sourceKey,\n isTerminal,\n found,\n expanded,\n}: {\n readonly edge: ZapPackEdge;\n readonly from: TokenRef;\n readonly depth: number;\n readonly sourceKey: string;\n readonly isTerminal: (edge: ZapPackEdge) => boolean;\n readonly found: Map<string, RoutablePair>;\n readonly expanded: Set<string>;\n}): TokenRef | undefined => {\n const key = tokenKey(edge.out);\n if (key === sourceKey) return undefined;\n if (isTerminal(edge) && !found.has(key)) {\n found.set(key, { in: from, out: edge.out, hops: depth });\n }\n if (!isProxyHeld(edge) || expanded.has(key)) return undefined;\n expanded.add(key);\n return edge.out;\n};\n\n// Every pair reachable from one token within `maxHops`, breadth-first so the\n// recorded hop count is the shortest one.\nconst closureFrom = ({\n byIn,\n from,\n maxHops,\n isTerminal,\n}: {\n readonly byIn: ReadonlyMap<string, readonly ZapPackEdge[]>;\n readonly from: TokenRef;\n readonly maxHops: number;\n readonly isTerminal: (edge: ZapPackEdge) => boolean;\n}): Map<string, RoutablePair> => {\n const sourceKey = tokenKey(from);\n const found = new Map<string, RoutablePair>();\n const expanded = new Set<string>([sourceKey]);\n let frontier: readonly TokenRef[] = [from];\n for (let depth = 1; depth <= maxHops && frontier.length > 0; depth++) {\n const next: TokenRef[] = [];\n for (const node of frontier) {\n for (const edge of byIn.get(tokenKey(node)) ?? []) {\n const out = visitEdge({\n edge,\n from,\n depth,\n sourceKey,\n isTerminal,\n found,\n expanded,\n });\n if (out) next.push(out);\n }\n }\n frontier = next;\n }\n return found;\n};\n\nconst indexByIn = (\n packs: readonly ZapPackOverview[],\n): Map<string, ZapPackEdge[]> => {\n const byIn = new Map<string, ZapPackEdge[]>();\n for (const pack of packs) {\n for (const edge of pack.edges) {\n const key = tokenKey(edge.in);\n const list = byIn.get(key);\n if (list) list.push(edge);\n else byIn.set(key, [edge]);\n }\n }\n return byIn;\n};\n\n/**\n * Builds a reachability index over the packs returned by\n * {@link ComposeClient.getZapPacks}. Per-source closures are computed on\n * first use and memoised, so `canRoute` on a handful of pairs stays cheap\n * while `pairs()` enumerates everything.\n */\nexport const buildReachability = (\n packs: readonly ZapPackOverview[],\n options: ReachabilityOptions = {},\n): Reachability => {\n const maxHops = options.maxHops ?? DEFAULT_MAX_HOPS;\n const allowAsync = options.allowAsyncRoutes ?? false;\n const isTerminal = (edge: ZapPackEdge): boolean =>\n isSync(edge) || (allowAsync && edge.availability === 'future');\n\n const byIn = indexByIn(packs);\n const memo = new Map<string, Map<string, RoutablePair>>();\n const closure = (from: TokenRef): Map<string, RoutablePair> => {\n const key = tokenKey(from);\n const cached = memo.get(key);\n if (cached) return cached;\n const computed = closureFrom({ byIn, from, maxHops, isTerminal });\n memo.set(key, computed);\n return computed;\n };\n\n return {\n maxHops,\n canRoute: (from, to) => closure(from).has(tokenKey(to)),\n routableFrom: (from) => [...closure(from).values()],\n pairs: () => {\n const sources = new Map<string, TokenRef>();\n for (const pack of packs) {\n for (const edge of pack.edges) sources.set(tokenKey(edge.in), edge.in);\n }\n const all: RoutablePair[] = [];\n for (const source of sources.values()) {\n all.push(...closure(source).values());\n }\n return all;\n },\n };\n};\n"],"mappings":"AAkEA,MAAM,mBAAmB;AAEzB,MAAM,
|
|
1
|
+
{"version":3,"file":"reachability.js","names":[],"sources":["../src/reachability.ts"],"sourcesContent":["/**\n * Client-side reachability over the zap-pack catalog.\n *\n * `GET /compose/zap-packs` lists single routing edges. `POST /compose/route`\n * chains up to the server's hop budget of them, so the set of routable pairs\n * is the closure of the catalog, not the catalog itself. This module computes\n * that closure locally with the planner's admissibility rule, so an integrator\n * can offer every pair `route` connects without a request per pair.\n *\n * The rule, mirrored from the server's route search:\n *\n * - every edge except the last must leave its output in the proxy for the\n * next edge to consume: no `availability`, no `recipient: 'required'`\n * - the last edge must be synchronous, or `availability: 'future'` when the\n * caller opts into `allowAsyncRoutes`\n * - a route never visits the same token twice\n *\n * Amount bounds (`inAmountMin` / `inAmountMax`) on an intermediate edge\n * cannot be checked without an amount, so a pair reported here is routable\n * structurally, exactly as a listed edge is. Routes that open with a\n * `lifi.swap` are not enumerable and are not reported. The server also\n * drops blacklisted tokens as intermediates, which is server-side config\n * this module cannot see, so a reported pair may still answer\n * `no_route_error`.\n */\n\nimport type { ZapPackEdge, ZapPackOverview } from './discovery.js';\n\n/** A token identified by address and chain. */\nexport interface TokenRef {\n readonly address: string;\n readonly chainId: number;\n}\n\n/** A from/to pair `POST /compose/route` can connect through the catalog. */\nexport interface RoutablePair {\n readonly in: TokenRef;\n readonly out: TokenRef;\n /** Catalog edges on the shortest admissible route; `1` is a listed edge. */\n readonly hops: number;\n}\n\nexport interface ReachabilityOptions {\n /**\n * Hop budget. The server's `no_route_error` reports its effective value in\n * `details.maxHops`; the deployment default is 2.\n */\n readonly maxHops?: number;\n /**\n * Admit a route whose last edge has `availability: 'future'`. Mirrors the\n * `allowAsyncRoutes` request option; such a pair is a `no_route_error`\n * without it.\n */\n readonly allowAsyncRoutes?: boolean;\n}\n\nexport interface Reachability {\n readonly maxHops: number;\n /** Whether `route` can connect `from` to `to` through the catalog. */\n readonly canRoute: (from: TokenRef, to: TokenRef) => boolean;\n /** Every pair starting at `from`, shortest routes first. */\n readonly routableFrom: (from: TokenRef) => readonly RoutablePair[];\n /** Every routable pair in the catalog. */\n readonly pairs: () => readonly RoutablePair[];\n}\n\nconst DEFAULT_MAX_HOPS = 2;\n\nconst tokenKey = (token: TokenRef): string =>\n `${token.chainId}:${token.address.toLowerCase()}`;\n\nconst isSync = (edge: ZapPackEdge): boolean => edge.availability === undefined;\n\n// The output stays in the proxy, so a following edge can consume it.\nconst isProxyHeld = (edge: ZapPackEdge): boolean =>\n isSync(edge) && edge.recipient !== 'required';\n\n// One edge out of a frontier token. Records the pair it completes, and returns\n// its output when a further hop may consume it (proxy-held) and no shorter\n// path already expanded that token.\nconst visitEdge = ({\n edge,\n from,\n depth,\n sourceKey,\n isTerminal,\n found,\n expanded,\n}: {\n readonly edge: ZapPackEdge;\n readonly from: TokenRef;\n readonly depth: number;\n readonly sourceKey: string;\n readonly isTerminal: (edge: ZapPackEdge) => boolean;\n readonly found: Map<string, RoutablePair>;\n readonly expanded: Set<string>;\n}): TokenRef | undefined => {\n const key = tokenKey(edge.out);\n if (key === sourceKey) return undefined;\n if (isTerminal(edge) && !found.has(key)) {\n found.set(key, { in: from, out: edge.out, hops: depth });\n }\n if (!isProxyHeld(edge) || expanded.has(key)) return undefined;\n expanded.add(key);\n return edge.out;\n};\n\n// Every pair reachable from one token within `maxHops`, breadth-first so the\n// recorded hop count is the shortest one.\nconst closureFrom = ({\n byIn,\n from,\n maxHops,\n isTerminal,\n}: {\n readonly byIn: ReadonlyMap<string, readonly ZapPackEdge[]>;\n readonly from: TokenRef;\n readonly maxHops: number;\n readonly isTerminal: (edge: ZapPackEdge) => boolean;\n}): Map<string, RoutablePair> => {\n const sourceKey = tokenKey(from);\n const found = new Map<string, RoutablePair>();\n const expanded = new Set<string>([sourceKey]);\n let frontier: readonly TokenRef[] = [from];\n for (let depth = 1; depth <= maxHops && frontier.length > 0; depth++) {\n const next: TokenRef[] = [];\n for (const node of frontier) {\n for (const edge of byIn.get(tokenKey(node)) ?? []) {\n const out = visitEdge({\n edge,\n from,\n depth,\n sourceKey,\n isTerminal,\n found,\n expanded,\n });\n if (out) next.push(out);\n }\n }\n frontier = next;\n }\n return found;\n};\n\nconst indexByIn = (\n packs: readonly ZapPackOverview[],\n): Map<string, ZapPackEdge[]> => {\n const byIn = new Map<string, ZapPackEdge[]>();\n for (const pack of packs) {\n for (const edge of pack.edges) {\n const key = tokenKey(edge.in);\n const list = byIn.get(key);\n if (list) list.push(edge);\n else byIn.set(key, [edge]);\n }\n }\n return byIn;\n};\n\n/**\n * Builds a reachability index over the packs returned by\n * {@link ComposeClient.getZapPacks}. Per-source closures are computed on\n * first use and memoised, so `canRoute` on a handful of pairs stays cheap\n * while `pairs()` enumerates everything.\n */\nexport const buildReachability = (\n packs: readonly ZapPackOverview[],\n options: ReachabilityOptions = {},\n): Reachability => {\n const maxHops = options.maxHops ?? DEFAULT_MAX_HOPS;\n const allowAsync = options.allowAsyncRoutes ?? false;\n const isTerminal = (edge: ZapPackEdge): boolean =>\n isSync(edge) || (allowAsync && edge.availability === 'future');\n\n const byIn = indexByIn(packs);\n const memo = new Map<string, Map<string, RoutablePair>>();\n const closure = (from: TokenRef): Map<string, RoutablePair> => {\n const key = tokenKey(from);\n const cached = memo.get(key);\n if (cached) return cached;\n const computed = closureFrom({ byIn, from, maxHops, isTerminal });\n memo.set(key, computed);\n return computed;\n };\n\n return {\n maxHops,\n canRoute: (from, to) => closure(from).has(tokenKey(to)),\n routableFrom: (from) => [...closure(from).values()],\n pairs: () => {\n const sources = new Map<string, TokenRef>();\n for (const pack of packs) {\n for (const edge of pack.edges) sources.set(tokenKey(edge.in), edge.in);\n }\n const all: RoutablePair[] = [];\n for (const source of sources.values()) {\n all.push(...closure(source).values());\n }\n return all;\n },\n };\n};\n"],"mappings":";AAkEA,MAAM,mBAAmB;AAEzB,MAAM,YAAY,UAChB,GAAG,MAAM,QAAQ,GAAG,MAAM,QAAQ,YAAY;AAEhD,MAAM,UAAU,SAA+B,KAAK,iBAAiB,KAAA;AAGrE,MAAM,eAAe,SACnB,OAAO,IAAI,KAAK,KAAK,cAAc;AAKrC,MAAM,aAAa,EACjB,MACA,MACA,OACA,WACA,YACA,OACA,eAS0B;CAC1B,MAAM,MAAM,SAAS,KAAK,GAAG;CAC7B,IAAI,QAAQ,WAAW,OAAO,KAAA;CAC9B,IAAI,WAAW,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,GACpC,MAAM,IAAI,KAAK;EAAE,IAAI;EAAM,KAAK,KAAK;EAAK,MAAM;CAAM,CAAC;CAEzD,IAAI,CAAC,YAAY,IAAI,KAAK,SAAS,IAAI,GAAG,GAAG,OAAO,KAAA;CACpD,SAAS,IAAI,GAAG;CAChB,OAAO,KAAK;AACd;AAIA,MAAM,eAAe,EACnB,MACA,MACA,SACA,iBAM+B;CAC/B,MAAM,YAAY,SAAS,IAAI;CAC/B,MAAM,wBAAQ,IAAI,IAA0B;CAC5C,MAAM,2BAAW,IAAI,IAAY,CAAC,SAAS,CAAC;CAC5C,IAAI,WAAgC,CAAC,IAAI;CACzC,KAAK,IAAI,QAAQ,GAAG,SAAS,WAAW,SAAS,SAAS,GAAG,SAAS;EACpE,MAAM,OAAmB,CAAC;EAC1B,KAAK,MAAM,QAAQ,UACjB,KAAK,MAAM,QAAQ,KAAK,IAAI,SAAS,IAAI,CAAC,KAAK,CAAC,GAAG;GACjD,MAAM,MAAM,UAAU;IACpB;IACA;IACA;IACA;IACA;IACA;IACA;GACF,CAAC;GACD,IAAI,KAAK,KAAK,KAAK,GAAG;EACxB;EAEF,WAAW;CACb;CACA,OAAO;AACT;AAEA,MAAM,aACJ,UAC+B;CAC/B,MAAM,uBAAO,IAAI,IAA2B;CAC5C,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,QAAQ,KAAK,OAAO;EAC7B,MAAM,MAAM,SAAS,KAAK,EAAE;EAC5B,MAAM,OAAO,KAAK,IAAI,GAAG;EACzB,IAAI,MAAM,KAAK,KAAK,IAAI;OACnB,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC;CAC3B;CAEF,OAAO;AACT;;;;;;;AAQA,MAAa,qBACX,OACA,UAA+B,CAAC,MACf;CACjB,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,aAAa,QAAQ,oBAAoB;CAC/C,MAAM,cAAc,SAClB,OAAO,IAAI,KAAM,cAAc,KAAK,iBAAiB;CAEvD,MAAM,OAAO,UAAU,KAAK;CAC5B,MAAM,uBAAO,IAAI,IAAuC;CACxD,MAAM,WAAW,SAA8C;EAC7D,MAAM,MAAM,SAAS,IAAI;EACzB,MAAM,SAAS,KAAK,IAAI,GAAG;EAC3B,IAAI,QAAQ,OAAO;EACnB,MAAM,WAAW,YAAY;GAAE;GAAM;GAAM;GAAS;EAAW,CAAC;EAChE,KAAK,IAAI,KAAK,QAAQ;EACtB,OAAO;CACT;CAEA,OAAO;EACL;EACA,WAAW,MAAM,OAAO,QAAQ,IAAI,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC;EACtD,eAAe,SAAS,CAAC,GAAG,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC;EAClD,aAAa;GACX,MAAM,0BAAU,IAAI,IAAsB;GAC1C,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,QAAQ,KAAK,OAAO,QAAQ,IAAI,SAAS,KAAK,EAAE,GAAG,KAAK,EAAE;GAEvE,MAAM,MAAsB,CAAC;GAC7B,KAAK,MAAM,UAAU,QAAQ,OAAO,GAClC,IAAI,KAAK,GAAG,QAAQ,MAAM,CAAC,CAAC,OAAO,CAAC;GAEtC,OAAO;EACT;CACF;AACF"}
|
package/dist/resources.cjs
CHANGED
|
@@ -1,39 +1,54 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var resources_exports = {};
|
|
20
|
-
__export(resources_exports, {
|
|
21
|
-
erc20: () => erc20,
|
|
22
|
-
native: () => native
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/resources.ts
|
|
3
|
+
var resources_exports = /* @__PURE__ */ require("./_virtual/_rolldown/runtime.cjs").__exportAll({
|
|
4
|
+
erc20: () => erc20,
|
|
5
|
+
native: () => native
|
|
23
6
|
});
|
|
24
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Creates a native token resource declaration.
|
|
9
|
+
*
|
|
10
|
+
* @param chainId - The EVM chain ID the native token belongs to.
|
|
11
|
+
* @returns A {@link NativeResource} for use in flow input schemas.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const builder = sdk.flow(1, {
|
|
16
|
+
* inputs: { eth: native(1) },
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
25
20
|
const native = (chainId) => ({
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
kind: "native",
|
|
22
|
+
chainId
|
|
28
23
|
});
|
|
24
|
+
/**
|
|
25
|
+
* Creates an ERC-20 token resource declaration.
|
|
26
|
+
*
|
|
27
|
+
* @param token - The `0x`-prefixed contract address of the ERC-20 token.
|
|
28
|
+
* @param chainId - The EVM chain ID the token is deployed on.
|
|
29
|
+
* @returns An {@link Erc20Resource} for use in flow input schemas.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
|
|
34
|
+
* const builder = sdk.flow(1, {
|
|
35
|
+
* inputs: { usdc: erc20(USDC, 1) },
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
29
39
|
const erc20 = (token, chainId) => ({
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
kind: "erc20",
|
|
41
|
+
token,
|
|
42
|
+
chainId
|
|
33
43
|
});
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
//#endregion
|
|
45
|
+
exports.erc20 = erc20;
|
|
46
|
+
exports.native = native;
|
|
47
|
+
Object.defineProperty(exports, "resources_exports", {
|
|
48
|
+
enumerable: true,
|
|
49
|
+
get: function() {
|
|
50
|
+
return resources_exports;
|
|
51
|
+
}
|
|
38
52
|
});
|
|
53
|
+
|
|
39
54
|
//# sourceMappingURL=resources.cjs.map
|
package/dist/resources.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/resources.ts"],"sourcesContent":["import type { Address } from './types.js';\n\n// These resource types are SDK-local declarations that mirror the shape of\n// `Resource` from `@lifi/compose-spec`. They exist so the SDK can be used\n// without directly depending on `@lifi/compose-spec` at the call site.\n// The types are structurally compatible, so they are assignable to each other.\n\n/** A resource declaration representing the chain's native token (e.g. ETH, MATIC). */\nexport interface NativeResource {\n readonly kind: 'native';\n readonly chainId: number;\n}\n\n/** A resource declaration representing an ERC-20 token at a specific address. */\nexport interface Erc20Resource {\n readonly kind: 'erc20';\n readonly token: Address;\n readonly chainId: number;\n}\n\n/** A token resource — either the chain's native token or an ERC-20. */\nexport type Resource = NativeResource | Erc20Resource;\n\n/**\n * Creates a native token resource declaration.\n *\n * @param chainId - The EVM chain ID the native token belongs to.\n * @returns A {@link NativeResource} for use in flow input schemas.\n *\n * @example\n * ```ts\n * const builder = sdk.flow(1, {\n * inputs: { eth: native(1) },\n * });\n * ```\n */\nexport const native = (chainId: number): NativeResource => ({\n kind: 'native',\n chainId,\n});\n\n/**\n * Creates an ERC-20 token resource declaration.\n *\n * @param token - The `0x`-prefixed contract address of the ERC-20 token.\n * @param chainId - The EVM chain ID the token is deployed on.\n * @returns An {@link Erc20Resource} for use in flow input schemas.\n *\n * @example\n * ```ts\n * const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';\n * const builder = sdk.flow(1, {\n * inputs: { usdc: erc20(USDC, 1) },\n * });\n * ```\n */\nexport const erc20 = (token: Address, chainId: number): Erc20Resource => ({\n kind: 'erc20',\n token,\n chainId,\n});\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"resources.cjs","names":[],"sources":["../src/resources.ts"],"sourcesContent":["import type { Address } from './types.js';\n\n// These resource types are SDK-local declarations that mirror the shape of\n// `Resource` from `@lifi/compose-spec`. They exist so the SDK can be used\n// without directly depending on `@lifi/compose-spec` at the call site.\n// The types are structurally compatible, so they are assignable to each other.\n\n/** A resource declaration representing the chain's native token (e.g. ETH, MATIC). */\nexport interface NativeResource {\n readonly kind: 'native';\n readonly chainId: number;\n}\n\n/** A resource declaration representing an ERC-20 token at a specific address. */\nexport interface Erc20Resource {\n readonly kind: 'erc20';\n readonly token: Address;\n readonly chainId: number;\n}\n\n/** A token resource — either the chain's native token or an ERC-20. */\nexport type Resource = NativeResource | Erc20Resource;\n\n/**\n * Creates a native token resource declaration.\n *\n * @param chainId - The EVM chain ID the native token belongs to.\n * @returns A {@link NativeResource} for use in flow input schemas.\n *\n * @example\n * ```ts\n * const builder = sdk.flow(1, {\n * inputs: { eth: native(1) },\n * });\n * ```\n */\nexport const native = (chainId: number): NativeResource => ({\n kind: 'native',\n chainId,\n});\n\n/**\n * Creates an ERC-20 token resource declaration.\n *\n * @param token - The `0x`-prefixed contract address of the ERC-20 token.\n * @param chainId - The EVM chain ID the token is deployed on.\n * @returns An {@link Erc20Resource} for use in flow input schemas.\n *\n * @example\n * ```ts\n * const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';\n * const builder = sdk.flow(1, {\n * inputs: { usdc: erc20(USDC, 1) },\n * });\n * ```\n */\nexport const erc20 = (token: Address, chainId: number): Erc20Resource => ({\n kind: 'erc20',\n token,\n chainId,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoCA,MAAa,UAAU,aAAqC;CAC1D,MAAM;CACN;AACF;;;;;;;;;;;;;;;;AAiBA,MAAa,SAAS,OAAgB,aAAoC;CACxE,MAAM;CACN;CACA;AACF"}
|