@coordination-network/user-client 0.0.1 → 0.0.2

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 CHANGED
@@ -20,10 +20,10 @@ console.log(networkId) // 0x-prefixed bytes32
20
20
  console.log(displayMetaStealthAddress) // "st:eth:0x..."
21
21
 
22
22
  // InMemoryIdentityRegistry and InMemoryMemberServer are test/demo fakes standing in for the
23
- // registry's read model and the network member's server. A real deployment uses
24
- // network-member-client's IdentityRegistryClient as the RegistryReader and an HTTP client for the
25
- // member server's registration endpoint as the RegistrationSubmitter — see "Dependency-injection
26
- // seams" below.
23
+ // registry's read model and the network member's server. A real deployment splits this across
24
+ // two processes: the holder's app signs the request and hands it to the network member's app,
25
+ // which submits it to its own member server, carrying that server's own token — see
26
+ // "Dependency-injection seams" below.
27
27
  const registry = new InMemoryIdentityRegistry()
28
28
  const memberServer = new InMemoryMemberServer(registry, { chainId: 1, verifyingContract: "0x..." })
29
29
 
@@ -58,7 +58,7 @@ if (result.status === "registered") {
58
58
  | `InMemoryIdentityRegistry` | class | In-memory `RegistryReader` fake for tests/local dev. `registerIdentity` is write-once. | `registerIdentity` throws `SubmissionFailedError` (`InvalidMetaStealthAddressLength` or `AlreadyRegistered`). |
59
59
  | `InMemoryMemberServer` | class | In-memory `RegistrationSubmitter` fake standing in for an approved network member's server. | `submit` throws `SubmissionFailedError` on `InvalidRegistrationRequest` or `AlreadyRegistered`. |
60
60
  | `createHttpRegistrationSubmitter` | function | Builds a `RegistrationSubmitter` that POSTs to a member server's `/v1/registrations` endpoint over `fetch`. | `HttpSubmissionError` for every non-submitted response and on a network failure. |
61
- | `HttpSubmissionError` | class | Extends `SubmissionFailedError`. Carries `status`, `reason` (`"alreadyRegistered" \| "rejected" \| "unavailable" \| "network" \| "invalidResponse"`), and, where the server sent them, `serverCode`/`metaStealthAddress`/`matchesRequest`. | — |
61
+ | `HttpSubmissionError` | class | Extends `SubmissionFailedError`. Carries `status`, `reason` (`"alreadyRegistered" \| "rejected" \| "unavailable" \| "unauthorized" \| "network" \| "invalidResponse"`), and when sent, `serverCode`/`metaStealthAddress`/`matchesRequest`. | — |
62
62
  | `UserClientError` | class | Base error class for this package, discriminated by `code: UserClientErrorCode`. | — |
63
63
  | `InvalidMetaStealthAddressError` | class | Re-exported from `@coordination-network/identity`. Extends its `KeygenError`, not `UserClientError`, and names the malformed key. Thrown when encoding a meta-stealth address. | — |
64
64
  | `SubmissionFailedError` | class | Extends `UserClientError` (`code: "SUBMISSION_FAILED"`). Thrown when a `RegistrationSubmitter.submit` call fails, including on a lost duplicate-registration race (see below). | — |
@@ -79,26 +79,34 @@ git diff --exit-code packages/user-client/tests/vectors/registration-vectors.jso
79
79
 
80
80
  **Implementing `RegistryReader` against a chain.** `IdentityRegistry` stores the mapping as `bytes`, so its generated getter answers an unregistered `networkId` with empty bytes. viem and ethers surface that as `"0x"`, and the port requires `null`. `register()` rejects anything that is neither `null` nor a 66-byte entry rather than reading it as an existing registration, but an adapter should map the empty answer to `null` itself.
81
81
 
82
- `RegistryReader` (read an identity's current registration) and `RegistrationSubmitter` (submit a new one) are dependency-injection interfaces, not concrete transports. On chain, writes are gated on an approved network member's Semaphore proof (`IdentityRegistry.registerIdentity(networkId, metaStealthAddress, proof)`; the proof comes from `@coordination-network/network-member-proof`). The user's signature is consent the member server verifies off chain with `verifyRegistrationRequest` before it builds the proof and submits; the contract never reads it. No credential check sits on this path (#46). The gas-sponsorship model is settled ([`specs/05-stealth-addresses.md`](../../specs/05-stealth-addresses.md), "Gas sponsorship"): registration stays self-submitted and self-paid by the network-member server, and only post-registration transactions go through the shared amortised Semaphore paymaster. Any future transport — a relayer, a meta-transaction relay, a bundler — plugs in as a new `RegistrationSubmitter` implementation without changing this package's API. `InMemoryIdentityRegistry` and `InMemoryMemberServer` are in-memory fakes for tests and local development; `@coordination-network/network-member-client`'s `IdentityRegistryClient` satisfies `RegistryReader` (it maps the getter's empty bytes to `null`); `createHttpRegistrationSubmitter` (below) is the real `RegistrationSubmitter`, an HTTP client for `apps/issuer-service`'s `POST /v1/registrations`, which verifies consent with `verifyRegistrationRequest` and submits it via `network-member-client`'s `submitRegistration`.
82
+ `RegistryReader` (read an identity's current registration) and `RegistrationSubmitter` (submit a new one) are dependency-injection interfaces, not concrete transports. On chain, writes are gated on an approved network member's Semaphore proof (`IdentityRegistry.registerIdentity(networkId, metaStealthAddress, proof)`; the proof comes from `@coordination-network/network-member-proof`). The user's signature is consent the member server verifies off chain with `verifyRegistrationRequest` before it builds the proof and submits; the contract never reads it. No credential check sits on this path (#46). The gas-sponsorship model is settled ([`specs/05-stealth-addresses.md`](../../specs/05-stealth-addresses.md), "Gas sponsorship"): registration stays self-submitted and self-paid by the network-member server, and only post-registration transactions go through the shared amortised Semaphore paymaster. Any future transport — a relayer, a meta-transaction relay, a bundler — plugs in as a new `RegistrationSubmitter` implementation without changing this package's API. `InMemoryIdentityRegistry` and `InMemoryMemberServer` are in-memory fakes for tests and local development; `@coordination-network/network-member-client`'s `IdentityRegistryClient` satisfies `RegistryReader` (it maps the getter's empty bytes to `null`); `createHttpRegistrationSubmitter` (below) is the member-side HTTP `RegistrationSubmitter`, for a process the organisation runs that holds its `memberServerToken`; it posts to `apps/issuer-service`'s `POST /v1/registrations`, which verifies consent with `verifyRegistrationRequest` and submits it via `network-member-client`'s `submitRegistration`.
83
83
 
84
84
  ### HTTP submitter
85
85
 
86
- `createHttpRegistrationSubmitter({ url })` POSTs the `RegistrationRequest` as JSON to `${url}/v1/registrations` and maps the member server's response onto this package's types:
86
+ A member-side process calls `submitter.submit(request)` with the `RegistrationRequest` the holder already built and signed with this package's own `buildRegistrationRequest`. `createHttpRegistrationSubmitter({ url, memberServerToken })` POSTs that request as JSON to `${url}/v1/registrations` and maps the member server's response onto this package's types:
87
87
 
88
88
  ```typescript
89
89
  import { createHttpRegistrationSubmitter } from "@coordination-network/user-client"
90
90
 
91
- const submitter = createHttpRegistrationSubmitter({ url: "https://member.example" })
92
- const result = await register({ deviceSecret, registry, submitter, domain })
91
+ const submitter = createHttpRegistrationSubmitter({
92
+ url: "https://member.example",
93
+ memberServerToken: process.env.MEMBER_SERVER_TOKEN
94
+ })
95
+ await submitter.submit(request)
93
96
  ```
94
97
 
95
- A `201` resolves `submit()` with `{ txHash }`. A `200` (the member server's `alreadyRegistered` response) throws `HttpSubmissionError` (`reason: "alreadyRegistered"`) carrying the registry's current `metaStealthAddress`; catch it and re-run `register()` — its own `registry.getIdentity` read will now see that entry and return the `alreadyRegistered` result instead. `400`, `503`, and a network failure throw `HttpSubmissionError` with `reason: "rejected"`, `"unavailable"` (with the server's own `serverCode`, if it sent one), and `"network"`, respectively. `HttpSubmissionError` never includes the request body or its signature.
98
+ `memberServerToken` is the Network Member Server's own bearer token (`apps/issuer-service`'s `MEMBER_SERVER_TOKEN`), sent as `Authorization: Bearer <memberServerToken>` when set; the registration route now requires it. That token belongs to a member-side process the organisation itself runs, not to a holder — never pass one from a holder's wallet or app bundle.
99
+
100
+ Don't pair the Quickstart's `register()` composition with a `createHttpRegistrationSubmitter` that holds `memberServerToken` anywhere but a trusted single process such as a local testbed; on a holder's device, give `register()` a `RegistrationSubmitter` that hands the signed request to the member's app instead.
101
+
102
+ A `201` resolves `submit()` with `{ txHash }`. A `200` (the member server's `alreadyRegistered` response) throws `HttpSubmissionError` (`reason: "alreadyRegistered"`) carrying the registry's current `metaStealthAddress` and `matchesRequest`; a member-side caller has no device secret to re-run `register()` with, so treat those fields as the answer — the identity is already registered, and `matchesRequest` says whether it's already this request's address. A caller that is itself running `register()` (a trusted single process) can instead just re-run it: its own `registry.getIdentity` read will now see the entry and return the `alreadyRegistered` result instead. `400` throws `reason: "rejected"`; `401` (a missing or wrong `memberServerToken`) throws `reason: "unauthorized"`; `429` and `503` both throw `reason: "unavailable"` carrying the server's own `serverCode` (`"RATE_LIMITED"` for a `429`); and a network failure throws `reason: "network"`. `HttpSubmissionError` never includes the request body or its signature.
96
103
 
97
104
  ## Security notes
98
105
 
99
106
  - **`status: "registered"` means submitted, not confirmed.** `register()` returns as soon as the injected `RegistrationSubmitter` resolves. It does not wait for inclusion or check a receipt, and `receipt.txHash` is `null` for a submitter that queues rather than broadcasts. A transaction that is mined and reverts also resolves here.
100
107
  - **An existing entry is reported, not verified, and can change.** Only `registerIdentity` refuses a duplicate; an approved network member can `updateIdentity` or `removeIdentity` any entry at any time. If `alreadyRegistered` comes back with `matchesDerived: false`, this device's keys do not derive the meta-stealth address its `networkId` currently resolves to, and that is recoverable only through a member calling `updateIdentity`. A `matchesDerived: true` result is not permanent either — re-read `getIdentity` and compare against `metaStealthAddressFromKeys` whenever the mapping is load-bearing.
101
108
  - **Consent is checked by the member server, not the chain.** `IdentityRegistry` gates writes on a Semaphore proof, not on the user's signature. A member server that skips `verifyRegistrationRequest` can register any `metaStealthAddress` under any `networkId`, since its membership proof covers whatever pair it submits. Comparing `metaStealthAddress` with `derivedMetaStealthAddress` (the bullet above) is how a user detects that.
109
+ - **`memberServerToken` leaking is worse than one bad registration.** Anyone who extracts it can act as that member on every member-side route, not just registration.
102
110
  - **Duplicate-registration races.** If two `register()` calls for the same `networkId` are in flight at once, both will see no existing registration and both will attempt `submit()`. The losing submission surfaces as a `SubmissionFailedError` (`AlreadyRegistered`, in `InMemoryMemberServer`'s case). The caller should simply retry `register()`: the retry's `registry.getIdentity` lookup will now find the winner's registration and return the `alreadyRegistered` result instead of erroring.
103
111
  - **React Native / Hermes.** `@coordination-network/identity`'s barrel loads on Hermes without a global `Buffer` — `onboard` and `register` don't need one. An app that also depends on something else expecting Node's `Buffer` may still want to set a polyfill globally for that code, but this package's own path does not require it.
104
112
 
package/dist/index.cjs CHANGED
@@ -311,9 +311,11 @@ async function register(params) {
311
311
 
312
312
  /**
313
313
  * Thrown by {@link createHttpRegistrationSubmitter}. `alreadyRegistered`
314
- * carries the registry's current entry so a caller can re-run `register()`
315
- * and land in its own `alreadyRegistered` branch once that's visible to
316
- * `params.registry.getIdentity`.
314
+ * carries the registry's current `metaStealthAddress` and `matchesRequest`
315
+ * as the answer — a member-side caller has no device secret to re-run
316
+ * `register()` with. A caller that is itself running `register()` (a
317
+ * trusted single process) can instead just re-run it, since its own
318
+ * `registry.getIdentity` read will now return `alreadyRegistered`.
317
319
  */
318
320
  class HttpSubmissionError extends SubmissionFailedError {
319
321
  constructor(message, init) {
@@ -342,14 +344,17 @@ function parseTxHash(value) {
342
344
  * Never logs or throws the request body or its signature — only the response
343
345
  * status and, where sent, the server's own error code.
344
346
  */
345
- function createHttpRegistrationSubmitter({ url, fetch: fetchImpl = fetch }) {
347
+ function createHttpRegistrationSubmitter({ url, fetch: fetchImpl = fetch, memberServerToken }) {
346
348
  return {
347
349
  async submit(request) {
348
350
  let response;
349
351
  try {
350
352
  response = await fetchImpl(`${url}/v1/registrations`, {
351
353
  method: "POST",
352
- headers: { "Content-Type": "application/json" },
354
+ headers: {
355
+ "Content-Type": "application/json",
356
+ ...(memberServerToken === undefined ? {} : { Authorization: `Bearer ${memberServerToken}` })
357
+ },
353
358
  body: JSON.stringify(request)
354
359
  });
355
360
  }
@@ -395,9 +400,15 @@ function createHttpRegistrationSubmitter({ url, fetch: fetchImpl = fetch }) {
395
400
  reason: "rejected"
396
401
  });
397
402
  }
398
- if (response.status === 503) {
403
+ if (response.status === 401) {
404
+ throw new HttpSubmissionError("Registration submission was not authorized", {
405
+ status: 401,
406
+ reason: "unauthorized"
407
+ });
408
+ }
409
+ if (response.status === 429 || response.status === 503) {
399
410
  throw new HttpSubmissionError("Registration service is unavailable", {
400
- status: 503,
411
+ status: response.status,
401
412
  reason: "unavailable",
402
413
  serverCode: body?.code
403
414
  });
package/dist/index.js CHANGED
@@ -310,9 +310,11 @@ async function register(params) {
310
310
 
311
311
  /**
312
312
  * Thrown by {@link createHttpRegistrationSubmitter}. `alreadyRegistered`
313
- * carries the registry's current entry so a caller can re-run `register()`
314
- * and land in its own `alreadyRegistered` branch once that's visible to
315
- * `params.registry.getIdentity`.
313
+ * carries the registry's current `metaStealthAddress` and `matchesRequest`
314
+ * as the answer — a member-side caller has no device secret to re-run
315
+ * `register()` with. A caller that is itself running `register()` (a
316
+ * trusted single process) can instead just re-run it, since its own
317
+ * `registry.getIdentity` read will now return `alreadyRegistered`.
316
318
  */
317
319
  class HttpSubmissionError extends SubmissionFailedError {
318
320
  constructor(message, init) {
@@ -341,14 +343,17 @@ function parseTxHash(value) {
341
343
  * Never logs or throws the request body or its signature — only the response
342
344
  * status and, where sent, the server's own error code.
343
345
  */
344
- function createHttpRegistrationSubmitter({ url, fetch: fetchImpl = fetch }) {
346
+ function createHttpRegistrationSubmitter({ url, fetch: fetchImpl = fetch, memberServerToken }) {
345
347
  return {
346
348
  async submit(request) {
347
349
  let response;
348
350
  try {
349
351
  response = await fetchImpl(`${url}/v1/registrations`, {
350
352
  method: "POST",
351
- headers: { "Content-Type": "application/json" },
353
+ headers: {
354
+ "Content-Type": "application/json",
355
+ ...(memberServerToken === undefined ? {} : { Authorization: `Bearer ${memberServerToken}` })
356
+ },
352
357
  body: JSON.stringify(request)
353
358
  });
354
359
  }
@@ -394,9 +399,15 @@ function createHttpRegistrationSubmitter({ url, fetch: fetchImpl = fetch }) {
394
399
  reason: "rejected"
395
400
  });
396
401
  }
397
- if (response.status === 503) {
402
+ if (response.status === 401) {
403
+ throw new HttpSubmissionError("Registration submission was not authorized", {
404
+ status: 401,
405
+ reason: "unauthorized"
406
+ });
407
+ }
408
+ if (response.status === 429 || response.status === 503) {
398
409
  throw new HttpSubmissionError("Registration service is unavailable", {
399
- status: 503,
410
+ status: response.status,
400
411
  reason: "unavailable",
401
412
  serverCode: body?.code
402
413
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coordination-network/user-client",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Single-call onboarding and registration for the coordination network: derive device keys, encode the meta-stealth address, and register networkId -> metaStealthAddress on IdentityRegistry.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -36,13 +36,13 @@
36
36
  "build": "rimraf dist types && rollup -c rollup.config.mjs"
37
37
  },
38
38
  "dependencies": {
39
- "@coordination-network/identity": "^0.0.1",
39
+ "@coordination-network/identity": "^0.0.2",
40
40
  "@noble/curves": "^1.9.7",
41
41
  "@noble/hashes": "^1.8.0"
42
42
  },
43
43
  "devDependencies": {
44
- "@coordination-network/network-member-client": "^0.0.1",
45
- "@coordination-network/network-member-proof": "^0.0.1",
44
+ "@coordination-network/network-member-client": "^0.0.2",
45
+ "@coordination-network/network-member-proof": "^0.0.2",
46
46
  "@rollup/plugin-typescript": "^12.3.0",
47
47
  "@semaphore-protocol/group": "4.14.3",
48
48
  "@semaphore-protocol/identity": "4.14.3",
@@ -3,7 +3,8 @@ import { hexToBytes } from "./bytes"
3
3
  import { TX_HASH_LENGTH } from "./constants"
4
4
  import { SubmissionFailedError } from "./errors"
5
5
 
6
- export type HttpSubmissionReason = "alreadyRegistered" | "rejected" | "unavailable" | "network" | "invalidResponse"
6
+ export type HttpSubmissionReason =
7
+ "alreadyRegistered" | "rejected" | "unavailable" | "unauthorized" | "network" | "invalidResponse"
7
8
 
8
9
  export interface HttpSubmissionErrorInit {
9
10
  status?: number
@@ -18,9 +19,11 @@ export interface HttpSubmissionErrorInit {
18
19
 
19
20
  /**
20
21
  * Thrown by {@link createHttpRegistrationSubmitter}. `alreadyRegistered`
21
- * carries the registry's current entry so a caller can re-run `register()`
22
- * and land in its own `alreadyRegistered` branch once that's visible to
23
- * `params.registry.getIdentity`.
22
+ * carries the registry's current `metaStealthAddress` and `matchesRequest`
23
+ * as the answer — a member-side caller has no device secret to re-run
24
+ * `register()` with. A caller that is itself running `register()` (a
25
+ * trusted single process) can instead just re-run it, since its own
26
+ * `registry.getIdentity` read will now return `alreadyRegistered`.
24
27
  */
25
28
  export class HttpSubmissionError extends SubmissionFailedError {
26
29
  readonly status?: number
@@ -43,6 +46,10 @@ export class HttpSubmissionError extends SubmissionFailedError {
43
46
  export interface HttpRegistrationSubmitterOptions {
44
47
  url: string
45
48
  fetch?: typeof fetch
49
+ /** Bearer token for the Network Member Server's member-side routes, sent as
50
+ * `Authorization: Bearer <memberServerToken>` when set. The server's own token — never a
51
+ * holder's, so it must not ship in a wallet or app bundle. */
52
+ memberServerToken?: string
46
53
  }
47
54
 
48
55
  interface SubmittedBody {
@@ -77,7 +84,8 @@ function parseTxHash(value: unknown): Hex | null {
77
84
  */
78
85
  export function createHttpRegistrationSubmitter({
79
86
  url,
80
- fetch: fetchImpl = fetch
87
+ fetch: fetchImpl = fetch,
88
+ memberServerToken
81
89
  }: HttpRegistrationSubmitterOptions): RegistrationSubmitter {
82
90
  return {
83
91
  async submit(request: RegistrationRequest): Promise<SubmissionReceipt> {
@@ -85,7 +93,10 @@ export function createHttpRegistrationSubmitter({
85
93
  try {
86
94
  response = await fetchImpl(`${url}/v1/registrations`, {
87
95
  method: "POST",
88
- headers: { "Content-Type": "application/json" },
96
+ headers: {
97
+ "Content-Type": "application/json",
98
+ ...(memberServerToken === undefined ? {} : { Authorization: `Bearer ${memberServerToken}` })
99
+ },
89
100
  body: JSON.stringify(request)
90
101
  })
91
102
  } catch (error) {
@@ -134,9 +145,16 @@ export function createHttpRegistrationSubmitter({
134
145
  })
135
146
  }
136
147
 
137
- if (response.status === 503) {
148
+ if (response.status === 401) {
149
+ throw new HttpSubmissionError("Registration submission was not authorized", {
150
+ status: 401,
151
+ reason: "unauthorized"
152
+ })
153
+ }
154
+
155
+ if (response.status === 429 || response.status === 503) {
138
156
  throw new HttpSubmissionError("Registration service is unavailable", {
139
- status: 503,
157
+ status: response.status,
140
158
  reason: "unavailable",
141
159
  serverCode: (body as ErrorBody | null)?.code
142
160
  })
package/types/index.d.ts CHANGED
@@ -145,7 +145,7 @@ declare class InMemoryMemberServer implements RegistrationSubmitter {
145
145
  declare function onboard(deviceSecret: Uint8Array | Hex): Onboarding;
146
146
  declare function register(params: RegisterParams): Promise<RegisterResult>;
147
147
 
148
- type HttpSubmissionReason = "alreadyRegistered" | "rejected" | "unavailable" | "network" | "invalidResponse";
148
+ type HttpSubmissionReason = "alreadyRegistered" | "rejected" | "unavailable" | "unauthorized" | "network" | "invalidResponse";
149
149
  interface HttpSubmissionErrorInit {
150
150
  status?: number;
151
151
  reason: HttpSubmissionReason;
@@ -158,9 +158,11 @@ interface HttpSubmissionErrorInit {
158
158
  }
159
159
  /**
160
160
  * Thrown by {@link createHttpRegistrationSubmitter}. `alreadyRegistered`
161
- * carries the registry's current entry so a caller can re-run `register()`
162
- * and land in its own `alreadyRegistered` branch once that's visible to
163
- * `params.registry.getIdentity`.
161
+ * carries the registry's current `metaStealthAddress` and `matchesRequest`
162
+ * as the answer — a member-side caller has no device secret to re-run
163
+ * `register()` with. A caller that is itself running `register()` (a
164
+ * trusted single process) can instead just re-run it, since its own
165
+ * `registry.getIdentity` read will now return `alreadyRegistered`.
164
166
  */
165
167
  declare class HttpSubmissionError extends SubmissionFailedError {
166
168
  readonly status?: number;
@@ -173,13 +175,17 @@ declare class HttpSubmissionError extends SubmissionFailedError {
173
175
  interface HttpRegistrationSubmitterOptions {
174
176
  url: string;
175
177
  fetch?: typeof fetch;
178
+ /** Bearer token for the Network Member Server's member-side routes, sent as
179
+ * `Authorization: Bearer <memberServerToken>` when set. The server's own token — never a
180
+ * holder's, so it must not ship in a wallet or app bundle. */
181
+ memberServerToken?: string;
176
182
  }
177
183
  /**
178
184
  * HTTP `RegistrationSubmitter` for `apps/issuer-service`'s `POST /v1/registrations`.
179
185
  * Never logs or throws the request body or its signature — only the response
180
186
  * status and, where sent, the server's own error code.
181
187
  */
182
- declare function createHttpRegistrationSubmitter({ url, fetch: fetchImpl }: HttpRegistrationSubmitterOptions): RegistrationSubmitter;
188
+ declare function createHttpRegistrationSubmitter({ url, fetch: fetchImpl, memberServerToken }: HttpRegistrationSubmitterOptions): RegistrationSubmitter;
183
189
 
184
190
  export { DIGEST_LENGTH, EIP712_DOMAIN_TYPE, HttpSubmissionError, IDENTITY_REGISTRY_DOMAIN_NAME, IDENTITY_REGISTRY_DOMAIN_VERSION, InMemoryIdentityRegistry, InMemoryMemberServer, NETWORK_ID_LENGTH, REGISTER_IDENTITY_TYPE, REQUEST_VERSION, RegistryReadFailedError, SCHEME_ID, SIGNATURE_LENGTH, SubmissionFailedError, TX_HASH_LENGTH, UserClientError, buildRegistrationRequest, createHttpRegistrationSubmitter, identityRegistryDomainSeparator, metaStealthAddressFromKeys, onboard, register, registerIdentityDigest, registerIdentityStructHash, signRegisterIdentity, verifyRegistrationRequest };
185
191
  export type { ChainDomain, Hex, HttpRegistrationSubmitterOptions, HttpSubmissionErrorInit, HttpSubmissionReason, Onboarding, RegisterParams, RegisterResult, RegistrationRequest, RegistrationSubmitter, RegistryReader, SubmissionReceipt, UserClientErrorCode };