@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 +18 -10
- package/dist/index.cjs +18 -7
- package/dist/index.js +18 -7
- package/package.json +4 -4
- package/src/http-submitter.ts +26 -8
- package/types/index.d.ts +11 -5
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
|
|
24
|
-
//
|
|
25
|
-
// member server
|
|
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
|
|
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
|
|
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
|
|
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({
|
|
92
|
-
|
|
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
|
-
|
|
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
|
|
315
|
-
*
|
|
316
|
-
* `
|
|
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: {
|
|
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 ===
|
|
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:
|
|
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
|
|
314
|
-
*
|
|
315
|
-
* `
|
|
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: {
|
|
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 ===
|
|
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:
|
|
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.
|
|
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.
|
|
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.
|
|
45
|
-
"@coordination-network/network-member-proof": "^0.0.
|
|
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",
|
package/src/http-submitter.ts
CHANGED
|
@@ -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 =
|
|
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
|
|
22
|
-
*
|
|
23
|
-
* `
|
|
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: {
|
|
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 ===
|
|
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:
|
|
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
|
|
162
|
-
*
|
|
163
|
-
* `
|
|
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 };
|