@agentcontextdistributionprotocol/acdp 0.3.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 (4) hide show
  1. package/README.md +84 -0
  2. package/index.d.ts +402 -0
  3. package/index.js +321 -0
  4. package/package.json +55 -0
package/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # acdp — Node.js SDK
2
+
3
+ Thin NAPI-rs binding over the [`acdp`](https://crates.io/crates/acdp)
4
+ Rust library. Implements the producer- and consumer-side crypto for the
5
+ Agent Context Distribution Protocol v0.1.0 (RFC-ACDP-0001/0003/0008).
6
+ HTTP is intentionally left to the caller — pair this with `fetch` /
7
+ `undici` for transport.
8
+
9
+ ## Install (development)
10
+
11
+ ```bash
12
+ npm install # installs @napi-rs/cli
13
+ npm run build:debug # produces index.js + acdp.<platform>.node
14
+ node --test tests/ # in-process unit tests, no HTTP
15
+ ```
16
+
17
+ ## Build a release binary
18
+
19
+ ```bash
20
+ npm run build # release mode (LTO + strip)
21
+ ```
22
+
23
+ ## Quickstart
24
+
25
+ ```javascript
26
+ import { AcdpProducer, AcdpVerifier } from '@agentcontextdistributionprotocol/acdp';
27
+
28
+ const producer = AcdpProducer.generate(
29
+ 'did:web:agents.example.com:my-agent',
30
+ 'did:web:agents.example.com:my-agent#key-1',
31
+ );
32
+
33
+ const raw = producer.buildPublishRequest({
34
+ title: 'Q1 snapshot',
35
+ contextType: 'data_snapshot',
36
+ summary: 'Quarter-end inventory',
37
+ });
38
+
39
+ // POST `raw` (the JSON string) to your registry. On retrieve:
40
+ const body = (await response.json()).body;
41
+ AcdpVerifier.verifyContentHash(JSON.stringify(body), body.content_hash);
42
+ AcdpVerifier.verifySignature(
43
+ pubKeyB64, // resolved from the producer's did:web doc
44
+ body.signature.value,
45
+ body.content_hash,
46
+ );
47
+ ```
48
+
49
+ ## Design rules
50
+
51
+ * **JSON across the FFI boundary.** Every method accepts and returns
52
+ JSON strings — never a Rust type, never a JS class instance you'd
53
+ have to serialize before sending. The binary stays at ~500 lines of
54
+ glue.
55
+ * **Crypto in Rust, HTTP in JS.** Key generation, JCS + SHA-256 hashing,
56
+ Ed25519 signing, and signature verification happen in the underlying
57
+ `acdp` crate. Transport, retries, and observability are yours.
58
+ * **`AcdpProducer` stores a 32-byte seed.** The Rust `SigningKey` is
59
+ `ZeroizeOnDrop` and not `Clone`, so the binding rebuilds the signing
60
+ key from the seed on each call.
61
+ * **Golden vector parity.** `golden content_hash + signature match
62
+ sig-001` pins the JS-side `content_hash` and `signature.value`
63
+ against the spec's `sig-001` fixture — the same constants the Rust
64
+ suite asserts. A drift on either side is a protocol break.
65
+
66
+ ## Layout
67
+
68
+ ```
69
+ bindings/acdp-node/
70
+ ├── Cargo.toml # standalone [workspace]; depends on `acdp` via path
71
+ ├── build.rs # napi-build setup
72
+ ├── package.json
73
+ ├── README.md # this file
74
+ ├── index.js # generated by `napi build`
75
+ ├── index.d.ts # generated by `napi build`
76
+ ├── acdp.<platform>.node # native binary
77
+ ├── src/
78
+ │ ├── lib.rs # module entry — re-exports the napi classes
79
+ │ ├── producer.rs # AcdpProducer: build/sign publish requests
80
+ │ ├── verifier.rs # AcdpVerifier: content_hash + signature verify
81
+ │ └── helpers.rs # visibility / contextType parsers
82
+ └── tests/
83
+ └── test.mjs
84
+ ```
package/index.d.ts ADDED
@@ -0,0 +1,402 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /* auto-generated by NAPI-RS */
5
+
6
+ /**
7
+ * A verification method resolved to raw public-key bytes, in the
8
+ * base64 shape the host's pinned-key directory speaks.
9
+ */
10
+ export interface ResolvedDidKey {
11
+ /** Verification-method id (full DID URL with `#fragment`). */
12
+ keyId: string
13
+ /** `ed25519` or `ecdsa-p256`. */
14
+ algorithm: string
15
+ /**
16
+ * Standard base64 of the raw key bytes:
17
+ * * ed25519 — 32 bytes
18
+ * * ecdsa-p256 — 65-byte SEC1 uncompressed (`0x04 || x || y`)
19
+ */
20
+ publicKeyB64: string
21
+ }
22
+ /**
23
+ * Options for `buildPublishRequest`. Field names map directly to the
24
+ * PublishRequest wire schema (camelCase on the JS side).
25
+ */
26
+ export interface PublishOpts {
27
+ /** Human-readable title (1..=500 chars). */
28
+ title: string
29
+ /** Closed enum or namespaced custom (`^[a-z][a-z0-9_]*:[a-z][a-z0-9_-]*$`). */
30
+ contextType: string
31
+ /** `public` | `restricted` | `private`. Defaults to `public`. */
32
+ visibility?: string
33
+ /** Long human-readable description (≤ 5000 chars). */
34
+ description?: string
35
+ /**
36
+ * Producer-supplied summary for search results (≤ 1000 chars).
37
+ * Part of ProducerContent — included in the content_hash preimage.
38
+ */
39
+ summary?: string
40
+ /** Free-form tags (each: `^[A-Za-z0-9][A-Za-z0-9_.-]*$`, ≤ 100 chars). */
41
+ tags?: Array<string>
42
+ /** Subject-domain identifier (≤ 200 chars). */
43
+ domain?: string
44
+ /**
45
+ * Producer-specific structured metadata. MUST be a JSON-encoded
46
+ * object string (it is re-parsed so it lands as a JSON object,
47
+ * not a quoted string).
48
+ */
49
+ metadata?: string
50
+ /**
51
+ * Lineage of contexts this body was derived from (`acdp://…` ids,
52
+ * ≤ 1000 unique).
53
+ */
54
+ derivedFrom?: Array<string>
55
+ /** Audience DIDs — required (≥ 1) when `visibility = "restricted"`. */
56
+ audience?: Array<string>
57
+ /** Optional JSON Schema URI describing the metadata shape. */
58
+ schemaUri?: string
59
+ /** Contributors (DIDs, ≤ 100 unique). */
60
+ contributors?: Array<string>
61
+ /**
62
+ * Data references — a JSON-encoded array of `acdp-data-ref` objects.
63
+ * Part of ProducerContent, so it is included in the content_hash
64
+ * preimage.
65
+ */
66
+ dataRefs?: string
67
+ /**
68
+ * RFC 3339 timestamp after which the conclusions should no longer be
69
+ * relied upon. Truncated to millisecond precision.
70
+ */
71
+ expiresAt?: string
72
+ /**
73
+ * Time window the data covers — a JSON object
74
+ * `{"start": <rfc3339>, "end": <rfc3339>}`. Both ends truncated to
75
+ * millisecond precision.
76
+ */
77
+ dataPeriod?: string
78
+ /**
79
+ * Self-verifying `lin:sha256:<hex>` lineage id. v2+ supersession
80
+ * only — rejected on first-version publishes.
81
+ */
82
+ expectedLineageId?: string
83
+ }
84
+ /**
85
+ * Options for `buildSupersedeRequest`. Any field omitted is carried
86
+ * over from `previousBodyJson` unchanged (mirrors `new_version_from`).
87
+ */
88
+ export interface SupersedeOpts {
89
+ title?: string
90
+ summary?: string
91
+ description?: string
92
+ tags?: Array<string>
93
+ domain?: string
94
+ metadata?: string
95
+ /**
96
+ * JSON-encoded array of `acdp-data-ref` objects (replaces the
97
+ * carried-over data refs when present).
98
+ */
99
+ dataRefs?: string
100
+ /** RFC 3339 expiry timestamp. */
101
+ expiresAt?: string
102
+ /** JSON object `{"start": <rfc3339>, "end": <rfc3339>}`. */
103
+ dataPeriod?: string
104
+ /** Self-verifying `lin:sha256:<hex>` lineage id (v2+). */
105
+ expectedLineageId?: string
106
+ }
107
+ /** Stateless did:web string helpers. All methods are static. */
108
+ export declare class AcdpDid {
109
+ /**
110
+ * Translate a `did:web:…` DID to the HTTPS URL of its DID document
111
+ * per RFC-ACDP-0001 §5.11.
112
+ *
113
+ * * `did:web:example.com` → `https://example.com/.well-known/did.json`
114
+ * * `did:web:example.com:users:alice` → `https://example.com/users/alice/did.json`
115
+ *
116
+ * Throws with `.code === "not_did_web"` if the input is not a
117
+ * `did:web` DID.
118
+ */
119
+ static webToUrl(did: string): string
120
+ /**
121
+ * Strip the `#fragment` from a DID URL, returning the bare DID.
122
+ * Returns the input unchanged when it carries no fragment.
123
+ */
124
+ static stripFragment(didUrl: string): string
125
+ }
126
+ /**
127
+ * A parsed did:web DID document. Construct with
128
+ * [`AcdpDidDocument::parse`], then resolve a signing key with
129
+ * [`AcdpDidDocument::key_for_algorithm`].
130
+ */
131
+ export declare class AcdpDidDocument {
132
+ /**
133
+ * Parse a DID document and assert its `id` equals `expectedDid`.
134
+ *
135
+ * `expectedDid` is the bare DID being resolved (no fragment). The
136
+ * `id`-match check (RFC-ACDP-0001 §9.1) stops a misconfigured or
137
+ * hostile server from substituting another DID's keys.
138
+ *
139
+ * Throws `.code === "parse_failed"` on malformed JSON / missing
140
+ * `id`, or `.code === "id_mismatch"` when `id` ≠ `expectedDid`.
141
+ */
142
+ static parse(jsonStr: string, expectedDid: string): AcdpDidDocument
143
+ /** The DID this document describes. */
144
+ get id(): string
145
+ /**
146
+ * Resolve a verification method to raw public-key bytes, enforcing
147
+ * the full consumer-side gate:
148
+ *
149
+ * 1. the method `requestedKeyId` (matched by `#fragment`, exact —
150
+ * no loose suffix) must exist, else `.code === "key_not_found"`;
151
+ * 2. it must be authorized in `assertionMethod`, else
152
+ * `.code === "key_not_authorized"`;
153
+ * 3. any algorithm the method declares (via `type`, JWK params, or
154
+ * multibase multicodec prefix) must equal `requestedAlg`, else
155
+ * `.code === "alg_mismatch"` (downgrade defense, RFC-ACDP-0008
156
+ * §3.9);
157
+ * 4. the key bytes must decode for `requestedAlg`, else
158
+ * `.code === "malformed_key"`.
159
+ *
160
+ * `requestedAlg` is `"ed25519"` or `"ecdsa-p256"`
161
+ * (`.code === "unsupported_algorithm"` otherwise). `requestedKeyId`
162
+ * is the full DID URL from the signature's `key_id`.
163
+ */
164
+ keyForAlgorithm(requestedKeyId: string, requestedAlg: string): ResolvedDidKey
165
+ }
166
+ /** RFC 8785 canonicalization utilities. All methods are static. */
167
+ export declare class AcdpCanonicalizer {
168
+ /**
169
+ * Canonicalize a JSON document to its RFC 8785 (JCS) form.
170
+ *
171
+ * * `jsonStr` — any JSON document as a string.
172
+ *
173
+ * Returns the canonical UTF-8 JSON string (sorted object keys, no
174
+ * whitespace, `-0.0` normalized to `0`, ECMAScript number
175
+ * formatting). Throws on malformed JSON, or if the document nests
176
+ * past the canonicalizer's recursion ceiling.
177
+ */
178
+ static canonicalize(jsonStr: string): string
179
+ /**
180
+ * SHA-256 over the canonical (JCS) form of a JSON document, returned
181
+ * as the ACDP envelope `"sha256:<64-lowercase-hex>"`.
182
+ *
183
+ * This is the hashing primitive behind `content_hash` /
184
+ * `data_ref.content_hash`. It hashes the document *as given* — it
185
+ * does NOT strip the RFC-ACDP-0001 §5.7 exclusion set, so to
186
+ * recompute a body's `content_hash` the caller passes the already
187
+ * producer-controlled object (or uses `AcdpVerifier.verifyContentHash`).
188
+ */
189
+ static contentHash(jsonStr: string): string
190
+ }
191
+ /**
192
+ * An ACDP producer: an Ed25519 signing key and its did:web identity.
193
+ *
194
+ * All methods return wire-ready JSON strings the caller sends via its
195
+ * own HTTP client. No HTTP calls are made inside this class.
196
+ */
197
+ export declare class AcdpProducer {
198
+ /** Generate a producer with a fresh random Ed25519 key (OsRng). */
199
+ static generate(agentDid: string, keyId: string): AcdpProducer
200
+ /** Construct from a 32-byte Ed25519 seed (deterministic). */
201
+ static fromSeed(seed: Buffer, agentDid: string, keyId: string): AcdpProducer
202
+ /** The producer's DID (`did:web:…`). */
203
+ get agentDid(): string
204
+ /** The producer's signing-key DID URL (`did:web:…#key-1`). */
205
+ get keyId(): string
206
+ /**
207
+ * Raw Ed25519 public key as standard base64 (44 chars with padding).
208
+ * Use this to populate a did:web verification method.
209
+ */
210
+ get publicKeyB64(): string
211
+ /**
212
+ * The raw 32-byte seed, for storage in a key vault. Returns a
213
+ * fresh `Buffer` each call — JS owns the bytes.
214
+ */
215
+ seedBytes(): Buffer
216
+ /**
217
+ * Build and sign a first-version PublishRequest. Returns the
218
+ * wire JSON string.
219
+ */
220
+ buildPublishRequest(opts: PublishOpts): string
221
+ /**
222
+ * Build and sign a supersession PublishRequest from a previous
223
+ * version's `Body` JSON. Version is propagated automatically
224
+ * (`previous.version + 1`) and `lineage_id` is carried forward.
225
+ */
226
+ buildSupersedeRequest(previousBodyJson: string, opts: SupersedeOpts): string
227
+ /**
228
+ * Sign a registry auth-challenge `signingInput` string. Returns
229
+ * the base64-encoded Ed25519 signature (88 chars with padding).
230
+ * Used by the ACDP registry's bearer-token flow.
231
+ */
232
+ signChallenge(signingInput: string): string
233
+ }
234
+ /**
235
+ * An ACDP producer signing with ECDSA-P256 (`ecdsa-p256`) instead of
236
+ * the Ed25519 baseline.
237
+ *
238
+ * Mirrors [`AcdpProducer`] exactly — same JSON-in/JSON-out surface and
239
+ * the same `PublishOpts` / `SupersedeOpts` shapes — but emits
240
+ * `signature.algorithm = "ecdsa-p256"` and the IEEE 1363 `r‖s` wire
241
+ * form. Use this when the producer's `did:web` verification method
242
+ * declares a P-256 key. The DID document MUST declare the P-256
243
+ * algorithm so consumers don't reject the signature on
244
+ * algorithm-downgrade grounds (RFC-ACDP-0008 §3.9); use
245
+ * [`AcdpP256Producer::did_verification_method`] to mint that entry.
246
+ */
247
+ export declare class AcdpP256Producer {
248
+ /** Generate a producer with a fresh random P-256 key (OsRng). */
249
+ static generate(agentDid: string, keyId: string): AcdpP256Producer
250
+ /**
251
+ * Construct from a 32-byte P-256 private scalar (deterministic).
252
+ * Throws if the bytes are not exactly 32 or are not a valid scalar.
253
+ */
254
+ static fromSeed(seed: Buffer, agentDid: string, keyId: string): AcdpP256Producer
255
+ /** The producer's DID (`did:web:…`). */
256
+ get agentDid(): string
257
+ /** The producer's signing-key DID URL (`did:web:…#key-1`). */
258
+ get keyId(): string
259
+ /**
260
+ * SEC1-uncompressed public key (`0x04 || x || y`, 65 bytes) as
261
+ * standard base64. Use this to populate a did:web `JsonWebKey2020`
262
+ * verification method.
263
+ */
264
+ get publicKeySec1B64(): string
265
+ /**
266
+ * The producer's P-256 public key as a JWK
267
+ * (`{"kty":"EC","crv":"P-256","x":…,"y":…}`), returned as a JSON
268
+ * object string. Drop this straight into a did:web `JsonWebKey2020`
269
+ * verification method's `publicKeyJwk`.
270
+ */
271
+ get publicKeyJwk(): string
272
+ /**
273
+ * A complete `verificationMethod` entry (JSON object string) for a
274
+ * did:web DID document, of type `JsonWebKey2020`.
275
+ *
276
+ * * `methodId` — the full DID URL for this key (e.g.
277
+ * `"did:web:agents.example.com:alice#key-1"`).
278
+ * * `controller` — the bare DID that owns the key (no fragment).
279
+ *
280
+ * Consumers resolve the signature algorithm from this entry, so
281
+ * publishing it is what keeps a P-256 signature from being rejected
282
+ * on algorithm-downgrade grounds (RFC-ACDP-0008 §3.9).
283
+ */
284
+ didVerificationMethod(methodId: string, controller: string): string
285
+ /**
286
+ * The raw 32-byte private scalar, for storage in a key vault.
287
+ * Returns a fresh `Buffer` each call — JS owns the bytes.
288
+ */
289
+ seedBytes(): Buffer
290
+ /**
291
+ * Build and sign a first-version PublishRequest. Returns the wire
292
+ * JSON string. Same surface as [`AcdpProducer::build_publish_request`];
293
+ * only the signature algorithm differs.
294
+ */
295
+ buildPublishRequest(opts: PublishOpts): string
296
+ /**
297
+ * Build and sign a supersession PublishRequest from a previous
298
+ * version's `Body` JSON. Same semantics as
299
+ * [`AcdpProducer::build_supersede_request`].
300
+ */
301
+ buildSupersedeRequest(previousBodyJson: string, opts: SupersedeOpts): string
302
+ /**
303
+ * Sign a registry auth-challenge `signingInput` string with the
304
+ * producer's P-256 key. Returns the base64 IEEE 1363 signature.
305
+ */
306
+ signChallenge(signingInput: string): string
307
+ }
308
+ /**
309
+ * An SSRF policy: the synchronous classification half of the Rust
310
+ * `SsrfPolicy`, exposed verdict-only (no DNS, no sockets).
311
+ */
312
+ export declare class AcdpSsrfPolicy {
313
+ /**
314
+ * The production policy: HTTPS-only, IP literals rejected, every
315
+ * private / loopback / link-local / IMDS / multicast / reserved
316
+ * range forbidden.
317
+ */
318
+ static production(): AcdpSsrfPolicy
319
+ /**
320
+ * A test-only policy that additionally permits loopback
321
+ * (`127.0.0.0/8` / `::1`) so a test harness can target a local
322
+ * listener. Never use in production.
323
+ */
324
+ static allowTestLoopback(): AcdpSsrfPolicy
325
+ /**
326
+ * Validate a URL: scheme (HTTPS-only), IP-literal rejection, and —
327
+ * for literal hosts — per-IP range filtering.
328
+ *
329
+ * Resolves on success. Throws an `Error` whose `.code` is the stable
330
+ * reason on a policy violation.
331
+ */
332
+ checkUrl(url: string): void
333
+ /**
334
+ * Validate a single already-resolved IP address (IPv4 or IPv6
335
+ * string). This is the per-address predicate the host loops over
336
+ * after resolving DNS itself — rejecting the whole answer set if any
337
+ * address fails (the mixed-answer rule stays in the host).
338
+ *
339
+ * Resolves on success. Throws with `.code === "invalid_ip"` if `ip`
340
+ * is not a valid address, or with the stable range reason if it
341
+ * falls in a forbidden range.
342
+ */
343
+ checkIp(ip: string): void
344
+ /**
345
+ * Validate that a redirect target stays within the origin's fetch
346
+ * authority — identical scheme, host, and effective port (an
347
+ * explicit `:443` equals the implicit https default).
348
+ *
349
+ * Resolves on success. Throws with `.code === "cross_authority"`
350
+ * when the authority differs.
351
+ */
352
+ checkRedirectAuthority(fromUrl: string, toUrl: string): void
353
+ }
354
+ /** Consumer-side verification utilities. All methods are static. */
355
+ export declare class AcdpVerifier {
356
+ /**
357
+ * Verify that a body's `content_hash` matches the SHA-256 over
358
+ * its JCS-canonicalized producer-controlled fields.
359
+ *
360
+ * * `bodyJson` — the `body` object from a `FullContext` retrieval
361
+ * (or the `PublishRequest` itself — both share the §5.7 layout).
362
+ * * `expectedHash` — the `body.content_hash` string
363
+ * (`"sha256:<64-hex>"`).
364
+ *
365
+ * Returns `true` on success; throws on mismatch or bad JSON.
366
+ */
367
+ static verifyContentHash(bodyJson: string, expectedHash: string): boolean
368
+ /**
369
+ * Verify an Ed25519 signature over a `content_hash` string.
370
+ *
371
+ * The signing input per RFC-ACDP-0001 §5.8 is the ASCII bytes of
372
+ * the full `"sha256:<hex>"` string — NOT the raw 32-byte digest.
373
+ *
374
+ * * `pubKeyB64` — standard base64 (padded) of the 32-byte raw
375
+ * Ed25519 public key (same shape as
376
+ * `AcdpProducer.publicKeyB64`).
377
+ * * `sigB64` — the `body.signature.value` field from the wire
378
+ * format.
379
+ * * `contentHash` — the `body.content_hash` string.
380
+ *
381
+ * Returns `true` on success; throws on failure.
382
+ */
383
+ static verifySignature(pubKeyB64: string, sigB64: string, contentHash: string): boolean
384
+ /**
385
+ * Verify an ECDSA-P256 signature over a `content_hash` string.
386
+ *
387
+ * The counterpart to `AcdpP256Producer` signing. The signing input
388
+ * per RFC-ACDP-0001 §5.8 is the ASCII bytes of the full
389
+ * `"sha256:<hex>"` string — NOT the raw 32-byte digest. The wire
390
+ * signature is IEEE 1363 `r‖s` (64 bytes, base64), NOT DER.
391
+ *
392
+ * * `pubKeySec1B64` — standard base64 of the 65-byte
393
+ * SEC1-uncompressed public key (`0x04 || x || y`), the same shape
394
+ * as `AcdpP256Producer.publicKeySec1B64`.
395
+ * * `sigB64` — the `body.signature.value` field from the wire
396
+ * format (88-char base64 of the 64-byte `r‖s`).
397
+ * * `contentHash` — the `body.content_hash` string.
398
+ *
399
+ * Returns `true` on success; throws on failure.
400
+ */
401
+ static verifySignatureP256(pubKeySec1B64: string, sigB64: string, contentHash: string): boolean
402
+ }
package/index.js ADDED
@@ -0,0 +1,321 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /* prettier-ignore */
4
+
5
+ /* auto-generated by NAPI-RS */
6
+
7
+ const { existsSync, readFileSync } = require('fs')
8
+ const { join } = require('path')
9
+
10
+ const { platform, arch } = process
11
+
12
+ let nativeBinding = null
13
+ let localFileExisted = false
14
+ let loadError = null
15
+
16
+ function isMusl() {
17
+ // For Node 10
18
+ if (!process.report || typeof process.report.getReport !== 'function') {
19
+ try {
20
+ const lddPath = require('child_process').execSync('which ldd').toString().trim()
21
+ return readFileSync(lddPath, 'utf8').includes('musl')
22
+ } catch (e) {
23
+ return true
24
+ }
25
+ } else {
26
+ const { glibcVersionRuntime } = process.report.getReport().header
27
+ return !glibcVersionRuntime
28
+ }
29
+ }
30
+
31
+ switch (platform) {
32
+ case 'android':
33
+ switch (arch) {
34
+ case 'arm64':
35
+ localFileExisted = existsSync(join(__dirname, 'acdp.android-arm64.node'))
36
+ try {
37
+ if (localFileExisted) {
38
+ nativeBinding = require('./acdp.android-arm64.node')
39
+ } else {
40
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-android-arm64')
41
+ }
42
+ } catch (e) {
43
+ loadError = e
44
+ }
45
+ break
46
+ case 'arm':
47
+ localFileExisted = existsSync(join(__dirname, 'acdp.android-arm-eabi.node'))
48
+ try {
49
+ if (localFileExisted) {
50
+ nativeBinding = require('./acdp.android-arm-eabi.node')
51
+ } else {
52
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-android-arm-eabi')
53
+ }
54
+ } catch (e) {
55
+ loadError = e
56
+ }
57
+ break
58
+ default:
59
+ throw new Error(`Unsupported architecture on Android ${arch}`)
60
+ }
61
+ break
62
+ case 'win32':
63
+ switch (arch) {
64
+ case 'x64':
65
+ localFileExisted = existsSync(
66
+ join(__dirname, 'acdp.win32-x64-msvc.node')
67
+ )
68
+ try {
69
+ if (localFileExisted) {
70
+ nativeBinding = require('./acdp.win32-x64-msvc.node')
71
+ } else {
72
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-win32-x64-msvc')
73
+ }
74
+ } catch (e) {
75
+ loadError = e
76
+ }
77
+ break
78
+ case 'ia32':
79
+ localFileExisted = existsSync(
80
+ join(__dirname, 'acdp.win32-ia32-msvc.node')
81
+ )
82
+ try {
83
+ if (localFileExisted) {
84
+ nativeBinding = require('./acdp.win32-ia32-msvc.node')
85
+ } else {
86
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-win32-ia32-msvc')
87
+ }
88
+ } catch (e) {
89
+ loadError = e
90
+ }
91
+ break
92
+ case 'arm64':
93
+ localFileExisted = existsSync(
94
+ join(__dirname, 'acdp.win32-arm64-msvc.node')
95
+ )
96
+ try {
97
+ if (localFileExisted) {
98
+ nativeBinding = require('./acdp.win32-arm64-msvc.node')
99
+ } else {
100
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-win32-arm64-msvc')
101
+ }
102
+ } catch (e) {
103
+ loadError = e
104
+ }
105
+ break
106
+ default:
107
+ throw new Error(`Unsupported architecture on Windows: ${arch}`)
108
+ }
109
+ break
110
+ case 'darwin':
111
+ localFileExisted = existsSync(join(__dirname, 'acdp.darwin-universal.node'))
112
+ try {
113
+ if (localFileExisted) {
114
+ nativeBinding = require('./acdp.darwin-universal.node')
115
+ } else {
116
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-darwin-universal')
117
+ }
118
+ break
119
+ } catch {}
120
+ switch (arch) {
121
+ case 'x64':
122
+ localFileExisted = existsSync(join(__dirname, 'acdp.darwin-x64.node'))
123
+ try {
124
+ if (localFileExisted) {
125
+ nativeBinding = require('./acdp.darwin-x64.node')
126
+ } else {
127
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-darwin-x64')
128
+ }
129
+ } catch (e) {
130
+ loadError = e
131
+ }
132
+ break
133
+ case 'arm64':
134
+ localFileExisted = existsSync(
135
+ join(__dirname, 'acdp.darwin-arm64.node')
136
+ )
137
+ try {
138
+ if (localFileExisted) {
139
+ nativeBinding = require('./acdp.darwin-arm64.node')
140
+ } else {
141
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-darwin-arm64')
142
+ }
143
+ } catch (e) {
144
+ loadError = e
145
+ }
146
+ break
147
+ default:
148
+ throw new Error(`Unsupported architecture on macOS: ${arch}`)
149
+ }
150
+ break
151
+ case 'freebsd':
152
+ if (arch !== 'x64') {
153
+ throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
154
+ }
155
+ localFileExisted = existsSync(join(__dirname, 'acdp.freebsd-x64.node'))
156
+ try {
157
+ if (localFileExisted) {
158
+ nativeBinding = require('./acdp.freebsd-x64.node')
159
+ } else {
160
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-freebsd-x64')
161
+ }
162
+ } catch (e) {
163
+ loadError = e
164
+ }
165
+ break
166
+ case 'linux':
167
+ switch (arch) {
168
+ case 'x64':
169
+ if (isMusl()) {
170
+ localFileExisted = existsSync(
171
+ join(__dirname, 'acdp.linux-x64-musl.node')
172
+ )
173
+ try {
174
+ if (localFileExisted) {
175
+ nativeBinding = require('./acdp.linux-x64-musl.node')
176
+ } else {
177
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-linux-x64-musl')
178
+ }
179
+ } catch (e) {
180
+ loadError = e
181
+ }
182
+ } else {
183
+ localFileExisted = existsSync(
184
+ join(__dirname, 'acdp.linux-x64-gnu.node')
185
+ )
186
+ try {
187
+ if (localFileExisted) {
188
+ nativeBinding = require('./acdp.linux-x64-gnu.node')
189
+ } else {
190
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-linux-x64-gnu')
191
+ }
192
+ } catch (e) {
193
+ loadError = e
194
+ }
195
+ }
196
+ break
197
+ case 'arm64':
198
+ if (isMusl()) {
199
+ localFileExisted = existsSync(
200
+ join(__dirname, 'acdp.linux-arm64-musl.node')
201
+ )
202
+ try {
203
+ if (localFileExisted) {
204
+ nativeBinding = require('./acdp.linux-arm64-musl.node')
205
+ } else {
206
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-linux-arm64-musl')
207
+ }
208
+ } catch (e) {
209
+ loadError = e
210
+ }
211
+ } else {
212
+ localFileExisted = existsSync(
213
+ join(__dirname, 'acdp.linux-arm64-gnu.node')
214
+ )
215
+ try {
216
+ if (localFileExisted) {
217
+ nativeBinding = require('./acdp.linux-arm64-gnu.node')
218
+ } else {
219
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-linux-arm64-gnu')
220
+ }
221
+ } catch (e) {
222
+ loadError = e
223
+ }
224
+ }
225
+ break
226
+ case 'arm':
227
+ if (isMusl()) {
228
+ localFileExisted = existsSync(
229
+ join(__dirname, 'acdp.linux-arm-musleabihf.node')
230
+ )
231
+ try {
232
+ if (localFileExisted) {
233
+ nativeBinding = require('./acdp.linux-arm-musleabihf.node')
234
+ } else {
235
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-linux-arm-musleabihf')
236
+ }
237
+ } catch (e) {
238
+ loadError = e
239
+ }
240
+ } else {
241
+ localFileExisted = existsSync(
242
+ join(__dirname, 'acdp.linux-arm-gnueabihf.node')
243
+ )
244
+ try {
245
+ if (localFileExisted) {
246
+ nativeBinding = require('./acdp.linux-arm-gnueabihf.node')
247
+ } else {
248
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-linux-arm-gnueabihf')
249
+ }
250
+ } catch (e) {
251
+ loadError = e
252
+ }
253
+ }
254
+ break
255
+ case 'riscv64':
256
+ if (isMusl()) {
257
+ localFileExisted = existsSync(
258
+ join(__dirname, 'acdp.linux-riscv64-musl.node')
259
+ )
260
+ try {
261
+ if (localFileExisted) {
262
+ nativeBinding = require('./acdp.linux-riscv64-musl.node')
263
+ } else {
264
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-linux-riscv64-musl')
265
+ }
266
+ } catch (e) {
267
+ loadError = e
268
+ }
269
+ } else {
270
+ localFileExisted = existsSync(
271
+ join(__dirname, 'acdp.linux-riscv64-gnu.node')
272
+ )
273
+ try {
274
+ if (localFileExisted) {
275
+ nativeBinding = require('./acdp.linux-riscv64-gnu.node')
276
+ } else {
277
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-linux-riscv64-gnu')
278
+ }
279
+ } catch (e) {
280
+ loadError = e
281
+ }
282
+ }
283
+ break
284
+ case 's390x':
285
+ localFileExisted = existsSync(
286
+ join(__dirname, 'acdp.linux-s390x-gnu.node')
287
+ )
288
+ try {
289
+ if (localFileExisted) {
290
+ nativeBinding = require('./acdp.linux-s390x-gnu.node')
291
+ } else {
292
+ nativeBinding = require('@agentcontextdistributionprotocol/acdp-linux-s390x-gnu')
293
+ }
294
+ } catch (e) {
295
+ loadError = e
296
+ }
297
+ break
298
+ default:
299
+ throw new Error(`Unsupported architecture on Linux: ${arch}`)
300
+ }
301
+ break
302
+ default:
303
+ throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
304
+ }
305
+
306
+ if (!nativeBinding) {
307
+ if (loadError) {
308
+ throw loadError
309
+ }
310
+ throw new Error(`Failed to load native binding`)
311
+ }
312
+
313
+ const { AcdpDid, AcdpDidDocument, AcdpCanonicalizer, AcdpProducer, AcdpP256Producer, AcdpSsrfPolicy, AcdpVerifier } = nativeBinding
314
+
315
+ module.exports.AcdpDid = AcdpDid
316
+ module.exports.AcdpDidDocument = AcdpDidDocument
317
+ module.exports.AcdpCanonicalizer = AcdpCanonicalizer
318
+ module.exports.AcdpProducer = AcdpProducer
319
+ module.exports.AcdpP256Producer = AcdpP256Producer
320
+ module.exports.AcdpSsrfPolicy = AcdpSsrfPolicy
321
+ module.exports.AcdpVerifier = AcdpVerifier
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@agentcontextdistributionprotocol/acdp",
3
+ "version": "0.3.0",
4
+ "description": "Agent Context Distribution Protocol — Node.js SDK",
5
+ "license": "MIT OR Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/agentcontextdistributionprotocol/acdp-rs.git",
9
+ "directory": "bindings/acdp-node"
10
+ },
11
+ "homepage": "https://github.com/agentcontextdistributionprotocol/acdp-rs/tree/main/bindings/acdp-node",
12
+ "main": "index.js",
13
+ "types": "index.d.ts",
14
+ "type": "commonjs",
15
+ "files": [
16
+ "index.js",
17
+ "index.d.ts"
18
+ ],
19
+ "napi": {
20
+ "name": "acdp",
21
+ "triples": {
22
+ "defaults": false,
23
+ "additional": [
24
+ "x86_64-apple-darwin",
25
+ "aarch64-apple-darwin",
26
+ "x86_64-unknown-linux-gnu",
27
+ "aarch64-unknown-linux-gnu"
28
+ ]
29
+ }
30
+ },
31
+ "scripts": {
32
+ "build": "napi build --platform --release",
33
+ "build:debug": "napi build --platform",
34
+ "artifacts": "napi artifacts",
35
+ "prepublishOnly": "napi prepublish -t npm",
36
+ "version": "napi version",
37
+ "test": "node --test tests/*.mjs"
38
+ },
39
+ "devDependencies": {
40
+ "@napi-rs/cli": "^2.18.0"
41
+ },
42
+ "engines": {
43
+ "node": ">=16"
44
+ },
45
+ "publishConfig": {
46
+ "access": "public",
47
+ "registry": "https://registry.npmjs.org/"
48
+ },
49
+ "optionalDependencies": {
50
+ "@agentcontextdistributionprotocol/acdp-darwin-x64": "0.3.0",
51
+ "@agentcontextdistributionprotocol/acdp-darwin-arm64": "0.3.0",
52
+ "@agentcontextdistributionprotocol/acdp-linux-x64-gnu": "0.3.0",
53
+ "@agentcontextdistributionprotocol/acdp-linux-arm64-gnu": "0.3.0"
54
+ }
55
+ }