@seams/wallet-server 0.9.3 → 0.10.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 (83) hide show
  1. package/THIRD_PARTY_NOTICES.md +33 -1
  2. package/artifact-manifest.json +57 -37
  3. package/cloudflare-router-ab/build/deriver-a/build-stamp.json +1 -1
  4. package/cloudflare-router-ab/build/deriver-a/index.js +2 -2
  5. package/cloudflare-router-ab/build/deriver-a/index_bg.wasm +0 -0
  6. package/cloudflare-router-ab/build/deriver-b/build-stamp.json +1 -1
  7. package/cloudflare-router-ab/build/deriver-b/index.js +2 -2
  8. package/cloudflare-router-ab/build/deriver-b/index_bg.wasm +0 -0
  9. package/cloudflare-router-ab/build/local-tools/darwin-arm64/router_ab_local_init +0 -0
  10. package/cloudflare-router-ab/build/local-tools/darwin-x64/router_ab_local_init +0 -0
  11. package/cloudflare-router-ab/build/local-tools/linux-x64/router_ab_local_init +0 -0
  12. package/cloudflare-router-ab/build/router/build-stamp.json +1 -1
  13. package/cloudflare-router-ab/build/router/index.js +1 -1
  14. package/cloudflare-router-ab/build/router/index_bg.wasm +0 -0
  15. package/cloudflare-router-ab/build/signing-worker/build-stamp.json +1 -1
  16. package/cloudflare-router-ab/build/signing-worker/index.js +1 -1
  17. package/cloudflare-router-ab/build/signing-worker/index_bg.wasm +0 -0
  18. package/cloudflare-router-ab/build/tenant-root-control-plane/build-stamp.json +1 -1
  19. package/cloudflare-router-ab/build/tenant-root-control-plane/index.js +1 -1
  20. package/cloudflare-router-ab/build/tenant-root-control-plane/index_bg.wasm +0 -0
  21. package/cloudflare-router-ab/migrations/deriver-a/0020_registration_preparation.sql +7 -0
  22. package/cloudflare-router-ab/migrations/deriver-b/0020_registration_preparation.sql +7 -0
  23. package/dist/esm/cloud-host.js +9 -9
  24. package/dist/esm/core/d1Ed25519SignerRead.js +3 -19
  25. package/dist/esm/hosted-wallet-gateway.js +15 -1
  26. package/dist/esm/localHostedWalletGatewayHandler.js +1 -1
  27. package/dist/esm/router/cloudflare/d1/authorization/d1AuthorizationStore.js +26 -20
  28. package/dist/esm/router/cloudflare/d1/ed25519Yao/d1Ed25519YaoProductRegistrationPartitionedStateStore.js +1 -1
  29. package/dist/esm/router/cloudflare/d1/registration/d1RegistrationCeremonyRecords.js +21 -2
  30. package/dist/esm/router/cloudflare/d1/registration/d1RegistrationCeremonyStore.js +11 -4
  31. package/dist/esm/router/cloudflare/d1/registration/d1RegistrationSetupRateLimit.js +34 -0
  32. package/dist/esm/router/cloudflare/d1/registration/d1WalletRegistrationCommitStore.js +17 -16
  33. package/dist/esm/router/cloudflare/d1/registration/d1WalletRegistrationService.js +45 -65
  34. package/dist/esm/router/cloudflare/d1/registration/d1WalletRegistrationSetupExecution.js +87 -10
  35. package/dist/esm/router/cloudflare/d1/wallet/d1WalletAddSignerService.js +1 -1
  36. package/dist/esm/router/cloudflare/runtime/walletGateway.js +2 -0
  37. package/dist/esm/router/cloudflare-adaptor.js +7 -7
  38. package/dist/esm/router/cloudflare.js +8812 -8594
  39. package/dist/esm/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoCapabilityCommit.js +45 -24
  40. package/dist/esm/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistration.js +52 -3
  41. package/dist/esm/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationPartitionedStateStore.js +1 -1
  42. package/dist/esm/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationPartitioning.js +13 -5
  43. package/dist/esm/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationRequestScopedRuntime.js +41 -7
  44. package/dist/esm/router/domains/ed25519Yao/recovery/routerAbEd25519YaoRecoveryRequestScopedCloudflare.js +1 -1
  45. package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoHttpRegistrationBackend.js +24 -4
  46. package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistration.js +24 -14
  47. package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistrationIntentAuthorization.js +10 -1
  48. package/dist/esm/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistrationRequestScopedCloudflare.js +45 -5
  49. package/dist/esm/router/domains/walletRegistration/walletRegistrationRoutes.js +48 -8
  50. package/dist/esm/router/express.js +107 -16
  51. package/dist/esm/router/framework/registrationSetupDispatch.js +28 -2
  52. package/dist/esm/router/framework/registrationSetupRateLimit.js +0 -0
  53. package/dist/esm/router/transport/fetch/routes/walletRegistration.js +3 -2
  54. package/dist/esm/storage/d1Retry.js +38 -0
  55. package/dist/types/shared-ts/src/utils/walletManagementProtocol.d.ts +1 -1
  56. package/dist/types/wallet-server/src/core/RegistrationCeremonyStore.d.ts +12 -0
  57. package/dist/types/wallet-server/src/core/d1Ed25519SignerRead.d.ts +1 -4
  58. package/dist/types/wallet-server/src/core/threeRouteRegistrationContracts.d.ts +50 -6
  59. package/dist/types/wallet-server/src/hosted-wallet-gateway.d.ts +1 -1
  60. package/dist/types/wallet-server/src/router/cloudflare/d1/registration/d1RegistrationCeremonyStore.d.ts +7 -1
  61. package/dist/types/wallet-server/src/router/cloudflare/d1/registration/d1RegistrationSetupRateLimit.d.ts +7 -0
  62. package/dist/types/wallet-server/src/router/cloudflare/d1/registration/d1WalletRegistrationService.d.ts +1 -1
  63. package/dist/types/wallet-server/src/router/cloudflare/d1/registration/d1WalletRegistrationSetupExecution.d.ts +3 -0
  64. package/dist/types/wallet-server/src/router/cloudflare/runtime/walletGateway.d.ts +1 -1
  65. package/dist/types/wallet-server/src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoCapabilityCommit.d.ts +18 -4
  66. package/dist/types/wallet-server/src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistration.d.ts +35 -4
  67. package/dist/types/wallet-server/src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationRequestScopedRuntime.d.ts +1 -1
  68. package/dist/types/wallet-server/src/router/domains/ed25519Yao/recovery/routerAbEd25519YaoRecovery.d.ts +7 -0
  69. package/dist/types/wallet-server/src/router/domains/ed25519Yao/recovery/routerAbEd25519YaoRecoveryRequestScopedCloudflare.d.ts +2 -2
  70. package/dist/types/wallet-server/src/router/domains/ed25519Yao/registration/routerAbEd25519YaoHttpRegistrationBackend.d.ts +5 -3
  71. package/dist/types/wallet-server/src/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistration.d.ts +18 -3
  72. package/dist/types/wallet-server/src/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistrationIntentAuthorization.d.ts +2 -0
  73. package/dist/types/wallet-server/src/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistrationRequestScopedCloudflare.d.ts +39 -0
  74. package/dist/types/wallet-server/src/router/domains/walletRegistration/walletRegistrationInputs.d.ts +6 -0
  75. package/dist/types/wallet-server/src/router/domains/walletRegistration/walletRegistrationReservation.d.ts +16 -2
  76. package/dist/types/wallet-server/src/router/domains/walletRegistration/walletRegistrationRoutes.d.ts +1 -0
  77. package/dist/types/wallet-server/src/router/framework/registrationSetupRateLimit.d.ts +11 -0
  78. package/dist/types/wallet-server/src/router/framework/routerApi.d.ts +1 -0
  79. package/dist/types/wallet-server/src/storage/d1Retry.d.ts +10 -0
  80. package/migrations/d1-signer/0079_tenant_lookup_indexes.sql +33 -0
  81. package/migrations/d1-signer/0080_registration_setup_rate_limits.sql +11 -0
  82. package/package.json +1 -1
  83. package/src/README.md +1 -1
@@ -1,42 +1,63 @@
1
- import { InMemoryRouterAbEd25519YaoRecoveryService, InMemoryRouterAbEd25519YaoRecoveryStateV1 } from "../recovery/routerAbEd25519YaoRecovery.js";
1
+ import { InMemoryRouterAbEd25519YaoRecoveryService, InMemoryRouterAbEd25519YaoRecoveryStateV1, resolveRouterAbEd25519YaoActiveCapability } from "../recovery/routerAbEd25519YaoRecovery.js";
2
2
  //#region src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoCapabilityCommit.ts
3
- /** The wallet and its initial capability become visible in the same transaction. */
4
- function commitRouterAbEd25519YaoRegistrationCapability(store, installation, walletWrite) {
5
- return commitCapability(store, installRegistration.bind(void 0, installation), walletWrite);
3
+ /**
4
+ * Checks a registration's capability against its admission and its result.
5
+ * The signer row of the wallet commit holds the capability, so a registration
6
+ * reads and writes no recovery state.
7
+ */
8
+ function validateRouterAbEd25519YaoRegistrationCapability(installation) {
9
+ return capabilityService(new InMemoryRouterAbEd25519YaoRecoveryStateV1()).installRegistrationFinalizeCapability(installation);
6
10
  }
7
- function rehydrateRouterAbEd25519YaoCapability(store, capability) {
8
- return commitCapability(store, installPersisted.bind(void 0, capability), Promise.resolve(null));
9
- }
10
- async function commitCapability(store, install, preparedWrite) {
11
+ /**
12
+ * Stores a signer row's capability in the recovery state, where a recovery
13
+ * admission suspends it.
14
+ */
15
+ async function rehydrateRouterAbEd25519YaoCapability(store, capability) {
11
16
  for (let attempt = 0; attempt < 2; attempt += 1) {
12
- const [snapshot, companionWrite] = await Promise.all([store.loadCapabilities(), preparedWrite]);
13
- const state = new InMemoryRouterAbEd25519YaoRecoveryStateV1();
14
- for (const [key, capability] of snapshot.value.recoveryCapabilities) state.capabilities.set(key, capability);
15
- for (const [key, capabilityKey] of snapshot.value.recoveryIdentityCapabilities) state.identityCapabilities.set(key, capabilityKey);
16
- const result = install(new InMemoryRouterAbEd25519YaoRecoveryService({
17
- admitRecovery: rejectProtocolExecution,
18
- resolveRecoveryDispatchRoot: rejectProtocolExecution,
19
- executeRecovery: rejectProtocolExecution,
20
- activateRecovery: rejectProtocolExecution
21
- }, state));
17
+ const snapshot = await store.loadCapabilities();
18
+ const state = recoveryStateFromSnapshot(snapshot);
19
+ const result = capabilityService(state).installPersistedActiveCapability(capability);
22
20
  if (!result.ok) return result;
23
21
  if ((await store.commitCapabilities(snapshot, {
24
22
  capabilities: state.capabilities,
25
23
  identityCapabilities: state.identityCapabilities
26
- }, companionWrite)).kind === "stored") return result;
24
+ }, null)).kind === "stored") return result;
27
25
  }
28
26
  throw new Error("Capability state remained contended after one reconciliation");
29
27
  }
30
- function installRegistration(input, service) {
31
- return service.installRegistrationFinalizeCapability(input);
28
+ /**
29
+ * The active capability of a signer row, as the recovery state allows it: a
30
+ * capability that a recovery suspended is not active, and one that a recovery
31
+ * retired conflicts. Nothing is written.
32
+ */
33
+ function resolveRouterAbEd25519YaoPersistedActiveCapability(snapshot, persisted, lookup) {
34
+ const state = recoveryStateFromSnapshot(snapshot);
35
+ const installed = capabilityService(state).installPersistedActiveCapability(persisted);
36
+ if (!installed.ok) return {
37
+ ok: false,
38
+ code: "capability_conflict",
39
+ message: installed.message
40
+ };
41
+ return resolveRouterAbEd25519YaoActiveCapability(state.capabilities, lookup);
42
+ }
43
+ function recoveryStateFromSnapshot(snapshot) {
44
+ const state = new InMemoryRouterAbEd25519YaoRecoveryStateV1();
45
+ for (const [key, capability] of snapshot.value.recoveryCapabilities) state.capabilities.set(key, capability);
46
+ for (const [key, capabilityKey] of snapshot.value.recoveryIdentityCapabilities) state.identityCapabilities.set(key, capabilityKey);
47
+ return state;
32
48
  }
33
- function installPersisted(input, service) {
34
- return service.installPersistedActiveCapability(input);
49
+ function capabilityService(state) {
50
+ return new InMemoryRouterAbEd25519YaoRecoveryService({
51
+ admitRecovery: rejectProtocolExecution,
52
+ resolveRecoveryDispatchRoot: rejectProtocolExecution,
53
+ executeRecovery: rejectProtocolExecution,
54
+ activateRecovery: rejectProtocolExecution
55
+ }, state);
35
56
  }
36
57
  function rejectProtocolExecution() {
37
58
  throw new Error("A capability commit cannot execute a protocol");
38
59
  }
39
60
  //#endregion
40
- export { commitRouterAbEd25519YaoRegistrationCapability, rehydrateRouterAbEd25519YaoCapability };
61
+ export { rehydrateRouterAbEd25519YaoCapability, resolveRouterAbEd25519YaoPersistedActiveCapability, validateRouterAbEd25519YaoRegistrationCapability };
41
62
 
42
63
  //# sourceMappingURL=routerAbEd25519YaoCapabilityCommit.js.map
@@ -223,10 +223,10 @@ var RouterAbEd25519YaoProductRegistrationRuntime = class {
223
223
  startRegistrationDispatchRoot() {
224
224
  return null;
225
225
  }
226
- async bindAndAdmitVerifiedRegistration(input) {
226
+ async bindAndAdmitVerifiedRegistration(input, _companionWrite, _startedDispatchRoot, mintedSessionId) {
227
227
  const bound = await this.input.authorization.bindAndAuthorizeAdmission(input);
228
228
  if (!bound.ok) return bound;
229
- const admitted = await this.input.registrationService.admit(bound.admissionRequest);
229
+ const admitted = await this.input.registrationService.admit(bound.admissionRequest, void 0, mintedSessionId);
230
230
  if (!admitted.ok) return admitted;
231
231
  return {
232
232
  ok: true,
@@ -236,6 +236,33 @@ var RouterAbEd25519YaoProductRegistrationRuntime = class {
236
236
  companionWrite: "not_committed"
237
237
  };
238
238
  }
239
+ /** This runtime issues a receipt at its admission only. */
240
+ async describeRegistrationAdmission() {
241
+ return {
242
+ ok: false,
243
+ status: 503,
244
+ code: "admission_failed",
245
+ message: "This runtime describes no admission before its proof"
246
+ };
247
+ }
248
+ /** This runtime executes through its registration route only. */
249
+ async executeAdmittedRegistration() {
250
+ return {
251
+ result: {
252
+ ok: false,
253
+ status: 503,
254
+ code: "execution_failed",
255
+ message: "This runtime executes a registration through its execute route"
256
+ },
257
+ timing: {
258
+ credentialDigestMs: 0,
259
+ d1AdmissionReadMs: 0,
260
+ routerExecutionMs: 0,
261
+ routerServerTiming: null,
262
+ resultReconstructionMs: 0
263
+ }
264
+ };
265
+ }
239
266
  async consumeActivated(request) {
240
267
  return await this.input.registrationService.consumeActivated(request);
241
268
  }
@@ -245,6 +272,10 @@ var RouterAbEd25519YaoProductRegistrationRuntime = class {
245
272
  async resolveActiveCapability(input) {
246
273
  return await this.input.capabilityResolver.resolveActiveCapability(input);
247
274
  }
275
+ /** This runtime's recovery state already holds every capability it resolves. */
276
+ async rehydrateActiveCapability(input) {
277
+ return await this.input.capabilityResolver.resolveActiveCapability(input);
278
+ }
248
279
  };
249
280
  /**
250
281
  * Projects the Ed25519 Yao view of one exact Wallet Session. Issuance itself
@@ -314,6 +345,24 @@ function createRouterAbEd25519YaoMaterialActivationRefV1(input) {
314
345
  });
315
346
  }
316
347
  /**
348
+ * Mints the Yao identity of a registration's NEAR branch: its material
349
+ * identity and the session of its admission. Setup stores it, and the
350
+ * admission that follows the proof is issued over it.
351
+ */
352
+ function mintRouterAbEd25519YaoRegistrationIdentityV1(input) {
353
+ const sessionId = new Uint8Array(32);
354
+ do
355
+ globalThis.crypto.getRandomValues(sessionId);
356
+ while (sessionId.every(isZeroByte));
357
+ return {
358
+ materialActivation: createRouterAbEd25519YaoMaterialActivationRefV1(input),
359
+ sessionId: Array.from(sessionId)
360
+ };
361
+ }
362
+ function isZeroByte(byte) {
363
+ return byte === 0;
364
+ }
365
+ /**
317
366
  * Takes the authority *scope* rather than the authority because setup admits
318
367
  * before the proof exists. Callers holding a verified authority
319
368
  * pass `registrationEd25519AuthorityScopeFromAuthority(authority)`; setup
@@ -400,6 +449,6 @@ async function buildRouterAbEd25519YaoAddSignerAdmissionRequestV1(input) {
400
449
  return parsed.value;
401
450
  }
402
451
  //#endregion
403
- export { buildRouterAbEd25519YaoAddSignerAdmissionRequestV1, buildRouterAbEd25519YaoProductAdmissionRequestV1, createRouterAbEd25519YaoMaterialActivationRefV1, createRouterAbEd25519YaoProductRegistrationCompositionFromPortsV1, createRouterAbEd25519YaoProductRegistrationRuntimeV1, createRouterAbEd25519YaoProductRegistrationStateFromPartsV1, createRouterAbEd25519YaoProductRegistrationStateV1, parseRouterAbEd25519YaoProductRegistrationStateV1, projectRouterAbEd25519YaoExactWalletSession, routerAbEd25519YaoPersistedCapabilityMatchesLookupV1 };
452
+ export { buildRouterAbEd25519YaoAddSignerAdmissionRequestV1, buildRouterAbEd25519YaoProductAdmissionRequestV1, createRouterAbEd25519YaoMaterialActivationRefV1, createRouterAbEd25519YaoProductRegistrationCompositionFromPortsV1, createRouterAbEd25519YaoProductRegistrationRuntimeV1, createRouterAbEd25519YaoProductRegistrationStateFromPartsV1, createRouterAbEd25519YaoProductRegistrationStateV1, mintRouterAbEd25519YaoRegistrationIdentityV1, parseRouterAbEd25519YaoProductRegistrationStateV1, projectRouterAbEd25519YaoExactWalletSession, routerAbEd25519YaoPersistedCapabilityMatchesLookupV1 };
404
453
 
405
454
  //# sourceMappingURL=routerAbEd25519YaoProductRegistration.js.map
@@ -1,7 +1,7 @@
1
- import { buildRouterAbEd25519YaoRegistrationExecutionAuthorityV1 } from "../registration/routerAbEd25519YaoRegistrationExecutionRecord.js";
2
1
  import { createRouterAbEd25519YaoProductRegistrationStateV1 } from "./routerAbEd25519YaoProductRegistration.js";
3
2
  import { encodeRouterAbEd25519YaoProductRegistrationStateV1, parseRouterAbEd25519YaoProductRegistrationStateJsonV1 } from "./routerAbEd25519YaoProductRegistrationPersistence.js";
4
3
  import { boundedRouterAbEd25519YaoProductRegistrationSharedStateV1, mergeRouterAbEd25519YaoProductRegistrationStatePartitionV1, partitionRouterAbEd25519YaoProductRegistrationStateV1 } from "./routerAbEd25519YaoProductRegistrationPartitioning.js";
4
+ import { buildRouterAbEd25519YaoRegistrationExecutionAuthorityV1 } from "../registration/routerAbEd25519YaoRegistrationExecutionRecord.js";
5
5
  //#region src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationPartitionedStateStore.ts
6
6
  const ROUTER_AB_ED25519_YAO_SHARED_STATE_RECORD_KEY_V1 = "router-ab-ed25519-yao:shared";
7
7
  const PARTITION_RECORD_CODEC_KIND = "router_ab_ed25519_yao_product_registration_partition_record_json_v1";
@@ -1,6 +1,12 @@
1
1
  import { createRouterAbEd25519YaoProductRegistrationStateFromPartsV1 } from "./routerAbEd25519YaoProductRegistration.js";
2
2
  //#region src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationPartitioning.ts
3
- const MAX_SHARED_RECOVERY_CAPABILITIES = 32;
3
+ /** A suspended capability belongs to a recovery in progress and has no other record. */
4
+ const MAX_SUSPENDED_RECOVERY_CAPABILITIES = 32;
5
+ /**
6
+ * An active or a retired capability repeats its signer row. A recovery stores
7
+ * one between its installation and its suspension, so only the newest few stay.
8
+ */
9
+ const MAX_SETTLED_RECOVERY_CAPABILITIES = 4;
4
10
  /**
5
11
  * Projects the tenant-wide state into shared and lifecycle-owned records.
6
12
  * Capability ownership and export nonce replay state deliberately stay in the
@@ -107,14 +113,16 @@ function boundedRouterAbEd25519YaoProductRegistrationSharedStateV1(source) {
107
113
  };
108
114
  }
109
115
  function boundedRecoveryCapabilities(source) {
110
- if (source.size <= MAX_SHARED_RECOVERY_CAPABILITIES) return new Map(source);
111
116
  const entries = [...source.entries()];
112
117
  const suspended = entries.filter(([, capability]) => capability.kind === "suspended");
113
118
  const retained = /* @__PURE__ */ new Set();
114
- for (const [key] of suspended.slice(-MAX_SHARED_RECOVERY_CAPABILITIES)) retained.add(key);
115
- for (let index = entries.length - 1; index >= 0 && retained.size < MAX_SHARED_RECOVERY_CAPABILITIES; index -= 1) {
119
+ for (const [key] of suspended.slice(-MAX_SUSPENDED_RECOVERY_CAPABILITIES)) retained.add(key);
120
+ let settled = 0;
121
+ for (let index = entries.length - 1; index >= 0 && settled < MAX_SETTLED_RECOVERY_CAPABILITIES; index -= 1) {
116
122
  const entry = entries[index];
117
- if (entry) retained.add(entry[0]);
123
+ if (!entry || entry[1].kind === "suspended") continue;
124
+ retained.add(entry[0]);
125
+ settled += 1;
118
126
  }
119
127
  const bounded = /* @__PURE__ */ new Map();
120
128
  for (const [key, capability] of entries) if (retained.has(key)) bounded.set(key, capability);
@@ -1,12 +1,13 @@
1
- import { InMemoryRouterAbEd25519YaoRegistrationService } from "../registration/routerAbEd25519YaoRegistration.js";
2
- import { InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationAdapter } from "../registration/routerAbEd25519YaoRegistrationIntentAuthorization.js";
3
- import { pinRouterAbEd25519YaoRegistrationDispatchRootV1, routerAbEd25519YaoRegistrationExecuteRequestFromRouterRequestJsonV1, routerAbEd25519YaoRegistrationResultFromRouterAnswerV1 } from "../registration/routerAbEd25519YaoRegistrationExecutionRecord.js";
1
+ import { InMemoryRouterAbEd25519YaoRegistrationService, describeRouterAbEd25519YaoRegistrationAdmissionV1 } from "../registration/routerAbEd25519YaoRegistration.js";
2
+ import { InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationAdapter, routerAbEd25519YaoCredentialDigestSha256HexV1 } from "../registration/routerAbEd25519YaoRegistrationIntentAuthorization.js";
4
3
  import { resolveRouterAbEd25519YaoActiveCapability } from "../recovery/routerAbEd25519YaoRecovery.js";
5
4
  import { routerAbEd25519YaoRegistrationSigningRootIdV1 } from "../routerAbEd25519YaoGatewayEnvelope.js";
6
5
  import { routerAbEd25519YaoPersistedCapabilityMatchesLookupV1 } from "./routerAbEd25519YaoProductRegistration.js";
7
- import { routerAbEd25519YaoAdmittedRegistrationAuthorityV1 } from "./routerAbEd25519YaoProductRegistrationPartitionedStateStore.js";
8
6
  import { parseRouterAbEd25519YaoRegistrationRouterAnswerV1 } from "../registration/routerAbEd25519YaoHttpRegistrationBackend.js";
9
- import { rehydrateRouterAbEd25519YaoCapability } from "./routerAbEd25519YaoCapabilityCommit.js";
7
+ import { pinRouterAbEd25519YaoRegistrationDispatchRootV1, routerAbEd25519YaoRegistrationExecuteRequestFromRouterRequestJsonV1, routerAbEd25519YaoRegistrationResultFromRouterAnswerV1 } from "../registration/routerAbEd25519YaoRegistrationExecutionRecord.js";
8
+ import { routerAbEd25519YaoAdmittedRegistrationAuthorityV1 } from "./routerAbEd25519YaoProductRegistrationPartitionedStateStore.js";
9
+ import { executeRouterAbEd25519YaoAdmittedRegistrationV1 } from "../registration/routerAbEd25519YaoRegistrationRequestScopedCloudflare.js";
10
+ import { rehydrateRouterAbEd25519YaoCapability, resolveRouterAbEd25519YaoPersistedActiveCapability } from "./routerAbEd25519YaoCapabilityCommit.js";
10
11
  //#region src/router/domains/ed25519Yao/capabilityLifecycle/routerAbEd25519YaoProductRegistrationRequestScopedRuntime.ts
11
12
  const MAX_DETERMINISTIC_COMMIT_ATTEMPTS = 2;
12
13
  /**
@@ -43,15 +44,33 @@ var RouterAbEd25519YaoProductRegistrationRequestScopedRuntime = class {
43
44
  dispatchRoot
44
45
  };
45
46
  }
46
- async bindAndAdmitVerifiedRegistration(input, companionWrite, startedDispatchRoot) {
47
+ async bindAndAdmitVerifiedRegistration(input, companionWrite, startedDispatchRoot, mintedSessionId) {
47
48
  return await bindAndAdmitVerifiedRegistration({
48
49
  input,
49
50
  companionWrite,
50
51
  startedDispatchRoot,
52
+ mintedSessionId,
51
53
  store: this.input.store,
52
54
  backend: this.input.registrationBackend
53
55
  });
54
56
  }
57
+ async describeRegistrationAdmission(request, mintedSessionId) {
58
+ return await describeRouterAbEd25519YaoRegistrationAdmissionV1({
59
+ backend: this.input.registrationBackend,
60
+ request,
61
+ mintedSessionId
62
+ });
63
+ }
64
+ async executeAdmittedRegistration(input) {
65
+ return await executeRouterAbEd25519YaoAdmittedRegistrationV1({
66
+ store: this.input.store,
67
+ backend: this.input.registrationBackend,
68
+ request: input.request,
69
+ credentialDigestSha256Hex: await routerAbEd25519YaoCredentialDigestSha256HexV1(input.credential),
70
+ credentialDigestMs: 0,
71
+ trace: input.trace
72
+ });
73
+ }
55
74
  /**
56
75
  * Consumes a registration's activation at the Router, which owns its
57
76
  * execution: the first consumer binding wins, and the same binding
@@ -102,7 +121,21 @@ var RouterAbEd25519YaoProductRegistrationRequestScopedRuntime = class {
102
121
  async installPersistedActiveCapability(input) {
103
122
  return await rehydrateRouterAbEd25519YaoCapability(this.input.store, input);
104
123
  }
124
+ /**
125
+ * The signer row holds a wallet's capability, and the recovery state says
126
+ * whether a recovery suspended it. Both are read together and nothing is
127
+ * written, so a lookup never contends with another wallet.
128
+ */
105
129
  async resolveActiveCapability(input) {
130
+ const invalid = resolveRouterAbEd25519YaoActiveCapability(NO_CAPABILITIES, input);
131
+ if (!invalid.ok && invalid.code === "invalid_lookup") return invalid;
132
+ const loadPersisted = this.input.loadPersistedActiveCapability;
133
+ const [loaded, persisted] = await Promise.all([this.input.store.loadCapabilities(), loadPersisted ? loadPersisted(input) : null]);
134
+ const result = resolveRouterAbEd25519YaoActiveCapability(loaded.value.recoveryCapabilities, input);
135
+ if (result.ok || result.code !== "unknown_capability" || !persisted || !routerAbEd25519YaoPersistedCapabilityMatchesLookupV1(persisted, input)) return result;
136
+ return resolveRouterAbEd25519YaoPersistedActiveCapability(loaded, persisted, input);
137
+ }
138
+ async rehydrateActiveCapability(input) {
106
139
  const result = resolveRouterAbEd25519YaoActiveCapability((await this.input.store.loadCapabilities()).value.recoveryCapabilities, input);
107
140
  if (result.ok || result.code !== "unknown_capability" || !this.input.loadPersistedActiveCapability) return result;
108
141
  const persisted = await this.input.loadPersistedActiveCapability(input);
@@ -116,6 +149,7 @@ var RouterAbEd25519YaoProductRegistrationRequestScopedRuntime = class {
116
149
  return resolveRouterAbEd25519YaoActiveCapability((await this.input.store.loadCapabilities()).value.recoveryCapabilities, input);
117
150
  }
118
151
  };
152
+ const NO_CAPABILITIES = /* @__PURE__ */ new Map();
119
153
  /**
120
154
  * Binds a verified intent and admits its registration. The tenant root the
121
155
  * registration dispatches to is resolved once, for a fresh admission, and
@@ -161,7 +195,7 @@ async function bindAndAdmitVerifiedRegistration(input) {
161
195
  }
162
196
  }
163
197
  if (backendResult === null) try {
164
- backendResult = await input.backend.admit(bound.admissionRequest);
198
+ backendResult = await input.backend.admit(bound.admissionRequest, void 0, input.mintedSessionId);
165
199
  } catch (error) {
166
200
  return {
167
201
  ok: false,
@@ -374,7 +374,7 @@ async function runRecoveryRequest(context, request) {
374
374
  async function runAdmissionRequest(context, request) {
375
375
  const first = await runAdmissionTwoPhase(context, request);
376
376
  if (first.kind !== "rejected" || first.value.ok || first.value.code !== "unknown_capability") return mapAdmissionResult(first);
377
- const resolved = await context.input.capabilities.resolveActiveCapability({
377
+ const resolved = await context.input.capabilities.rehydrateActiveCapability({
378
378
  kind: "router_ab_ed25519_yao_active_capability_lookup_v1",
379
379
  walletId: request.application_binding.wallet_id,
380
380
  nearEd25519SigningKeyId: request.application_binding.near_ed25519_signing_key_id,
@@ -88,6 +88,9 @@ function randomSession() {
88
88
  while (isZero(bytes));
89
89
  return Array.from(bytes);
90
90
  }
91
+ function isSessionId(bytes) {
92
+ return bytes.length === 32 && bytes.every((byte) => Number.isInteger(byte) && byte >= 0 && byte <= 255) && bytes.some((byte) => byte !== 0);
93
+ }
91
94
  function isZero(bytes) {
92
95
  for (const byte of bytes) if (byte !== 0) return false;
93
96
  return true;
@@ -415,8 +418,19 @@ var RouterAbEd25519YaoHttpRegistrationBackend = class {
415
418
  this.lastRouterServerTiming = null;
416
419
  return timing;
417
420
  }
418
- async admit(request, _traceContext) {
419
- return await this.admitActivation(request, "registration");
421
+ async prepareRegistrationPair(identity, request, receipt, expiresAtMs) {
422
+ const tenantRoot = await this.resolveRegistrationDispatchRoot(routerAbEd25519YaoRegistrationSigningRootIdV1(request));
423
+ if (!(await this.post("/router-ab/router/ed25519-yao/registration/prepare", identity, {
424
+ tenant_root: tenantRoot,
425
+ application: request.application_binding,
426
+ participant_ids: request.participant_ids,
427
+ binding: receipt.binding,
428
+ ownership_generation: identity.ownershipGeneration,
429
+ expires_at_ms: expiresAtMs
430
+ }, createRouterAbTraceContextV1().value, "exact")).ok) throw new Error("Registration pair preparation failed");
431
+ }
432
+ async admit(request, _traceContext, mintedSessionId) {
433
+ return await this.admitActivation(request, "registration", mintedSessionId);
420
434
  }
421
435
  async admitRecovery(request, _traceContext) {
422
436
  return await this.admitActivation(request, "recovery");
@@ -477,7 +491,7 @@ var RouterAbEd25519YaoHttpRegistrationBackend = class {
477
491
  signing_worker_recipient_public_key: this.config.signingWorkerRecipientPublicKey
478
492
  };
479
493
  }
480
- async admitActivation(request, operation) {
494
+ async admitActivation(request, operation, mintedSessionId) {
481
495
  if (request.scope.signing_worker_id !== this.config.signingWorkerId) return {
482
496
  ok: false,
483
497
  status: 400,
@@ -486,7 +500,13 @@ var RouterAbEd25519YaoHttpRegistrationBackend = class {
486
500
  };
487
501
  const stableContextBinding = await deriveRouterAbEd25519YaoStableContextBindingV1(request.application_binding, request.participant_ids);
488
502
  const keyset = this.keyset();
489
- const sessionId = randomSession();
503
+ if (mintedSessionId !== void 0 && !isSessionId(mintedSessionId)) return {
504
+ ok: false,
505
+ status: 500,
506
+ code: "admission_failed",
507
+ message: `${operation} minted session is invalid`
508
+ };
509
+ const sessionId = mintedSessionId === void 0 ? randomSession() : [...mintedSessionId];
490
510
  switch (operation) {
491
511
  case "registration": return {
492
512
  ok: true,
@@ -42,6 +42,25 @@ function canonicalWireFingerprint(value) {
42
42
  function encodeRouterAbEd25519YaoRegistrationAdmissionFingerprintV1(request) {
43
43
  return canonicalWireFingerprint(request);
44
44
  }
45
+ /**
46
+ * The receipt that `backend` issues for `request` over the session that setup
47
+ * minted, checked as an admission checks it. It stores nothing and admits
48
+ * nothing: the admission still follows the verified proof.
49
+ */
50
+ async function describeRouterAbEd25519YaoRegistrationAdmissionV1(input) {
51
+ return admissionReceiptFromBackend(input.request, await input.backend.admit(input.request, void 0, input.mintedSessionId));
52
+ }
53
+ function admissionReceiptFromBackend(request, backendResult) {
54
+ if (!backendResult.ok) return backendFailure(backendResult, "admission_failed");
55
+ const parsed = parseRouterAbEd25519YaoRegistrationActivationAdmissionReceiptV1(backendResult.body);
56
+ if (!parsed.ok) return invalidBackendResponse(parsed.message);
57
+ if (!registrationScopeMatchesReceipt(request, parsed.value)) return invalidBackendResponse("registration admission receipt scope does not match request");
58
+ return {
59
+ ok: true,
60
+ status: 200,
61
+ value: parsed.value
62
+ };
63
+ }
45
64
  function registrationScopeMatchesReceipt(request, receipt) {
46
65
  const scope = request.scope;
47
66
  const lifecycle = receipt.binding.lifecycle;
@@ -205,7 +224,7 @@ var InMemoryRouterAbEd25519YaoRegistrationService = class {
205
224
  this.lifecycleSessions = state.lifecycleSessions;
206
225
  this.admissionClaims = state.admissionClaims;
207
226
  }
208
- async admit(request, traceContext) {
227
+ async admit(request, traceContext, mintedSessionId) {
209
228
  const preparation = this.prepareAdmit(request);
210
229
  switch (preparation.kind) {
211
230
  case "completed": return {
@@ -219,7 +238,7 @@ var InMemoryRouterAbEd25519YaoRegistrationService = class {
219
238
  try {
220
239
  outcome = {
221
240
  kind: "backend_response",
222
- result: await this.backend.admit(request, traceContext)
241
+ result: await this.backend.admit(request, traceContext, mintedSessionId)
223
242
  };
224
243
  } catch (error) {
225
244
  outcome = {
@@ -290,19 +309,10 @@ var InMemoryRouterAbEd25519YaoRegistrationService = class {
290
309
  code: "admission_uncertain",
291
310
  message: input.outcome.message
292
311
  };
293
- const backendResult = input.outcome.result;
294
- if (!backendResult.ok) {
295
- this.admissionClaims.delete(input.claim.lifecycleId);
296
- return backendFailure(backendResult, "admission_failed");
297
- }
298
- const parsed = parseRouterAbEd25519YaoRegistrationActivationAdmissionReceiptV1(backendResult.body);
312
+ const parsed = admissionReceiptFromBackend(input.request, input.outcome.result);
299
313
  if (!parsed.ok) {
300
314
  this.admissionClaims.delete(input.claim.lifecycleId);
301
- return invalidBackendResponse(parsed.message);
302
- }
303
- if (!registrationScopeMatchesReceipt(input.request, parsed.value)) {
304
- this.admissionClaims.delete(input.claim.lifecycleId);
305
- return invalidBackendResponse("registration admission receipt scope does not match request");
315
+ return parsed;
306
316
  }
307
317
  const key = registrationSessionKey(parsed.value);
308
318
  if (this.states.has(key)) return {
@@ -551,6 +561,6 @@ var InMemoryRouterAbEd25519YaoRegistrationService = class {
551
561
  }
552
562
  };
553
563
  //#endregion
554
- export { InMemoryRouterAbEd25519YaoRegistrationService, InMemoryRouterAbEd25519YaoRegistrationStateV1, createRouterAbEd25519YaoRegistrationModule, encodeRouterAbEd25519YaoRegistrationAdmissionFingerprintV1, routerAbEd25519YaoExecutionMatchesAdmissionV1 };
564
+ export { InMemoryRouterAbEd25519YaoRegistrationService, InMemoryRouterAbEd25519YaoRegistrationStateV1, createRouterAbEd25519YaoRegistrationModule, describeRouterAbEd25519YaoRegistrationAdmissionV1, encodeRouterAbEd25519YaoRegistrationAdmissionFingerprintV1, routerAbEd25519YaoExecutionMatchesAdmissionV1 };
555
565
 
556
566
  //# sourceMappingURL=routerAbEd25519YaoRegistration.js.map
@@ -65,6 +65,15 @@ async function routerAbEd25519YaoBearerCredentialDigestV1(request) {
65
65
  function routerAbEd25519YaoCredentialDigestHexV1(digest) {
66
66
  return bytesToHex(digest);
67
67
  }
68
+ /** The digest that an admission binds for the credential of its registration intent. */
69
+ async function routerAbEd25519YaoCredentialDigestSha256HexV1(credential) {
70
+ const digest = await credentialDigestSha256(credential);
71
+ try {
72
+ return bytesToHex(digest);
73
+ } finally {
74
+ digest.fill(0);
75
+ }
76
+ }
68
77
  function bytesToHex(bytes) {
69
78
  let encoded = "";
70
79
  for (const byte of bytes) encoded += byte.toString(16).padStart(2, "0");
@@ -356,6 +365,6 @@ var InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationAdapter = class {
356
365
  }
357
366
  };
358
367
  //#endregion
359
- export { InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationAdapter, InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationStateV1, routerAbEd25519YaoBearerCredentialDigestV1, routerAbEd25519YaoCredentialDigestHexV1 };
368
+ export { InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationAdapter, InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationStateV1, routerAbEd25519YaoBearerCredentialDigestV1, routerAbEd25519YaoCredentialDigestHexV1, routerAbEd25519YaoCredentialDigestSha256HexV1 };
360
369
 
361
370
  //# sourceMappingURL=routerAbEd25519YaoRegistrationIntentAuthorization.js.map
@@ -3,8 +3,8 @@ import { ROUTER_AB_TRACE_ID_HEADER_V1, createRouterAbTraceContextV1, parseRouter
3
3
  import { json, readJson } from "../../../framework/http.js";
4
4
  import { InMemoryRouterAbEd25519YaoRegistrationService, routerAbEd25519YaoExecutionMatchesAdmissionV1 } from "./routerAbEd25519YaoRegistration.js";
5
5
  import { InMemoryRouterAbEd25519YaoRegistrationIntentAuthorizationAdapter, routerAbEd25519YaoBearerCredentialDigestV1 } from "./routerAbEd25519YaoRegistrationIntentAuthorization.js";
6
- import { pinRouterAbEd25519YaoRegistrationDispatchRootV1, routerAbEd25519YaoRegistrationResultFromRouterAnswerV1 } from "./routerAbEd25519YaoRegistrationExecutionRecord.js";
7
6
  import { routerAbEd25519YaoRegistrationSigningRootIdV1 } from "../routerAbEd25519YaoGatewayEnvelope.js";
7
+ import { pinRouterAbEd25519YaoRegistrationDispatchRootV1, routerAbEd25519YaoRegistrationResultFromRouterAnswerV1 } from "./routerAbEd25519YaoRegistrationExecutionRecord.js";
8
8
  import { routerAbEd25519YaoAdmittedRegistrationAuthorityV1 } from "../capabilityLifecycle/routerAbEd25519YaoProductRegistrationPartitionedStateStore.js";
9
9
  import { runRouterAbEd25519YaoRegistrationTwoPhaseV1 } from "./routerAbEd25519YaoRegistrationTwoPhaseRunner.js";
10
10
  //#region src/router/domains/ed25519Yao/registration/routerAbEd25519YaoRegistrationRequestScopedCloudflare.ts
@@ -172,17 +172,41 @@ async function runAdmissionRequest(input, request, trace) {
172
172
  * again, so a completed execution's answer outlives the root's lineage.
173
173
  */
174
174
  async function runExecutionRequest(input, request, trace) {
175
- const lifecycleId = request.binding.lifecycle.lifecycle_id;
176
175
  const credentialStartedAt = performance.now();
177
176
  const credential = await routerAbEd25519YaoBearerCredentialDigestV1(input.request);
177
+ const credentialDigestMs = elapsedMs(credentialStartedAt);
178
+ if (!credential.ok) return timedExecutionResult(credential.result, {
179
+ credentialDigestMs,
180
+ d1AdmissionReadMs: 0,
181
+ routerExecutionMs: 0,
182
+ routerServerTiming: null,
183
+ resultReconstructionMs: 0
184
+ });
185
+ return await executeRouterAbEd25519YaoAdmittedRegistrationV1({
186
+ store: input.store,
187
+ backend: input.backend,
188
+ request,
189
+ credentialDigestSha256Hex: credential.digestSha256Hex,
190
+ credentialDigestMs,
191
+ trace
192
+ });
193
+ }
194
+ /**
195
+ * Runs one admitted registration for the holder of its credential. The
196
+ * execute route takes the credential from its bearer. A respond that carries
197
+ * the execute request takes it from the signed setup that it just verified.
198
+ */
199
+ async function executeRouterAbEd25519YaoAdmittedRegistrationV1(input) {
200
+ const { request, trace } = input;
201
+ const credential = { digestSha256Hex: input.credentialDigestSha256Hex };
202
+ const lifecycleId = request.binding.lifecycle.lifecycle_id;
178
203
  const timing = {
179
- credentialDigestMs: elapsedMs(credentialStartedAt),
204
+ credentialDigestMs: input.credentialDigestMs,
180
205
  d1AdmissionReadMs: 0,
181
206
  routerExecutionMs: 0,
182
207
  routerServerTiming: null,
183
208
  resultReconstructionMs: 0
184
209
  };
185
- if (!credential.ok) return timedExecutionResult(credential.result, timing);
186
210
  const admissionStartedAt = performance.now();
187
211
  const authority = routerAbEd25519YaoAdmittedRegistrationAuthorityV1((await input.store.loadRegistration(lifecycleId)).state, lifecycleId);
188
212
  const timingBeforeRouter = {
@@ -356,6 +380,22 @@ function registrationResultResponse(result, timing) {
356
380
  }
357
381
  return response;
358
382
  }
383
+ /**
384
+ * The timing of one execution as Server-Timing entries, for a route that
385
+ * reports them in its own header: a respond that ran the execution.
386
+ */
387
+ function routerAbEd25519YaoRegistrationExecutionTimingEntriesV1(timing) {
388
+ const entries = [
389
+ ["yao_d1_admission_read", timing.d1AdmissionReadMs],
390
+ ["yao_router_execution", timing.routerExecutionMs],
391
+ ["yao_result_reconstruction", timing.resultReconstructionMs]
392
+ ];
393
+ for (const metric of (timing.routerServerTiming ?? "").split(",")) {
394
+ const parsed = /^\s*([A-Za-z0-9_]+);dur=([0-9.]+)\s*$/u.exec(metric);
395
+ if (parsed?.[1] && parsed[2]) entries.push([parsed[1], Number(parsed[2])]);
396
+ }
397
+ return entries;
398
+ }
359
399
  function registrationExecutionServerTiming(timing) {
360
400
  const gatewayTiming = [
361
401
  serverTimingMetric("yao_credential_digest", timing.credentialDigestMs),
@@ -413,6 +453,6 @@ function terminalStateConflictFailure(result) {
413
453
  };
414
454
  }
415
455
  //#endregion
416
- export { handleRouterAbEd25519YaoRegistrationRequestScopedCloudflareV1 };
456
+ export { executeRouterAbEd25519YaoAdmittedRegistrationV1, handleRouterAbEd25519YaoRegistrationRequestScopedCloudflareV1, routerAbEd25519YaoRegistrationExecutionTimingEntriesV1 };
417
457
 
418
458
  //# sourceMappingURL=routerAbEd25519YaoRegistrationRequestScopedCloudflare.js.map
@@ -5,6 +5,7 @@ import { base64UrlDecode } from "../../../shared-ts/src/utils/base64.js";
5
5
  import { parseDigestB64u } from "../../../shared-ts/src/utils/canonicalPrimitives.js";
6
6
  import { base58Encode } from "../../../shared-ts/src/utils/base58.js";
7
7
  import "../../../shared-ts/src/utils/encoders.js";
8
+ import { parseRouterAbEd25519YaoRegistrationActivationExecuteRequestV1 } from "../../../shared-ts/src/utils/routerAbEd25519Yao.js";
8
9
  import { ecdsaClientRootPublicKey33B64uFromString } from "../../../shared-ts/src/threshold/ecdsaDerivationRoleLocalBootstrap.js";
9
10
  import { normalizeRuntimePolicyScope } from "../../../shared-ts/src/threshold/signingRootScope.js";
10
11
  import { parseRouterAbEcdsaRegistrationActivationRequestV1, parseRouterAbEcdsaRegistrationRequestV1 } from "../../../shared-ts/src/utils/routerAbEcdsaDerivation.js";
@@ -1603,6 +1604,22 @@ async function handleRouterApiWalletRegistrationSetup(input) {
1603
1604
  });
1604
1605
  if (!resolved.ok) return routeJson(resolved.status, resolved.body);
1605
1606
  const principal = context.principal;
1607
+ if (input.services.registrationSetupRateLimit) try {
1608
+ if (!(await input.services.registrationSetupRateLimit({
1609
+ apiKeyId: principal.apiKeyId,
1610
+ orgId: principal.orgId,
1611
+ projectId: context.environment.projectId,
1612
+ envId: context.environment.key,
1613
+ sourceIp: input.sourceIp || "unknown"
1614
+ })).allowed) return routeJson(429, {
1615
+ ok: false,
1616
+ code: "rate_limited",
1617
+ message: "Too many registration attempts. Wait one minute and try again.",
1618
+ retryAfterMs: 6e4
1619
+ });
1620
+ } catch {
1621
+ return routeError(503, "internal", "Registration setup rate limit is unavailable");
1622
+ }
1606
1623
  const runtimePolicyScope = {
1607
1624
  orgId: principal.orgId,
1608
1625
  projectId: context.environment.projectId,
@@ -1729,15 +1746,38 @@ function parseWalletRegistrationRespondRequest(body) {
1729
1746
  const parsedAuthority = parseWalletRegistrationAuthorityProof(body);
1730
1747
  if (!parsedAuthority.ok) return parsedAuthority;
1731
1748
  const authority = parsedAuthority.value;
1732
- if (planKind === "near_ed25519") return {
1733
- ok: true,
1734
- value: {
1735
- registrationCeremonyId,
1736
- signedSetup,
1737
- authority,
1738
- planKind
1739
- }
1749
+ if (planKind !== "near_ed25519" && body.ed25519Execution !== void 0) return {
1750
+ ok: false,
1751
+ code: "invalid_body",
1752
+ message: "only an Ed25519-only respond carries its Yao execution"
1740
1753
  };
1754
+ if (planKind === "near_ed25519") {
1755
+ if (body.ed25519Execution === void 0) return {
1756
+ ok: true,
1757
+ value: {
1758
+ registrationCeremonyId,
1759
+ signedSetup,
1760
+ authority,
1761
+ planKind
1762
+ }
1763
+ };
1764
+ const ed25519Execution = parseRouterAbEd25519YaoRegistrationActivationExecuteRequestV1(body.ed25519Execution);
1765
+ if (!ed25519Execution.ok) return {
1766
+ ok: false,
1767
+ code: "invalid_body",
1768
+ message: ed25519Execution.message
1769
+ };
1770
+ return {
1771
+ ok: true,
1772
+ value: {
1773
+ registrationCeremonyId,
1774
+ signedSetup,
1775
+ authority,
1776
+ planKind,
1777
+ ed25519Execution: ed25519Execution.value
1778
+ }
1779
+ };
1780
+ }
1741
1781
  const ecdsa = isPlainObject(body.ecdsa) ? body.ecdsa : null;
1742
1782
  if (!ecdsa || ecdsa.kind !== "router_ab_ecdsa_registration_v1") return {
1743
1783
  ok: false,