passkey-kit 0.12.1 → 0.14.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.
Files changed (172) hide show
  1. package/README.md +408 -227
  2. package/{types → dist}/base.d.ts +1 -0
  3. package/dist/base.d.ts.map +1 -0
  4. package/{src/base.ts → dist/base.js} +8 -10
  5. package/dist/base.js.map +1 -0
  6. package/dist/base64url.d.ts +18 -0
  7. package/dist/base64url.d.ts.map +1 -0
  8. package/dist/base64url.js +18 -0
  9. package/dist/base64url.js.map +1 -0
  10. package/dist/constants.d.ts +91 -0
  11. package/dist/constants.d.ts.map +1 -0
  12. package/dist/constants.js +115 -0
  13. package/dist/constants.js.map +1 -0
  14. package/dist/contract-errors.d.ts +69 -0
  15. package/dist/contract-errors.d.ts.map +1 -0
  16. package/dist/contract-errors.js +132 -0
  17. package/dist/contract-errors.js.map +1 -0
  18. package/dist/errors.d.ts +163 -0
  19. package/dist/errors.d.ts.map +1 -0
  20. package/dist/errors.js +244 -0
  21. package/dist/errors.js.map +1 -0
  22. package/dist/events.d.ts +94 -0
  23. package/dist/events.d.ts.map +1 -0
  24. package/dist/events.js +92 -0
  25. package/dist/events.js.map +1 -0
  26. package/dist/index.d.ts +22 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +36 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/indexer/codec.d.ts +18 -0
  31. package/dist/indexer/codec.d.ts.map +1 -0
  32. package/dist/indexer/codec.js +32 -0
  33. package/dist/indexer/codec.js.map +1 -0
  34. package/dist/indexer/index.d.ts +25 -0
  35. package/dist/indexer/index.d.ts.map +1 -0
  36. package/dist/indexer/index.js +34 -0
  37. package/dist/indexer/index.js.map +1 -0
  38. package/dist/indexer/mercury.d.ts +94 -0
  39. package/dist/indexer/mercury.d.ts.map +1 -0
  40. package/dist/indexer/mercury.js +245 -0
  41. package/dist/indexer/mercury.js.map +1 -0
  42. package/dist/indexer/stellar-indexer.d.ts +115 -0
  43. package/dist/indexer/stellar-indexer.d.ts.map +1 -0
  44. package/dist/indexer/stellar-indexer.js +279 -0
  45. package/dist/indexer/stellar-indexer.js.map +1 -0
  46. package/dist/indexer/types.d.ts +73 -0
  47. package/dist/indexer/types.d.ts.map +1 -0
  48. package/dist/indexer/types.js +9 -0
  49. package/dist/indexer/types.js.map +1 -0
  50. package/dist/kit/auth-payload.d.ts +106 -0
  51. package/dist/kit/auth-payload.d.ts.map +1 -0
  52. package/dist/kit/auth-payload.js +227 -0
  53. package/dist/kit/auth-payload.js.map +1 -0
  54. package/dist/kit/deploy-ops.d.ts +45 -0
  55. package/dist/kit/deploy-ops.d.ts.map +1 -0
  56. package/dist/kit/deploy-ops.js +69 -0
  57. package/dist/kit/deploy-ops.js.map +1 -0
  58. package/dist/kit/tx-ops.d.ts +95 -0
  59. package/dist/kit/tx-ops.d.ts.map +1 -0
  60. package/dist/kit/tx-ops.js +125 -0
  61. package/dist/kit/tx-ops.js.map +1 -0
  62. package/dist/kit/wallet-ops.d.ts +59 -0
  63. package/dist/kit/wallet-ops.d.ts.map +1 -0
  64. package/dist/kit/wallet-ops.js +122 -0
  65. package/dist/kit/wallet-ops.js.map +1 -0
  66. package/dist/kit/webauthn-ops.d.ts +55 -0
  67. package/dist/kit/webauthn-ops.d.ts.map +1 -0
  68. package/dist/kit/webauthn-ops.js +79 -0
  69. package/dist/kit/webauthn-ops.js.map +1 -0
  70. package/dist/kit.d.ts +132 -0
  71. package/dist/kit.d.ts.map +1 -0
  72. package/dist/kit.js +290 -0
  73. package/dist/kit.js.map +1 -0
  74. package/dist/managers/credential-manager.d.ts +39 -0
  75. package/dist/managers/credential-manager.d.ts.map +1 -0
  76. package/dist/managers/credential-manager.js +47 -0
  77. package/dist/managers/credential-manager.js.map +1 -0
  78. package/dist/managers/index.d.ts +7 -0
  79. package/dist/managers/index.d.ts.map +1 -0
  80. package/dist/managers/index.js +7 -0
  81. package/dist/managers/index.js.map +1 -0
  82. package/dist/managers/signer-manager.d.ts +62 -0
  83. package/dist/managers/signer-manager.d.ts.map +1 -0
  84. package/dist/managers/signer-manager.js +111 -0
  85. package/dist/managers/signer-manager.js.map +1 -0
  86. package/dist/managers/submission-manager.d.ts +52 -0
  87. package/dist/managers/submission-manager.d.ts.map +1 -0
  88. package/dist/managers/submission-manager.js +77 -0
  89. package/dist/managers/submission-manager.js.map +1 -0
  90. package/dist/relayer.d.ts +61 -0
  91. package/dist/relayer.d.ts.map +1 -0
  92. package/dist/relayer.js +122 -0
  93. package/dist/relayer.js.map +1 -0
  94. package/dist/rpc-data.d.ts +45 -0
  95. package/dist/rpc-data.d.ts.map +1 -0
  96. package/dist/rpc-data.js +61 -0
  97. package/dist/rpc-data.js.map +1 -0
  98. package/dist/sac.d.ts +31 -0
  99. package/dist/sac.d.ts.map +1 -0
  100. package/dist/sac.js +47 -0
  101. package/dist/sac.js.map +1 -0
  102. package/dist/server.d.ts +79 -0
  103. package/dist/server.d.ts.map +1 -0
  104. package/dist/server.js +152 -0
  105. package/dist/server.js.map +1 -0
  106. package/dist/signers.d.ts +83 -0
  107. package/dist/signers.d.ts.map +1 -0
  108. package/dist/signers.js +124 -0
  109. package/dist/signers.js.map +1 -0
  110. package/dist/storage/index.d.ts +13 -0
  111. package/dist/storage/index.d.ts.map +1 -0
  112. package/dist/storage/index.js +12 -0
  113. package/dist/storage/index.js.map +1 -0
  114. package/dist/storage/indexeddb.d.ts +26 -0
  115. package/dist/storage/indexeddb.d.ts.map +1 -0
  116. package/dist/storage/indexeddb.js +100 -0
  117. package/dist/storage/indexeddb.js.map +1 -0
  118. package/dist/storage/localStorage.d.ts +22 -0
  119. package/dist/storage/localStorage.d.ts.map +1 -0
  120. package/dist/storage/localStorage.js +86 -0
  121. package/dist/storage/localStorage.js.map +1 -0
  122. package/dist/storage/memory.d.ts +18 -0
  123. package/dist/storage/memory.d.ts.map +1 -0
  124. package/dist/storage/memory.js +41 -0
  125. package/dist/storage/memory.js.map +1 -0
  126. package/dist/types.d.ts +136 -0
  127. package/dist/types.d.ts.map +1 -0
  128. package/dist/types.js +39 -0
  129. package/dist/types.js.map +1 -0
  130. package/dist/utils.d.ts +72 -0
  131. package/dist/utils.d.ts.map +1 -0
  132. package/dist/utils.js +253 -0
  133. package/dist/utils.js.map +1 -0
  134. package/dist/validation.d.ts +42 -0
  135. package/dist/validation.d.ts.map +1 -0
  136. package/dist/validation.js +75 -0
  137. package/dist/validation.js.map +1 -0
  138. package/dist/version.d.ts +7 -0
  139. package/dist/version.d.ts.map +1 -0
  140. package/dist/version.js +9 -0
  141. package/dist/version.js.map +1 -0
  142. package/package.json +47 -20
  143. package/.claude/settings.local.json +0 -20
  144. package/.cursorrules +0 -170
  145. package/.gitattributes +0 -2
  146. package/.github/workflows/release.yml +0 -21
  147. package/.vscode/settings.json +0 -6
  148. package/PROPOSAL.md +0 -397
  149. package/cheatsheet.txt +0 -18
  150. package/clone-js-sdk.sh +0 -21
  151. package/packages/passkey-kit-sdk/README.md +0 -54
  152. package/packages/passkey-kit-sdk/package.json +0 -21
  153. package/packages/passkey-kit-sdk/src/index.ts +0 -171
  154. package/packages/passkey-kit-sdk/tsconfig.json +0 -98
  155. package/packages/passkey-kit-sdk/types/index.d.ts +0 -190
  156. package/packages/sac-sdk/README.md +0 -54
  157. package/packages/sac-sdk/package.json +0 -21
  158. package/packages/sac-sdk/src/index.ts +0 -586
  159. package/packages/sac-sdk/tsconfig.json +0 -98
  160. package/packages/sac-sdk/types/index.d.ts +0 -532
  161. package/pnpm-workspace.yaml +0 -2
  162. package/src/index.ts +0 -5
  163. package/src/kit.ts +0 -823
  164. package/src/sac.ts +0 -29
  165. package/src/server.ts +0 -179
  166. package/src/types.ts +0 -32
  167. package/tsconfig.json +0 -28
  168. package/types/index.d.ts +0 -5
  169. package/types/kit.d.ts +0 -95
  170. package/types/sac.d.ts +0 -13
  171. package/types/server.d.ts +0 -29
  172. package/types/types.d.ts +0 -22
package/dist/index.js ADDED
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Passkey Kit — create and use smart-wallet accounts on Stellar with WebAuthn
3
+ * passkeys.
4
+ *
5
+ * Storage adapters live under the `passkey-kit/storage` subpath; the server-only
6
+ * entrypoint lives under `passkey-kit/server`.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ // Core client. (The server-only `PasskeyServer` lives at `passkey-kit/server`
11
+ // so it — and the relayer secret it holds — can never be bundled into browser
12
+ // code.)
13
+ export { PasskeyKit, } from "./kit.js";
14
+ export { SACClient, buildTokenTransferHostFunction } from "./sac.js";
15
+ // Generated contract client
16
+ export { Client as PasskeyClient } from "passkey-kit-sdk";
17
+ // Signer abstraction
18
+ export { PasskeySigner, Ed25519Signer, PolicySigner, } from "./signers.js";
19
+ // Signer-key helpers, storage + result types
20
+ export { SignerKey, SignerStore, } from "./types.js";
21
+ // Typed errors
22
+ export { PasskeyKitError, PasskeyKitErrorCode, ConfigurationError, WalletNotConnectedError, WalletOwnershipError, WebAuthnError, SigningError, SignerNotFoundError, SimulationError, SubmissionError, ValidationError, IndexerError, RelayerError, ContractError, wrapError, } from "./errors.js";
23
+ // Contract-error decoding
24
+ export { CONTRACT_ERROR_REGISTRY, contractErrorFromCode, decodeContractError, } from "./contract-errors.js";
25
+ // Indexer abstraction. Mercury's hosted passkey-indexer is keyless, so the
26
+ // `MercuryIndexer` backend is browser-safe and exported here (no `/server` gate).
27
+ export { MercuryIndexer, mercuryPasskeyIndexerUrl, MERCURY_PASSKEY_INDEXER_URLS, lookupWithRetry, } from "./indexer/index.js";
28
+ // Events
29
+ export { PasskeyEventEmitter, } from "./events.js";
30
+ // Crypto / derivation helpers
31
+ export { deriveContractAddress, extractPublicKeyFromAttestation, compactSignature, generateChallenge, isOnP256Curve, } from "./utils.js";
32
+ // Client-side validation
33
+ export { validateAddress, validateAmount, validateExpiration, validateSecp256r1PublicKey, } from "./validation.js";
34
+ // Package metadata
35
+ export { VERSION, NAME } from "./version.js";
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,8EAA8E;AAC9E,8EAA8E;AAC9E,SAAS;AACT,OAAO,EACL,UAAU,GAIX,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,8BAA8B,EAAE,MAAM,UAAU,CAAC;AAErE,4BAA4B;AAC5B,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE1D,qBAAqB;AACrB,OAAO,EACL,aAAa,EACb,aAAa,EACb,YAAY,GAKb,MAAM,cAAc,CAAC;AAEtB,6CAA6C;AAC7C,OAAO,EACL,SAAS,EACT,WAAW,GAWZ,MAAM,YAAY,CAAC;AAEpB,eAAe;AACf,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,SAAS,GACV,MAAM,aAAa,CAAC;AAErB,0BAA0B;AAC1B,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,mBAAmB,GAGpB,MAAM,sBAAsB,CAAC;AAE9B,2EAA2E;AAC3E,kFAAkF;AAClF,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,4BAA4B,EAC5B,eAAe,GAQhB,MAAM,oBAAoB,CAAC;AAE5B,SAAS;AACT,OAAO,EACL,mBAAmB,GAIpB,MAAM,aAAa,CAAC;AAErB,8BAA8B;AAC9B,OAAO,EACL,qBAAqB,EACrB,+BAA+B,EAC/B,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,yBAAyB;AACzB,OAAO,EACL,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,iBAAiB,CAAC;AAEzB,mBAAmB;AACnB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * ScVal encoding helpers for the Mercury indexer backend.
3
+ *
4
+ * The hosted passkey-indexer returns fully-decoded signer JSON, so the only
5
+ * on-chain encoding the backend still needs is the contract `SignerKey` ScVal —
6
+ * for the temporary-signer eviction probe (`contractDataExists`) and the
7
+ * reverse-lookup on-chain confirmation (`getSigner`). Both go through the
8
+ * contract Spec built from a throwaway client.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import { xdr } from "@stellar/stellar-sdk";
13
+ import type { Spec as ContractSpec } from "@stellar/stellar-sdk/contract";
14
+ import { SignerKey } from "../types.js";
15
+ export declare function walletSpec(): ContractSpec;
16
+ /** Encode an SDK-side {@link SignerKey} into its contract `SignerKey` ScVal. */
17
+ export declare function signerKeyToContractScVal(key: SignerKey): xdr.ScVal;
18
+ //# sourceMappingURL=codec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../src/indexer/codec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAC3C,OAAO,KAAK,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE1E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAOxC,wBAAgB,UAAU,IAAI,YAAY,CAYzC;AAED,gFAAgF;AAChF,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,SAAS,GAAG,GAAG,CAAC,KAAK,CAElE"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * ScVal encoding helpers for the Mercury indexer backend.
3
+ *
4
+ * The hosted passkey-indexer returns fully-decoded signer JSON, so the only
5
+ * on-chain encoding the backend still needs is the contract `SignerKey` ScVal —
6
+ * for the temporary-signer eviction probe (`contractDataExists`) and the
7
+ * reverse-lookup on-chain confirmation (`getSigner`). Both go through the
8
+ * contract Spec built from a throwaway client.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import { Client as PasskeyClient } from "passkey-kit-sdk";
13
+ import { signerKeyToScVal } from "../kit/auth-payload.js";
14
+ import { toContractSignerKey } from "../kit/wallet-ops.js";
15
+ // The contract Spec is network-independent, so memoize a single instance built
16
+ // from a throwaway client (constructing a client does not touch the network).
17
+ let cachedSpec;
18
+ export function walletSpec() {
19
+ if (!cachedSpec) {
20
+ cachedSpec = new PasskeyClient({
21
+ contractId: "CAXCIOHU357VIEDAWOU6YZUL3IU3CDFLCHA6O4PT2VDICDX4PNGSVZDL",
22
+ networkPassphrase: "Test SDF Network ; September 2015",
23
+ rpcUrl: "https://rpc.invalid",
24
+ }).spec;
25
+ }
26
+ return cachedSpec;
27
+ }
28
+ /** Encode an SDK-side {@link SignerKey} into its contract `SignerKey` ScVal. */
29
+ export function signerKeyToContractScVal(key) {
30
+ return signerKeyToScVal(walletSpec(), toContractSignerKey(key));
31
+ }
32
+ //# sourceMappingURL=codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/indexer/codec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,+EAA+E;AAC/E,8EAA8E;AAC9E,IAAI,UAAoC,CAAC;AACzC,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,UAAU,GACR,IAAI,aAAa,CAAC;YAChB,UAAU,EACR,0DAA0D;YAC5D,iBAAiB,EAAE,mCAAmC;YACtD,MAAM,EAAE,qBAAqB;SAC9B,CACF,CAAC,IAAI,CAAC;IACT,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,wBAAwB,CAAC,GAAc;IACrD,OAAO,gBAAgB,CAAC,UAAU,EAAE,EAAE,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;AAClE,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Indexer abstraction barrel.
3
+ *
4
+ * The {@link SignerIndexer} interface + {@link WalletSigner} types, the pure
5
+ * {@link lookupWithRetry} helper, and the {@link MercuryIndexer} backend are all
6
+ * browser-safe — Mercury's hosted passkey-indexer is keyless, so nothing here
7
+ * holds a secret — and the whole module is re-exported from the main
8
+ * `passkey-kit` entry.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ export type { SignerIndexer, WalletSigner, IndexerHealth, SignerStatus, SignerStorageClass, FindWalletsHardeningDeps, } from "./types.js";
13
+ export { MercuryIndexer, mercuryPasskeyIndexerUrl, type MercuryIndexerConfig, } from "./mercury.js";
14
+ export { MERCURY_PASSKEY_INDEXER_URLS } from "../constants.js";
15
+ /**
16
+ * Poll a lookup until it satisfies `predicate` (defaults to "non-empty"), for
17
+ * post-write discovery assertions where the indexer lags the ledger. Defaults
18
+ * to 20 attempts × 2s.
19
+ */
20
+ export declare function lookupWithRetry<T>(fn: () => Promise<T[]>, options?: {
21
+ attempts?: number;
22
+ delayMs?: number;
23
+ predicate?: (result: T[]) => boolean;
24
+ }): Promise<T[]>;
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/indexer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,YAAY,EACV,aAAa,EACb,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,KAAK,oBAAoB,GAC1B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAE/D;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,EAAE,CAAC,EACtB,OAAO,CAAC,EAAE;IACR,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,OAAO,CAAC;CACtC,GACA,OAAO,CAAC,CAAC,EAAE,CAAC,CAcd"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Indexer abstraction barrel.
3
+ *
4
+ * The {@link SignerIndexer} interface + {@link WalletSigner} types, the pure
5
+ * {@link lookupWithRetry} helper, and the {@link MercuryIndexer} backend are all
6
+ * browser-safe — Mercury's hosted passkey-indexer is keyless, so nothing here
7
+ * holds a secret — and the whole module is re-exported from the main
8
+ * `passkey-kit` entry.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ export { MercuryIndexer, mercuryPasskeyIndexerUrl, } from "./mercury.js";
13
+ export { MERCURY_PASSKEY_INDEXER_URLS } from "../constants.js";
14
+ /**
15
+ * Poll a lookup until it satisfies `predicate` (defaults to "non-empty"), for
16
+ * post-write discovery assertions where the indexer lags the ledger. Defaults
17
+ * to 20 attempts × 2s.
18
+ */
19
+ export async function lookupWithRetry(fn, options) {
20
+ const attempts = options?.attempts ?? 20;
21
+ const delayMs = options?.delayMs ?? 2000;
22
+ const predicate = options?.predicate ?? ((r) => r.length > 0);
23
+ let last = [];
24
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
25
+ last = await fn();
26
+ if (predicate(last))
27
+ return last;
28
+ if (attempt < attempts - 1) {
29
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
30
+ }
31
+ }
32
+ return last;
33
+ }
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/indexer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH,OAAO,EACL,cAAc,EACd,wBAAwB,GAEzB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAE/D;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,EAAsB,EACtB,OAIC;IAED,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC;IACzC,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE9D,IAAI,IAAI,GAAQ,EAAE,CAAC;IACnB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,QAAQ,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QACvD,IAAI,GAAG,MAAM,EAAE,EAAE,CAAC;QAClB,IAAI,SAAS,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACjC,IAAI,OAAO,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Mercury hosted passkey-indexer backend.
3
+ *
4
+ * Queries Mercury's public, **keyless** passkey-indexer REST API — no JWT, no
5
+ * API key — which indexes passkey-kit smart-wallet signers on both networks with
6
+ * full history across both signer generations (legacy `("sw_v1", …)` tuple
7
+ * events and the v1 typed `#[contractevent]`s). The endpoint returns fully
8
+ * decoded signer rows, so this backend maps JSON straight onto {@link WalletSigner}
9
+ * with no XDR round-trip.
10
+ *
11
+ * Base URLs (see {@link mercuryPasskeyIndexerUrl}):
12
+ * `https://{testnet,mainnet}.mercurydata.app/rest/passkey-indexer`
13
+ * GET / -> `{ service, status }` health
14
+ * GET /api/wallet/:contractId -> signers (this backend's getSigners)
15
+ * GET /api/lookup/:credentialId -> wallets by passkey keyId (hex)
16
+ * GET /api/lookup/address/:address -> wallets by ed25519 (G…) / policy (C…)
17
+ * GET /api/stats -> indexer statistics
18
+ *
19
+ * Docs: https://docs.mercurydata.app/smart-wallet-indexers/introduction-1
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+ import { type Server } from "@stellar/stellar-sdk/rpc";
24
+ import { SignerKey } from "../types.js";
25
+ import type { FindWalletsHardeningDeps, IndexerHealth, SignerIndexer, WalletSigner } from "./types.js";
26
+ /**
27
+ * Resolve the hosted passkey-indexer base URL for a network. Mercury indexes
28
+ * both testnet and mainnet; any other network returns `undefined` (no hosted
29
+ * endpoint — pass an explicit `url` to point at a self-hosted instance).
30
+ */
31
+ export declare function mercuryPasskeyIndexerUrl(networkPassphrase: string): string | undefined;
32
+ export interface MercuryIndexerConfig {
33
+ /**
34
+ * Hosted passkey-indexer base URL, e.g.
35
+ * `https://testnet.mercurydata.app/rest/passkey-indexer`. Keyless (public
36
+ * REST). Prefer {@link MercuryIndexer.forNetwork} to resolve this per network.
37
+ */
38
+ url: string;
39
+ /**
40
+ * RPC server — enables the temporary-signer eviction probe and lets
41
+ * `findWallets` confirm reverse-lookup candidates on-chain.
42
+ */
43
+ rpc?: Server;
44
+ /**
45
+ * Deps that let `findWallets` confirm a candidate by deterministic derivation
46
+ * from the keyId, skipping an RPC round-trip.
47
+ */
48
+ hardening?: FindWalletsHardeningDeps;
49
+ /** Injectable fetch (tests / non-global runtimes). Defaults to global `fetch`. */
50
+ fetch?: typeof fetch;
51
+ }
52
+ export declare class MercuryIndexer implements SignerIndexer {
53
+ private readonly config;
54
+ constructor(config: MercuryIndexerConfig);
55
+ /**
56
+ * Null-tolerant factory: resolve the hosted base URL for `networkPassphrase`
57
+ * (unless `url` is given), returning `null` when the network has no hosted
58
+ * endpoint and no explicit `url` — callers treat `null` as "discovery
59
+ * disabled".
60
+ */
61
+ static forNetwork(config: Omit<MercuryIndexerConfig, "url"> & {
62
+ url?: string;
63
+ }, networkPassphrase: string): MercuryIndexer | null;
64
+ /**
65
+ * GET a passkey-indexer route. Returns the parsed JSON, or `null` on a `404`
66
+ * (a genuine "not found" is an answer, not a failure). Any other non-2xx, a
67
+ * timeout, or a transport error throws an {@link IndexerError}.
68
+ */
69
+ private get;
70
+ getSigners(wallet: string): Promise<WalletSigner[]>;
71
+ /**
72
+ * Whether the signer's temporary ledger entry still exists on-chain. Probes by
73
+ * the `SignerKey` ScVal — the exact key the contract stores the entry under
74
+ * (`storage().temporary().set::<SignerKey, SignerVal>`) — so it actually
75
+ * matches. Throws on a transport error (caller decides eviction only from a
76
+ * genuine not-found).
77
+ */
78
+ private entryExists;
79
+ findWallets(key: SignerKey): Promise<string[]>;
80
+ /**
81
+ * Harden the reverse lookup (#598 F3): keep a candidate only if it is either
82
+ * the deterministic derivation of the keyId OR still holds the signer entry
83
+ * on-chain — never trust an unverified indexer row.
84
+ *
85
+ * Fail-CLOSED: when candidates exist but no confirmation route
86
+ * does — no `rpc`, and no usable derivation (`hardening` only covers
87
+ * Secp256r1 keys) — this throws instead of returning unconfirmed rows. An
88
+ * unverifiable answer must never be handed to a caller that will route
89
+ * deposits or identity to it.
90
+ */
91
+ private confirmCandidates;
92
+ health(): Promise<IndexerHealth>;
93
+ }
94
+ //# sourceMappingURL=mercury.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mercury.d.ts","sourceRoot":"","sources":["../../src/indexer/mercury.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAAc,KAAK,MAAM,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,SAAS,EAAqB,MAAM,aAAa,CAAC;AAS3D,OAAO,KAAK,EACV,wBAAwB,EACxB,aAAa,EACb,aAAa,EACb,YAAY,EACb,MAAM,YAAY,CAAC;AAIpB;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,iBAAiB,EAAE,MAAM,GACxB,MAAM,GAAG,SAAS,CAMpB;AAmDD,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,SAAS,CAAC,EAAE,wBAAwB,CAAC;IACrC,kFAAkF;IAClF,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,qBAAa,cAAe,YAAW,aAAa;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,oBAAoB;IASzD;;;;;OAKG;IACH,MAAM,CAAC,UAAU,CACf,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,KAAK,CAAC,GAAG;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,EAC5D,iBAAiB,EAAE,MAAM,GACxB,cAAc,GAAG,IAAI;IAMxB;;;;OAIG;YACW,GAAG;IAqCX,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IA8BzD;;;;;;OAMG;YACW,WAAW;IASnB,WAAW,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAapD;;;;;;;;;;OAUG;YACW,iBAAiB;IAsCzB,MAAM,IAAI,OAAO,CAAC,aAAa,CAAC;CAiBvC"}
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Mercury hosted passkey-indexer backend.
3
+ *
4
+ * Queries Mercury's public, **keyless** passkey-indexer REST API — no JWT, no
5
+ * API key — which indexes passkey-kit smart-wallet signers on both networks with
6
+ * full history across both signer generations (legacy `("sw_v1", …)` tuple
7
+ * events and the v1 typed `#[contractevent]`s). The endpoint returns fully
8
+ * decoded signer rows, so this backend maps JSON straight onto {@link WalletSigner}
9
+ * with no XDR round-trip.
10
+ *
11
+ * Base URLs (see {@link mercuryPasskeyIndexerUrl}):
12
+ * `https://{testnet,mainnet}.mercurydata.app/rest/passkey-indexer`
13
+ * GET / -> `{ service, status }` health
14
+ * GET /api/wallet/:contractId -> signers (this backend's getSigners)
15
+ * GET /api/lookup/:credentialId -> wallets by passkey keyId (hex)
16
+ * GET /api/lookup/address/:address -> wallets by ed25519 (G…) / policy (C…)
17
+ * GET /api/stats -> indexer statistics
18
+ *
19
+ * Docs: https://docs.mercurydata.app/smart-wallet-indexers/introduction-1
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+ import { Networks } from "@stellar/stellar-sdk";
24
+ import { Durability } from "@stellar/stellar-sdk/rpc";
25
+ import { SignerKey } from "../types.js";
26
+ import { IndexerError, PasskeyKitErrorCode } from "../errors.js";
27
+ import { DEFAULT_INDEXER_TIMEOUT_MS, MERCURY_PASSKEY_INDEXER_URLS, } from "../constants.js";
28
+ import { getSigner } from "../kit/wallet-ops.js";
29
+ import { contractDataExists } from "../rpc-data.js";
30
+ import base64url from "../base64url.js";
31
+ import { signerKeyToContractScVal, walletSpec } from "./codec.js";
32
+ import { deriveContractAddress } from "../utils.js";
33
+ /**
34
+ * Resolve the hosted passkey-indexer base URL for a network. Mercury indexes
35
+ * both testnet and mainnet; any other network returns `undefined` (no hosted
36
+ * endpoint — pass an explicit `url` to point at a self-hosted instance).
37
+ */
38
+ export function mercuryPasskeyIndexerUrl(networkPassphrase) {
39
+ if (networkPassphrase === Networks.PUBLIC)
40
+ return MERCURY_PASSKEY_INDEXER_URLS.mainnet;
41
+ if (networkPassphrase === Networks.TESTNET)
42
+ return MERCURY_PASSKEY_INDEXER_URLS.testnet;
43
+ return undefined;
44
+ }
45
+ export class MercuryIndexer {
46
+ config;
47
+ constructor(config) {
48
+ this.config = config;
49
+ if (!config.url) {
50
+ throw new IndexerError("MercuryIndexer requires a url", PasskeyKitErrorCode.INDEXER_NOT_CONFIGURED);
51
+ }
52
+ }
53
+ /**
54
+ * Null-tolerant factory: resolve the hosted base URL for `networkPassphrase`
55
+ * (unless `url` is given), returning `null` when the network has no hosted
56
+ * endpoint and no explicit `url` — callers treat `null` as "discovery
57
+ * disabled".
58
+ */
59
+ static forNetwork(config, networkPassphrase) {
60
+ const url = config.url ?? mercuryPasskeyIndexerUrl(networkPassphrase);
61
+ if (!url)
62
+ return null;
63
+ return new MercuryIndexer({ ...config, url });
64
+ }
65
+ /**
66
+ * GET a passkey-indexer route. Returns the parsed JSON, or `null` on a `404`
67
+ * (a genuine "not found" is an answer, not a failure). Any other non-2xx, a
68
+ * timeout, or a transport error throws an {@link IndexerError}.
69
+ */
70
+ async get(path) {
71
+ const doFetch = this.config.fetch ?? fetch;
72
+ const controller = new AbortController();
73
+ const timeout = setTimeout(() => controller.abort(), DEFAULT_INDEXER_TIMEOUT_MS);
74
+ try {
75
+ const response = await doFetch(`${this.config.url}${path}`, {
76
+ signal: controller.signal,
77
+ });
78
+ if (response.status === 404)
79
+ return null;
80
+ if (!response.ok) {
81
+ const body = await response.text().catch(() => "");
82
+ throw new IndexerError(`Mercury passkey-indexer GET ${path} failed (${response.status}): ${body.slice(0, 200)}`, PasskeyKitErrorCode.INDEXER_REQUEST_FAILED, { path, status: response.status });
83
+ }
84
+ return (await response.json());
85
+ }
86
+ catch (err) {
87
+ if (err instanceof IndexerError)
88
+ throw err;
89
+ const aborted = err instanceof Error && err.name === "AbortError";
90
+ throw new IndexerError(aborted
91
+ ? `Mercury passkey-indexer GET ${path} timed out`
92
+ : String(err), PasskeyKitErrorCode.INDEXER_REQUEST_FAILED, { path }, err instanceof Error ? err : undefined);
93
+ }
94
+ finally {
95
+ clearTimeout(timeout);
96
+ }
97
+ }
98
+ async getSigners(wallet) {
99
+ const res = await this.get(`/api/wallet/${wallet}`);
100
+ if (!res)
101
+ return []; // 404: the wallet has no indexed signers
102
+ const signers = res.signers.map(jsonToWalletSigner);
103
+ // Eviction probe: the indexer derives `status` from signer add/update/remove
104
+ // events and cannot observe temporary-entry TTL eviction, so confirm each
105
+ // live temporary signer still exists on-chain (#598 F6 / audit H2). A genuine
106
+ // not-found => evicted; a transport error leaves the reported status intact.
107
+ if (this.config.rpc) {
108
+ for (const signer of signers) {
109
+ if (signer.storage === "temporary" && signer.status === "live") {
110
+ try {
111
+ if (!(await this.entryExists(wallet, signer.key))) {
112
+ signer.status = "evicted";
113
+ }
114
+ }
115
+ catch {
116
+ // Transport error (429/5xx/timeout): eviction undeterminable — keep
117
+ // the row as the indexer reported it rather than false-evicting.
118
+ }
119
+ }
120
+ }
121
+ }
122
+ return signers;
123
+ }
124
+ /**
125
+ * Whether the signer's temporary ledger entry still exists on-chain. Probes by
126
+ * the `SignerKey` ScVal — the exact key the contract stores the entry under
127
+ * (`storage().temporary().set::<SignerKey, SignerVal>`) — so it actually
128
+ * matches. Throws on a transport error (caller decides eviction only from a
129
+ * genuine not-found).
130
+ */
131
+ async entryExists(wallet, key) {
132
+ return contractDataExists(this.config.rpc, wallet, signerKeyToContractScVal(key), Durability.Temporary);
133
+ }
134
+ async findWallets(key) {
135
+ // Secp256r1 keys are looked up by hex credential id; ed25519/policy keys by
136
+ // their strkey address. The SDK carries the Secp256r1 keyId as base64url, so
137
+ // convert to the hex the credential-id route expects.
138
+ const path = key.key === "Secp256r1"
139
+ ? `/api/lookup/${base64url.toBuffer(key.value).toString("hex")}`
140
+ : `/api/lookup/address/${key.value}`;
141
+ const res = await this.get(path);
142
+ const candidates = res?.wallets.map((w) => w.contract_id) ?? [];
143
+ return this.confirmCandidates(candidates, key);
144
+ }
145
+ /**
146
+ * Harden the reverse lookup (#598 F3): keep a candidate only if it is either
147
+ * the deterministic derivation of the keyId OR still holds the signer entry
148
+ * on-chain — never trust an unverified indexer row.
149
+ *
150
+ * Fail-CLOSED: when candidates exist but no confirmation route
151
+ * does — no `rpc`, and no usable derivation (`hardening` only covers
152
+ * Secp256r1 keys) — this throws instead of returning unconfirmed rows. An
153
+ * unverifiable answer must never be handed to a caller that will route
154
+ * deposits or identity to it.
155
+ */
156
+ async confirmCandidates(candidates, key) {
157
+ const { rpc, hardening } = this.config;
158
+ const derived = hardening && key.key === "Secp256r1"
159
+ ? deriveContractAddress(base64url.toBuffer(key.value), hardening.deployerPublicKey, hardening.networkPassphrase)
160
+ : undefined;
161
+ if (candidates.length > 0 && !rpc && !derived) {
162
+ throw new IndexerError("Cannot confirm reverse-lookup candidates: configure `rpc` (any key type) " +
163
+ "or `hardening` (Secp256r1 derivation) — unconfirmed indexer rows are never returned", PasskeyKitErrorCode.INDEXER_NOT_CONFIGURED, { key: key.key, candidates: candidates.length });
164
+ }
165
+ const confirmed = [];
166
+ for (const candidate of candidates) {
167
+ if (candidate === derived) {
168
+ confirmed.push(candidate);
169
+ continue;
170
+ }
171
+ if (rpc) {
172
+ const signer = await getSigner({ rpc, spec: walletSpec() }, candidate, key);
173
+ if (signer)
174
+ confirmed.push(candidate);
175
+ }
176
+ }
177
+ return confirmed;
178
+ }
179
+ async health() {
180
+ try {
181
+ const res = await this.get("/");
182
+ if (res?.status === "ok")
183
+ return { ok: true, backend: "mercury" };
184
+ return {
185
+ ok: false,
186
+ backend: "mercury",
187
+ detail: `unexpected health payload: ${JSON.stringify(res)}`,
188
+ };
189
+ }
190
+ catch (err) {
191
+ return {
192
+ ok: false,
193
+ backend: "mercury",
194
+ detail: err instanceof Error ? err.message : String(err),
195
+ };
196
+ }
197
+ }
198
+ }
199
+ /** Map a passkey-indexer JSON signer key onto the SDK-side {@link SignerKey}. */
200
+ function keyFromJson(k) {
201
+ switch (k.type) {
202
+ case "secp256r1":
203
+ // The indexer renders the credential id as lowercase hex; the SDK carries
204
+ // it as base64url (matches StoredPasskey.keyId and the contract SignerKey).
205
+ return SignerKey.Secp256r1(Buffer.from(k.value, "hex").toString("base64url"));
206
+ case "ed25519":
207
+ return SignerKey.Ed25519(k.value); // already a `G…` strkey
208
+ case "policy":
209
+ return SignerKey.Policy(k.value); // already a `C…` strkey
210
+ }
211
+ }
212
+ /** Decode the JSON limits object into the SDK's {@link SignerLimits}. */
213
+ function limitsFromJson(limits) {
214
+ if (limits === undefined)
215
+ return undefined; // unlimited (contract `None`)
216
+ // `{}` -> an empty Map: a scoped-but-empty limit set = deny-all, matching the
217
+ // contract's fail-closed `Some(empty)` semantics.
218
+ const out = new Map();
219
+ for (const [contract, keys] of Object.entries(limits)) {
220
+ out.set(contract, keys === null ? undefined : keys.map(keyFromJson));
221
+ }
222
+ return out;
223
+ }
224
+ /** Map a fully-decoded passkey-indexer signer row onto a {@link WalletSigner}. */
225
+ function jsonToWalletSigner(json) {
226
+ const publicKey = json.publicKey
227
+ ? new Uint8Array(Buffer.from(json.publicKey, "hex"))
228
+ : undefined;
229
+ // WalletSigner.expiration is contract-typed as UNIX seconds. Only carry it
230
+ // when the indexer reports the `unix` (v1) unit; a legacy `ledger`-sequence
231
+ // expiration is conveyed through the indexer-derived `status`, never smuggled
232
+ // into the seconds field where a consumer would misread it as a timestamp.
233
+ const expiration = json.expiration != null && json.expiration_unit !== "ledger"
234
+ ? json.expiration
235
+ : undefined;
236
+ return {
237
+ key: keyFromJson(json.key),
238
+ ...(publicKey ? { publicKey } : {}),
239
+ ...(expiration != null ? { expiration } : {}),
240
+ limits: limitsFromJson(json.limits),
241
+ storage: json.storage,
242
+ status: json.status,
243
+ };
244
+ }
245
+ //# sourceMappingURL=mercury.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mercury.js","sourceRoot":"","sources":["../../src/indexer/mercury.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Stellar Indexer backend (Creit Tech), over `POST /v1/contract-data/`.
3
+ *
4
+ * The wallet stores one top-level contract-data entry per signer
5
+ * (`key = SignerKey ScVal`, `val = SignerVal`), so signer enumeration is a
6
+ * contract-scoped query and reverse lookup is derive-then-confirm: derive the
7
+ * wallet address from the keyId, then confirm the signer entry exists there.
8
+ * Removed signers appear as tombstoned (`deleted_at`) entries.
9
+ *
10
+ * WIRE FORMAT (F2-confirmed, todo 959 c2502 / todo 967):
11
+ * - The live API returns each entry's `key`/`val` as **JSON ScVal**, e.g.
12
+ * `{"vec":[{"symbol":"Secp256r1"},{"bytes":"<hex>"}]}` — NOT base64 XDR. We
13
+ * convert JSON ScVal -> `xdr.ScVal` ({@link jsonScValToXdr}) and reuse the
14
+ * contract-spec decoders (`scValToSignerKey`/`decodeSignerVal`). The JSON
15
+ * convention is the standard Stellar one: `symbol`, `bytes` (hex), `address`
16
+ * (strkey), `vec` (array), `map` (`[{key,val}]`), `u64`/`i64` (string),
17
+ * `u32`/`i32` (number), `bool`, `string`, `void` (None).
18
+ * - Entry fields: `id, contract_id, durability, key, val,
19
+ * last_modified_ledger_seq, tx_meta_version, timestamp, created_at,
20
+ * updated_at, deleted_at`.
21
+ *
22
+ * NETWORK: **the Stellar Indexer indexes MAINNET only** — a testnet contract
23
+ * returns HTTP 200 with zero entries (F2). To keep "unsupported network" from
24
+ * masquerading as "wallet has no signers", the backend is network-aware: use
25
+ * {@link StellarIndexerBackend.forNetwork} (returns `null` off mainnet), and a
26
+ * config pinned to a non-mainnet passphrase throws at construction rather than
27
+ * silently returning `[]`. Live validation therefore needs a mainnet v1 wallet
28
+ * (endgame-gated); until then this is unit-tested against the documented shape.
29
+ *
30
+ * @packageDocumentation
31
+ */
32
+ import { Networks, xdr } from "@stellar/stellar-sdk";
33
+ import { SignerKey } from "../types.js";
34
+ import type { FindWalletsHardeningDeps, IndexerHealth, SignerIndexer, WalletSigner } from "./types.js";
35
+ /** Max contract ids per contract-data request (API cap). */
36
+ export declare const MAX_CONTRACTS_PER_QUERY = 25;
37
+ /** The only network the Stellar Indexer indexes (mainnet). */
38
+ export declare const STELLAR_INDEXER_NETWORK = Networks.PUBLIC;
39
+ /**
40
+ * A raw contract-data entry (F2-confirmed live shape). `key`/`val` are JSON
41
+ * ScVal objects (see {@link jsonScValToXdr}), not base64-XDR strings; the extra
42
+ * fields are carried through untyped since only these four drive decoding.
43
+ */
44
+ export interface StellarIndexerEntry {
45
+ /** JSON ScVal of the SignerKey. */
46
+ key: unknown;
47
+ /** JSON ScVal of the SignerVal. */
48
+ val: unknown;
49
+ durability: "persistent" | "temporary";
50
+ deleted_at: string | null;
51
+ id?: string;
52
+ contract_id?: string;
53
+ last_modified_ledger_seq?: number;
54
+ tx_meta_version?: string | number;
55
+ timestamp?: string;
56
+ created_at?: string;
57
+ updated_at?: string;
58
+ }
59
+ export interface StellarIndexerConfig {
60
+ /** Base URL, e.g. https://api.stellarindexer.com */
61
+ url: string;
62
+ /** Bearer access token (server-side secret). */
63
+ accessToken: string;
64
+ /**
65
+ * Network passphrase this backend serves. The Stellar Indexer indexes mainnet
66
+ * only; a non-mainnet passphrase throws at construction (prefer
67
+ * {@link StellarIndexerBackend.forNetwork} to get a `null` off mainnet). When
68
+ * omitted, mainnet is assumed.
69
+ */
70
+ networkPassphrase?: string;
71
+ /** Deps enabling derive-then-confirm reverse lookup. */
72
+ hardening?: FindWalletsHardeningDeps;
73
+ /** Clock source (seconds); injectable for tests. */
74
+ now?: () => number;
75
+ }
76
+ export declare class StellarIndexerBackend implements SignerIndexer {
77
+ private readonly config;
78
+ constructor(config: StellarIndexerConfig);
79
+ /**
80
+ * Network-aware factory: the backend for mainnet, or `null` for any other
81
+ * network (the Stellar Indexer doesn't index testnet, so "discovery disabled"
82
+ * is the honest answer — callers treat `null` as no-indexer rather than an
83
+ * empty signer set).
84
+ */
85
+ static forNetwork(config: Omit<StellarIndexerConfig, "networkPassphrase">, networkPassphrase: string): StellarIndexerBackend | null;
86
+ private nowSeconds;
87
+ private query;
88
+ getSigners(wallet: string): Promise<WalletSigner[]>;
89
+ /**
90
+ * Group entries by signer key and resolve status. A key with any live entry
91
+ * is live/expired; a key whose every entry is tombstoned (no live counterpart
92
+ * in either durability) is `removed`.
93
+ */
94
+ entriesToSigners(entries: StellarIndexerEntry[]): WalletSigner[];
95
+ /**
96
+ * Reverse lookup via derive-then-confirm. Only Secp256r1 keyIds are
97
+ * derivable; Ed25519/Policy signers are not discoverable through this backend
98
+ * (use Mercury's event-driven index for those).
99
+ */
100
+ findWallets(key: SignerKey): Promise<string[]>;
101
+ health(): Promise<IndexerHealth>;
102
+ }
103
+ /**
104
+ * Convert a Stellar JSON-ScVal object into an `xdr.ScVal`.
105
+ *
106
+ * The Stellar Indexer serializes ledger-entry `key`/`val` as JSON ScVal — a
107
+ * single-key object per value (`{"vec":[...]}`, `{"symbol":"…"}`, …). This is
108
+ * the inverse of that serialization for the variants a smart-wallet
109
+ * SignerKey/SignerVal can contain, letting the contract-spec decoders take over.
110
+ *
111
+ * Unknown variant keys THROW (never silently misdecode): an unexpected wire
112
+ * shape must surface as an error, not a wrong signer.
113
+ */
114
+ export declare function jsonScValToXdr(json: unknown): xdr.ScVal;
115
+ //# sourceMappingURL=stellar-indexer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stellar-indexer.d.ts","sourceRoot":"","sources":["../../src/indexer/stellar-indexer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAW,QAAQ,EAAiB,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIxC,OAAO,KAAK,EACV,wBAAwB,EACxB,aAAa,EACb,aAAa,EAEb,YAAY,EACb,MAAM,YAAY,CAAC;AASpB,4DAA4D;AAC5D,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAE1C,8DAA8D;AAC9D,eAAO,MAAM,uBAAuB,kBAAkB,CAAC;AAEvD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,mCAAmC;IACnC,GAAG,EAAE,OAAO,CAAC;IACb,mCAAmC;IACnC,GAAG,EAAE,OAAO,CAAC;IACb,UAAU,EAAE,YAAY,GAAG,WAAW,CAAC;IACvC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,oDAAoD;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wDAAwD;IACxD,SAAS,CAAC,EAAE,wBAAwB,CAAC;IACrC,oDAAoD;IACpD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qBAAa,qBAAsB,YAAW,aAAa;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,oBAAoB;IAmBzD;;;;;OAKG;IACH,MAAM,CAAC,UAAU,CACf,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,mBAAmB,CAAC,EACvD,iBAAiB,EAAE,MAAM,GACxB,qBAAqB,GAAG,IAAI;IAK/B,OAAO,CAAC,UAAU;YAIJ,KAAK;IA2Cb,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAKzD;;;;OAIG;IACH,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,YAAY,EAAE;IA6BhE;;;;OAIG;IACG,WAAW,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IA2B9C,MAAM,IAAI,OAAO,CAAC,aAAa,CAAC;CAcvC;AAyBD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,GAAG,CAAC,KAAK,CAwEvD"}