@midnight-ntwrk/midnight-did-api 0.5.0-rc1

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 (135) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +218 -0
  3. package/dist/api-logger.d.ts +3 -0
  4. package/dist/api-logger.js +8 -0
  5. package/dist/api-logger.js.map +1 -0
  6. package/dist/browser.d.ts +6 -0
  7. package/dist/browser.js +6 -0
  8. package/dist/browser.js.map +1 -0
  9. package/dist/config-profiles.d.ts +75 -0
  10. package/dist/config-profiles.js +75 -0
  11. package/dist/config-profiles.js.map +1 -0
  12. package/dist/config.d.ts +37 -0
  13. package/dist/config.js +50 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/contract-instance.d.ts +7 -0
  16. package/dist/contract-instance.js +6 -0
  17. package/dist/contract-instance.js.map +1 -0
  18. package/dist/contract-lifecycle-operations.d.ts +4 -0
  19. package/dist/contract-lifecycle-operations.js +40 -0
  20. package/dist/contract-lifecycle-operations.js.map +1 -0
  21. package/dist/contract-lifecycle.d.ts +6 -0
  22. package/dist/contract-lifecycle.js +7 -0
  23. package/dist/contract-lifecycle.js.map +1 -0
  24. package/dist/controller-operations.d.ts +9 -0
  25. package/dist/controller-operations.js +49 -0
  26. package/dist/controller-operations.js.map +1 -0
  27. package/dist/deploy.d.ts +6 -0
  28. package/dist/deploy.js +7 -0
  29. package/dist/deploy.js.map +1 -0
  30. package/dist/did-operations.d.ts +6 -0
  31. package/dist/did-operations.js +7 -0
  32. package/dist/did-operations.js.map +1 -0
  33. package/dist/did-subject.d.ts +6 -0
  34. package/dist/did-subject.js +11 -0
  35. package/dist/did-subject.js.map +1 -0
  36. package/dist/document-operations.d.ts +5 -0
  37. package/dist/document-operations.js +17 -0
  38. package/dist/document-operations.js.map +1 -0
  39. package/dist/domain-to-runtime.d.ts +4 -0
  40. package/dist/domain-to-runtime.js +7 -0
  41. package/dist/domain-to-runtime.js.map +1 -0
  42. package/dist/index.d.ts +8 -0
  43. package/dist/index.js +8 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/ledger-mappers.d.ts +15 -0
  46. package/dist/ledger-mappers.js +137 -0
  47. package/dist/ledger-mappers.js.map +1 -0
  48. package/dist/ledger-state.d.ts +6 -0
  49. package/dist/ledger-state.js +24 -0
  50. package/dist/ledger-state.js.map +1 -0
  51. package/dist/lib.d.ts +15 -0
  52. package/dist/lib.js +16 -0
  53. package/dist/lib.js.map +1 -0
  54. package/dist/lightweight.d.ts +1 -0
  55. package/dist/lightweight.js +9 -0
  56. package/dist/lightweight.js.map +1 -0
  57. package/dist/logger-utils.d.ts +3 -0
  58. package/dist/logger-utils.js +26 -0
  59. package/dist/logger-utils.js.map +1 -0
  60. package/dist/network-mapping.d.ts +6 -0
  61. package/dist/network-mapping.js +20 -0
  62. package/dist/network-mapping.js.map +1 -0
  63. package/dist/package-paths.d.ts +10 -0
  64. package/dist/package-paths.js +31 -0
  65. package/dist/package-paths.js.map +1 -0
  66. package/dist/polyfills.d.ts +1 -0
  67. package/dist/polyfills.js +7 -0
  68. package/dist/polyfills.js.map +1 -0
  69. package/dist/private-state-storage.d.ts +8 -0
  70. package/dist/private-state-storage.js +18 -0
  71. package/dist/private-state-storage.js.map +1 -0
  72. package/dist/private-state.d.ts +13 -0
  73. package/dist/private-state.js +75 -0
  74. package/dist/private-state.js.map +1 -0
  75. package/dist/providers.d.ts +13 -0
  76. package/dist/providers.js +32 -0
  77. package/dist/providers.js.map +1 -0
  78. package/dist/release-artifacts.d.ts +41 -0
  79. package/dist/release-artifacts.js +60 -0
  80. package/dist/release-artifacts.js.map +1 -0
  81. package/dist/resolution.d.ts +15 -0
  82. package/dist/resolution.js +46 -0
  83. package/dist/resolution.js.map +1 -0
  84. package/dist/runtime-to-domain.d.ts +4 -0
  85. package/dist/runtime-to-domain.js +7 -0
  86. package/dist/runtime-to-domain.js.map +1 -0
  87. package/dist/seed.d.ts +1 -0
  88. package/dist/seed.js +13 -0
  89. package/dist/seed.js.map +1 -0
  90. package/dist/service-operations.d.ts +6 -0
  91. package/dist/service-operations.js +17 -0
  92. package/dist/service-operations.js.map +1 -0
  93. package/dist/transaction-intents.d.ts +9 -0
  94. package/dist/transaction-intents.js +27 -0
  95. package/dist/transaction-intents.js.map +1 -0
  96. package/dist/types.d.ts +60 -0
  97. package/dist/types.js +9 -0
  98. package/dist/types.js.map +1 -0
  99. package/dist/update.d.ts +7 -0
  100. package/dist/update.js +8 -0
  101. package/dist/update.js.map +1 -0
  102. package/dist/verification-method-operations.d.ts +19 -0
  103. package/dist/verification-method-operations.js +60 -0
  104. package/dist/verification-method-operations.js.map +1 -0
  105. package/dist/verification-method-relations.d.ts +13 -0
  106. package/dist/verification-method-relations.js +40 -0
  107. package/dist/verification-method-relations.js.map +1 -0
  108. package/dist/wallet-context.d.ts +3 -0
  109. package/dist/wallet-context.js +55 -0
  110. package/dist/wallet-context.js.map +1 -0
  111. package/dist/wallet-dust.d.ts +10 -0
  112. package/dist/wallet-dust.js +28 -0
  113. package/dist/wallet-dust.js.map +1 -0
  114. package/dist/wallet-keys.d.ts +5 -0
  115. package/dist/wallet-keys.js +27 -0
  116. package/dist/wallet-keys.js.map +1 -0
  117. package/dist/wallet-provider.d.ts +3 -0
  118. package/dist/wallet-provider.js +29 -0
  119. package/dist/wallet-provider.js.map +1 -0
  120. package/dist/wallet-sdk-config.d.ts +32 -0
  121. package/dist/wallet-sdk-config.js +23 -0
  122. package/dist/wallet-sdk-config.js.map +1 -0
  123. package/dist/wallet-state.d.ts +6 -0
  124. package/dist/wallet-state.js +32 -0
  125. package/dist/wallet-state.js.map +1 -0
  126. package/dist/wallet.d.ts +9 -0
  127. package/dist/wallet.js +17 -0
  128. package/dist/wallet.js.map +1 -0
  129. package/examples/README.md +60 -0
  130. package/examples/bootstrap-issuer-did.ts +313 -0
  131. package/examples/deploy-did.ts +40 -0
  132. package/examples/update-did.ts +84 -0
  133. package/package.json +88 -0
  134. package/tsconfig.build.json +5 -0
  135. package/tsconfig.json +23 -0
package/dist/wallet.js ADDED
@@ -0,0 +1,17 @@
1
+ import "./polyfills.js";
2
+ import { toHex } from "@midnight-ntwrk/midnight-js-utils";
3
+ import { randomBytes } from "./lightweight.js";
4
+ import { createWalletContext } from "./wallet-context.js";
5
+ import { waitForWalletFunds, waitForWalletSync } from "./wallet-state.js";
6
+ export { registerForDustGeneration } from "./wallet-dust.js";
7
+ export { getWalletBalances, serializeWalletState, waitForWalletFunds, waitForWalletSync, } from "./wallet-state.js";
8
+ export const buildWallet = async (config, seed, snapshot) => await createWalletContext(config, seed, snapshot);
9
+ export const restoreWalletFromState = async (config, seed, snapshot) => await createWalletContext(config, seed, snapshot);
10
+ export const buildWalletAndWaitForFunds = async (config, seed) => {
11
+ const walletContext = await buildWallet(config, seed);
12
+ await waitForWalletSync(walletContext);
13
+ await waitForWalletFunds(walletContext);
14
+ return walletContext;
15
+ };
16
+ export const buildFreshWallet = async (config) => await buildWalletAndWaitForFunds(config, toHex(randomBytes(32)));
17
+ //# sourceMappingURL=wallet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet.js","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AAAA,OAAO,gBAAgB,CAAC;AAExB,OAAO,EAAE,KAAK,EAAE,MAAM,mCAAmC,CAAC;AAG1D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAK/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE1E,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAC9B,MAAc,EACd,IAAY,EACZ,QAAsC,EACH,EAAE,CACrC,MAAM,mBAAmB,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AAEpD,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,EACzC,MAAc,EACd,IAAY,EACZ,QAAqC,EACF,EAAE,CACrC,MAAM,mBAAmB,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AAEpD,MAAM,CAAC,MAAM,0BAA0B,GAAG,KAAK,EAC7C,MAAc,EACd,IAAY,EACuB,EAAE;IACrC,MAAM,aAAa,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACtD,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAAC;IACvC,MAAM,kBAAkB,CAAC,aAAa,CAAC,CAAC;IACxC,OAAO,aAAa,CAAC;AACvB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EACnC,MAAc,EACqB,EAAE,CACrC,MAAM,0BAA0B,CAAC,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,60 @@
1
+ # DID API examples
2
+
3
+ These examples are package-level Node/TypeScript snippets for direct API usage.
4
+ They do not import resolver service, manager service, or UI code.
5
+
6
+ Run the examples from the repository root with development dependencies
7
+ installed; the commands use the root `ts-node` dev dependency.
8
+
9
+ ## Deploy a DID
10
+
11
+ Run against a funded standalone wallet seed and local standalone network:
12
+
13
+ ```bash
14
+ MIDNIGHT_WALLET_SEED=<hex-seed> \
15
+ pnpm exec ts-node --esm packages/api/examples/deploy-did.ts
16
+ ```
17
+
18
+ The example builds a wallet, configures providers, initializes DID private state,
19
+ deploys the DID contract, and resolves the resulting DID document.
20
+
21
+ ## Update a DID
22
+
23
+ Run after deployment with the deployed contract address:
24
+
25
+ ```bash
26
+ MIDNIGHT_WALLET_SEED=<hex-seed> \
27
+ MIDNIGHT_DID_CONTRACT_ADDRESS=<contract-address> \
28
+ pnpm exec ts-node --esm packages/api/examples/update-did.ts
29
+ ```
30
+
31
+ The example joins an existing DID contract, adds a verification method and
32
+ authentication relation, adds a DIDComm service, updates the service endpoint,
33
+ and resolves the final DID document.
34
+
35
+ The verification method key value in `update-did.ts` is placeholder key material
36
+ for a disposable standalone flow. Replace it with a real verification method key
37
+ before using the example against any shared or persistent network.
38
+
39
+ ## Bootstrap an issuer DID
40
+
41
+ Run against any standalone Midnight environment to deploy an issuer DID with
42
+ both Ed25519 authentication and Jubjub assertionMethod verification methods,
43
+ emitting a JSON keystore consumable by downstream issuers:
44
+
45
+ ```bash
46
+ ISSUER_BOOTSTRAP_SEED=<hex-seed> \
47
+ ISSUER_KEYSTORE_OUT=./issuer-keystore.json \
48
+ INDEXER_URL=<indexer-url> \
49
+ NODE_RPC_URL=<node-rpc-url> \
50
+ PROOF_SERVER_URL=<proof-server-url> \
51
+ pnpm exec ts-node --esm packages/api/examples/bootstrap-issuer-did.ts
52
+ ```
53
+
54
+ The example builds a funded wallet from the genesis seed, calls
55
+ `createDID` → `addVerificationMethod` (Ed25519) →
56
+ `addVerificationMethodRelation` (authentication) →
57
+ `addSchnorrJubjubVerificationMethod` (Jubjub) →
58
+ `addVerificationMethodRelation` (assertionMethod), wraps each chain write in a
59
+ dust-shortage retry, and writes the resulting keystore to
60
+ `ISSUER_KEYSTORE_OUT`.
@@ -0,0 +1,313 @@
1
+ //! Bootstrap an "issuer DID" with the two verification methods
2
+ //! the OID4VP/VCI flows need (Ed25519 authentication + Jubjub
3
+ //! assertionMethod), then write a JSON keystore consumable by
4
+ //! `IssuerDIDIT-mock/src/services/issuerDid.ts`.
5
+ //!
6
+ //! Lives in the api package's examples/ rather than in the
7
+ //! IssuerDIDIT-mock or the solution-examples workspace because:
8
+ //!
9
+ //! - midnight-did packages have intricate workspace deps
10
+ //! (`jubjub-schnorr` etc.) that only resolve cleanly from
11
+ //! inside *this* workspace. The IssuerDIDIT-mock package
12
+ //! ships intentionally outside any workspace, so it can't pull
13
+ //! the api in transitively.
14
+ //! - The midnight-identity-solution-examples parent workspace
15
+ //! uses a custom `bootstrap-libs.sh`-assembled libs layout
16
+ //! that drops `jubjub-schnorr` entirely.
17
+ //!
18
+ //! From this workspace's root:
19
+ //!
20
+ //! ```bash
21
+ //! ISSUER_BOOTSTRAP_SEED=0000…0001 \
22
+ //! ISSUER_KEYSTORE_OUT=/abs/path/to/issuer-keystore.json \
23
+ //! INDEXER_URL=http://127.0.0.1:8088/api/v3/graphql \
24
+ //! NODE_RPC_URL=http://127.0.0.1:9944 \
25
+ //! PROOF_SERVER_URL=http://127.0.0.1:6300 \
26
+ //! pnpm exec ts-node --esm packages/api/examples/bootstrap-issuer-did.ts
27
+ //! ```
28
+ //!
29
+ //! ## Output keystore JSON shape
30
+ //!
31
+ //! Matches what the Rust `did-bootstrap` CLI produces, so the
32
+ //! existing IssuerDIDIT-mock loader keeps working unchanged:
33
+ //!
34
+ //! ```json
35
+ //! {
36
+ //! "did": "did:midnight:undeployed:...",
37
+ //! "ed25519": { "kid": "did:midnight:...#key-auth", "secret_hex": "..." },
38
+ //! "jubjub": { "kid": "did:midnight:...#key-assert", "secret_hex": "..." }
39
+ //! }
40
+ //! ```
41
+ //!
42
+ //! ## Determinism
43
+ //!
44
+ //! Wallet HD derivation comes from `@midnight-ntwrk/wallet-sdk-hd`
45
+ //! (the TS source of truth — Rust's wallet-core mirrors it; the
46
+ //! 2026-05-29 standalone bootstrap confirmed empirical parity by
47
+ //! pulling the genesis-mint DUST from the derived address).
48
+ //!
49
+ //! Ed25519/Jubjub DID-key secrets are 32 random bytes per
50
+ //! bootstrap (no determinism). Env-wipe between iterations
51
+ //! rotates the DID contract address anyway; deterministic key
52
+ //! bytes buys nothing user-visible. Match the Rust CLI's HKDF
53
+ //! scheme later if a future caller needs reproducible keystore
54
+ //! bytes across runs against the same env.
55
+
56
+ import { createHash, randomBytes } from "node:crypto";
57
+ import { existsSync, writeFileSync } from "node:fs";
58
+
59
+ import {
60
+ createMidnightDIDString,
61
+ parseContractAddress,
62
+ } from "@midnight-ntwrk/midnight-did/midnight";
63
+ import {
64
+ addSchnorrJubjubVerificationMethod,
65
+ addVerificationMethod,
66
+ addVerificationMethodRelation,
67
+ buildWalletAndWaitForFunds,
68
+ configureProviders,
69
+ createDID,
70
+ getMidnightNetwork,
71
+ initPrivateState,
72
+ ProfileConfig,
73
+ registerForDustGeneration,
74
+ resolve,
75
+ } from "@midnight-ntwrk/midnight-did-api";
76
+ import {
77
+ createVerificationMethod,
78
+ CurveType,
79
+ encodeBase64Url,
80
+ KeyType,
81
+ VerificationMethodRelationType,
82
+ VerificationMethodType,
83
+ } from "@midnight-ntwrk/midnight-did-domain";
84
+ import { deriveJubjubPublicKeyFromSeed } from "@midnight-ntwrk/midnight-did-jubjub-schnorr";
85
+ import { ed25519 } from "@noble/curves/ed25519";
86
+
87
+ // ── config from env ─────────────────────────────────────────────
88
+
89
+ const seedInput = process.env.ISSUER_BOOTSTRAP_SEED;
90
+ if (!seedInput || seedInput.length === 0) {
91
+ console.error("Set ISSUER_BOOTSTRAP_SEED (hex 64 chars or any short string)");
92
+ process.exit(2);
93
+ }
94
+
95
+ const outPath = process.env.ISSUER_KEYSTORE_OUT;
96
+ if (!outPath || outPath.length === 0) {
97
+ console.error("Set ISSUER_KEYSTORE_OUT to an absolute path");
98
+ process.exit(2);
99
+ }
100
+
101
+ const indexerUrl =
102
+ process.env.INDEXER_URL ?? "http://127.0.0.1:8088/api/v3/graphql";
103
+ const nodeRpcUrl = process.env.NODE_RPC_URL ?? "http://127.0.0.1:9944";
104
+ const proofServerUrl = process.env.PROOF_SERVER_URL ?? "http://127.0.0.1:6300";
105
+
106
+ if (existsSync(outPath)) {
107
+ console.error(
108
+ `Refusing to overwrite ${outPath}. Delete it manually to re-bootstrap.`,
109
+ );
110
+ process.exit(2);
111
+ }
112
+
113
+ // ── helpers ──────────────────────────────────────────────────────
114
+
115
+ const DUST_RETRY =
116
+ /Not enough Dust generated to pay the fee|could not balance dust/i;
117
+ const sleep = (ms: number): Promise<void> =>
118
+ new Promise((r) => setTimeout(r, ms));
119
+
120
+ async function retryOnDustShortage<T>(
121
+ label: string,
122
+ fn: () => Promise<T>,
123
+ retries = 3,
124
+ delayMs = 8_000,
125
+ ): Promise<T> {
126
+ let lastErr: unknown;
127
+ for (let attempt = 0; attempt <= retries; attempt += 1) {
128
+ try {
129
+ return await fn();
130
+ } catch (err) {
131
+ lastErr = err;
132
+ const msg = err instanceof Error ? err.message : String(err);
133
+ if (attempt === retries || !DUST_RETRY.test(msg)) throw err;
134
+ console.error(
135
+ `[bootstrap] ${label} dust shortage on attempt ${attempt + 1}/${retries + 1}, sleeping ${delayMs}ms`,
136
+ );
137
+ await sleep(delayMs);
138
+ }
139
+ }
140
+ throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
141
+ }
142
+
143
+ function randomSecret32(): Uint8Array {
144
+ return Uint8Array.from(randomBytes(32));
145
+ }
146
+
147
+ /// 64 hex chars (with optional `0x`) → decoded verbatim;
148
+ /// anything else → SHA-256-hashed to 32 bytes. Matches the Rust
149
+ /// CLI's `seed_to_bytes` normalisation exactly so the same
150
+ /// `ISSUER_BOOTSTRAP_SEED` value produces the same wallet seed
151
+ /// across both bootstrap paths.
152
+ function seedToHexString(seed: string): string {
153
+ const stripped = seed.startsWith("0x") ? seed.slice(2) : seed;
154
+ if (stripped.length === 64 && /^[0-9a-fA-F]+$/.test(stripped)) {
155
+ return stripped.toLowerCase();
156
+ }
157
+ return createHash("sha256").update(seed, "utf8").digest("hex");
158
+ }
159
+
160
+ // ── flow ─────────────────────────────────────────────────────────
161
+
162
+ const seedHex = seedToHexString(seedInput);
163
+ console.error(
164
+ `[bootstrap] seed=${seedHex.slice(0, 8)}… (${seedInput === seedHex ? "verbatim hex" : "hashed"})`,
165
+ );
166
+
167
+ const indexer = new URL(indexerUrl);
168
+ const wsScheme = indexer.protocol === "https:" ? "wss:" : "ws:";
169
+ const indexerWS = `${wsScheme}//${indexer.host}${indexer.pathname}/ws`;
170
+
171
+ const dappConfig = new ProfileConfig("standalone", {
172
+ indexer: indexerUrl,
173
+ indexerWS,
174
+ node: nodeRpcUrl,
175
+ proofServer: proofServerUrl,
176
+ });
177
+ console.error(
178
+ `[bootstrap] endpoints: indexer=${dappConfig.indexer} node=${dappConfig.node} proof=${dappConfig.proofServer}`,
179
+ );
180
+
181
+ console.error("[bootstrap] step 1/7 build wallet, wait for funds…");
182
+ const walletCtx = await buildWalletAndWaitForFunds(dappConfig, seedHex);
183
+
184
+ try {
185
+ console.error("[bootstrap] step 2/7 register for dust generation…");
186
+ await registerForDustGeneration(
187
+ walletCtx.wallet,
188
+ walletCtx.unshieldedKeystore,
189
+ );
190
+
191
+ console.error("[bootstrap] step 3/7 configure providers…");
192
+ const providers = await configureProviders(walletCtx, dappConfig);
193
+
194
+ console.error("[bootstrap] step 4/7 init DID private state…");
195
+ const privateState = await initPrivateState(providers);
196
+
197
+ console.error("[bootstrap] step 5/7 createDID (deploy contract)…");
198
+ const contract = await retryOnDustShortage("createDID", () =>
199
+ createDID(providers, privateState),
200
+ );
201
+
202
+ const contractAddress = parseContractAddress(
203
+ contract.deployTxData.public.contractAddress,
204
+ );
205
+ const didString = createMidnightDIDString(
206
+ contractAddress,
207
+ getMidnightNetwork(),
208
+ );
209
+ console.error(`[bootstrap] DID deployed: ${didString}`);
210
+
211
+ // Ed25519 authentication
212
+ const edKid = `${didString}#key-auth`;
213
+ const edSecret = randomSecret32();
214
+ const edPublic = ed25519.getPublicKey(edSecret);
215
+ const edVm = createVerificationMethod({
216
+ id: edKid,
217
+ type: VerificationMethodType.JsonWebKey,
218
+ controller: didString,
219
+ publicKeyJwk: {
220
+ kty: KeyType.OKP,
221
+ crv: CurveType.Ed25519,
222
+ x: encodeBase64Url(edPublic),
223
+ },
224
+ });
225
+ console.error(
226
+ "[bootstrap] step 6/7 attach Ed25519 + authentication relation…",
227
+ );
228
+ await retryOnDustShortage("addVerificationMethod(ed25519)", () =>
229
+ addVerificationMethod(contract, edVm),
230
+ );
231
+ await retryOnDustShortage(
232
+ "addVerificationMethodRelation(authentication)",
233
+ () =>
234
+ addVerificationMethodRelation(
235
+ contract,
236
+ providers,
237
+ VerificationMethodRelationType.Authentication,
238
+ edKid,
239
+ ),
240
+ );
241
+
242
+ // Jubjub assertion
243
+ const jubKid = `${didString}#key-assert`;
244
+ const jubSecret = randomSecret32();
245
+ const jubPublic = deriveJubjubPublicKeyFromSeed(jubSecret);
246
+ console.error(
247
+ "[bootstrap] step 7/7 attach Jubjub + assertionMethod relation…",
248
+ );
249
+ await retryOnDustShortage("addSchnorrJubjubVerificationMethod", () =>
250
+ addSchnorrJubjubVerificationMethod(contract, {
251
+ id: jubKid,
252
+ publicKey: jubPublic,
253
+ }),
254
+ );
255
+ await retryOnDustShortage(
256
+ "addVerificationMethodRelation(assertionMethod)",
257
+ () =>
258
+ addVerificationMethodRelation(
259
+ contract,
260
+ providers,
261
+ VerificationMethodRelationType.AssertionMethod,
262
+ jubKid,
263
+ ),
264
+ );
265
+
266
+ // Verify. The relation arrays may contain bare fragment ids
267
+ // (`#key-auth`) or full DID URLs depending on how the resolver
268
+ // serialised them. We compare by fragment only — that's what
269
+ // the api package's test suite does (`hasSameMethodFragment`
270
+ // in `src/test/did.api.test.ts`).
271
+ const toFragment = (s: string): string => {
272
+ const trimmed = s.trim();
273
+ const hash = trimmed.indexOf("#");
274
+ return hash >= 0 ? trimmed.slice(hash) : `#${trimmed}`;
275
+ };
276
+ type VerificationMethodReference = string | { id: string };
277
+ const referenceToFragment = (
278
+ reference: VerificationMethodReference,
279
+ ): string =>
280
+ toFragment(typeof reference === "string" ? reference : reference.id);
281
+
282
+ const resolution = await resolve(providers, contract);
283
+ const doc = resolution?.didDocument;
284
+ const authFragments = (doc?.authentication ?? []).map(referenceToFragment);
285
+ const assertFragments = (doc?.assertionMethod ?? []).map(referenceToFragment);
286
+ if (!authFragments.includes(toFragment(edKid))) {
287
+ throw new Error(
288
+ `Ed25519 kid ${edKid} (${toFragment(edKid)}) not in authentication relation — got ${JSON.stringify(authFragments)}`,
289
+ );
290
+ }
291
+ if (!assertFragments.includes(toFragment(jubKid))) {
292
+ throw new Error(
293
+ `Jubjub kid ${jubKid} (${toFragment(jubKid)}) not in assertionMethod relation — got ${JSON.stringify(assertFragments)}`,
294
+ );
295
+ }
296
+
297
+ const out = {
298
+ did: didString,
299
+ ed25519: {
300
+ kid: edKid,
301
+ secret_hex: Buffer.from(edSecret).toString("hex"),
302
+ },
303
+ jubjub: {
304
+ kid: jubKid,
305
+ secret_hex: Buffer.from(jubSecret).toString("hex"),
306
+ },
307
+ };
308
+ writeFileSync(outPath, JSON.stringify(out, null, 2));
309
+ console.log(`Wrote ${outPath}`);
310
+ console.log(`Issuer DID: ${didString}`);
311
+ } finally {
312
+ await walletCtx.wallet.stop();
313
+ }
@@ -0,0 +1,40 @@
1
+ import {
2
+ buildWalletAndWaitForFunds,
3
+ configureProviders,
4
+ createDID,
5
+ initPrivateState,
6
+ resolve,
7
+ StandaloneConfig,
8
+ } from "@midnight-ntwrk/midnight-did-api";
9
+
10
+ const seed = process.env.MIDNIGHT_WALLET_SEED;
11
+ if (seed === undefined || seed.length === 0) {
12
+ throw new Error("Set MIDNIGHT_WALLET_SEED to deploy a DID");
13
+ }
14
+
15
+ const bigintReplacer = (_key: string, value: unknown) =>
16
+ typeof value === "bigint" ? value.toString() : value;
17
+
18
+ const config = new StandaloneConfig();
19
+ const walletContext = await buildWalletAndWaitForFunds(config, seed);
20
+
21
+ try {
22
+ const providers = await configureProviders(walletContext, config);
23
+ const privateState = await initPrivateState(providers);
24
+ const didContract = await createDID(providers, privateState);
25
+ const resolution = await resolve(providers, didContract);
26
+
27
+ console.log(
28
+ JSON.stringify(
29
+ {
30
+ contractAddress: didContract.deployTxData.public.contractAddress,
31
+ did: resolution?.didDocument.id,
32
+ resolution,
33
+ },
34
+ bigintReplacer,
35
+ 2,
36
+ ),
37
+ );
38
+ } finally {
39
+ await walletContext.wallet.stop();
40
+ }
@@ -0,0 +1,84 @@
1
+ import {
2
+ addService,
3
+ addVerificationMethod,
4
+ addVerificationMethodRelation,
5
+ buildWalletAndWaitForFunds,
6
+ configureProviders,
7
+ joinContract,
8
+ resolve,
9
+ StandaloneConfig,
10
+ updateService,
11
+ } from "@midnight-ntwrk/midnight-did-api";
12
+ import {
13
+ createService,
14
+ createVerificationMethod,
15
+ CurveType,
16
+ KeyType,
17
+ VerificationMethodRelationType,
18
+ VerificationMethodType,
19
+ } from "@midnight-ntwrk/midnight-did-domain";
20
+
21
+ const seed = process.env.MIDNIGHT_WALLET_SEED;
22
+ const contractAddress = process.env.MIDNIGHT_DID_CONTRACT_ADDRESS;
23
+
24
+ if (seed === undefined || seed.length === 0) {
25
+ throw new Error("Set MIDNIGHT_WALLET_SEED to update a DID");
26
+ }
27
+ if (contractAddress === undefined || contractAddress.length === 0) {
28
+ throw new Error("Set MIDNIGHT_DID_CONTRACT_ADDRESS to update a DID");
29
+ }
30
+
31
+ const bigintReplacer = (_key: string, value: unknown) =>
32
+ typeof value === "bigint" ? value.toString() : value;
33
+
34
+ const config = new StandaloneConfig();
35
+ const walletContext = await buildWalletAndWaitForFunds(config, seed);
36
+
37
+ try {
38
+ const providers = await configureProviders(walletContext, config);
39
+ const didContract = await joinContract(providers, contractAddress);
40
+ const before = await resolve(providers, didContract);
41
+ if (before === null) {
42
+ throw new Error(`No DID contract found at ${contractAddress}`);
43
+ }
44
+
45
+ const did = before.didDocument.id;
46
+ const verificationMethod = createVerificationMethod({
47
+ id: "#example-key-1",
48
+ type: VerificationMethodType.JsonWebKey,
49
+ controller: did,
50
+ publicKeyJwk: {
51
+ kty: KeyType.OKP,
52
+ crv: CurveType.Ed25519,
53
+ // Example-only placeholder key material. Use a real holder/issuer key in applications.
54
+ x: "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE",
55
+ },
56
+ });
57
+
58
+ await addVerificationMethod(didContract, verificationMethod);
59
+ await addVerificationMethodRelation(
60
+ didContract,
61
+ providers,
62
+ VerificationMethodRelationType.Authentication,
63
+ verificationMethod.id,
64
+ );
65
+
66
+ const service = createService({
67
+ id: "#didcomm",
68
+ type: "DIDCommMessaging",
69
+ serviceEndpoint: "https://example.com/didcomm",
70
+ });
71
+ await addService(didContract, service);
72
+ await updateService(
73
+ didContract,
74
+ createService({
75
+ ...service,
76
+ serviceEndpoint: "https://example.com/didcomm/v2",
77
+ }),
78
+ );
79
+
80
+ const after = await resolve(providers, didContract);
81
+ console.log(JSON.stringify(after, bigintReplacer, 2));
82
+ } finally {
83
+ await walletContext.wallet.stop();
84
+ }
package/package.json ADDED
@@ -0,0 +1,88 @@
1
+ {
2
+ "name": "@midnight-ntwrk/midnight-did-api",
3
+ "version": "0.5.0-rc1",
4
+ "license": "Apache-2.0",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/midnightntwrk/midnight-did.git",
9
+ "directory": "packages/api"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public",
13
+ "registry": "https://registry.npmjs.org/"
14
+ },
15
+ "engines": {
16
+ "node": ">=24",
17
+ "pnpm": ">=10"
18
+ },
19
+ "main": "dist/index.js",
20
+ "module": "dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "require": "./dist/index.js",
26
+ "import": "./dist/index.js",
27
+ "default": "./dist/index.js"
28
+ },
29
+ "./browser": {
30
+ "types": "./dist/browser.d.ts",
31
+ "import": "./dist/browser.js",
32
+ "default": "./dist/browser.js"
33
+ }
34
+ },
35
+ "dependencies": {
36
+ "@midnight-ntwrk/compact-js": "2.5.0",
37
+ "@midnight-ntwrk/compact-runtime": "0.15.0",
38
+ "@midnight-ntwrk/ledger-v8": "8.0.3",
39
+ "@midnight-ntwrk/midnight-js-contracts": "4.0.2",
40
+ "@midnight-ntwrk/midnight-js-http-client-proof-provider": "4.0.2",
41
+ "@midnight-ntwrk/midnight-js-indexer-public-data-provider": "4.0.2",
42
+ "@midnight-ntwrk/midnight-js-level-private-state-provider": "4.0.2",
43
+ "@midnight-ntwrk/midnight-js-network-id": "4.0.2",
44
+ "@midnight-ntwrk/midnight-js-node-zk-config-provider": "4.0.2",
45
+ "@midnight-ntwrk/midnight-js-types": "4.0.2",
46
+ "@midnight-ntwrk/midnight-js-utils": "4.0.2",
47
+ "@midnight-ntwrk/wallet-sdk-dust-wallet": "3.0.0",
48
+ "@midnight-ntwrk/wallet-sdk-facade": "3.0.0",
49
+ "@midnight-ntwrk/wallet-sdk-hd": "3.0.0",
50
+ "@midnight-ntwrk/wallet-sdk-shielded": "2.1.0",
51
+ "@midnight-ntwrk/wallet-sdk-unshielded-wallet": "2.1.0",
52
+ "@noble/curves": "^1.9.7",
53
+ "pino": "^9.7.0",
54
+ "pino-pretty": "^13.0.0",
55
+ "rxjs": "7.8.2",
56
+ "ws": "^8.18.2",
57
+ "zod": "^4.1.0",
58
+ "@midnight-ntwrk/midnight-did": "0.5.0-rc1",
59
+ "@midnight-ntwrk/midnight-did-contract": "0.5.0-rc1",
60
+ "@midnight-ntwrk/midnight-did-domain": "0.5.0-rc1"
61
+ },
62
+ "devDependencies": {
63
+ "globals": "14.0.0",
64
+ "long": "5.3.2",
65
+ "protobufjs": "7.6.5",
66
+ "@midnight-ntwrk/midnight-did-jubjub-schnorr": "0.5.0-rc1"
67
+ },
68
+ "files": [
69
+ "dist/**",
70
+ "README.md",
71
+ "examples/**",
72
+ "package.json",
73
+ "tsconfig.json",
74
+ "tsconfig.build.json"
75
+ ],
76
+ "scripts": {
77
+ "clean": "rm -rf dist",
78
+ "build": "pnpm run clean && tsc -b tsconfig.build.json --force",
79
+ "typecheck": "tsc -p tsconfig.json --noEmit",
80
+ "typecheck:examples": "tsc -p tsconfig.examples.json --noEmit",
81
+ "test": "vitest run -c vitest.unit.config.ts --passWithNoTests",
82
+ "test:ci": "vitest run -c vitest.unit.config.ts --passWithNoTests",
83
+ "test-api": "vitest run -c vitest.api.config.ts",
84
+ "coverage": "vitest run -c vitest.unit.config.ts --coverage",
85
+ "lint": "eslint src examples",
86
+ "lint:fix": "eslint src examples --fix"
87
+ }
88
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "exclude": ["src/**/*.test.ts", "src/test/**/*.ts"],
4
+ "compilerOptions": {}
5
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "include": ["src/**/*.ts"],
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src",
6
+ "composite": true,
7
+ "declaration": true,
8
+ "lib": ["ESNext"],
9
+ "target": "ES2022",
10
+ "module": "ESNext",
11
+ "moduleResolution": "Bundler",
12
+ "allowJs": true,
13
+ "forceConsistentCasingInFileNames": true,
14
+ "noImplicitAny": true,
15
+ "strict": true,
16
+ "isolatedModules": true,
17
+ "sourceMap": true,
18
+ "resolveJsonModule": true,
19
+ "esModuleInterop": true,
20
+ "skipLibCheck": true,
21
+ "baseUrl": "."
22
+ }
23
+ }