@labacacia/nps-sdk 1.0.0-alpha.3 → 1.0.0-alpha.4

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 (212) hide show
  1. package/CHANGELOG.cn.md +53 -0
  2. package/CHANGELOG.md +62 -0
  3. package/README.cn.md +8 -2
  4. package/README.md +8 -2
  5. package/dist/core/anchor-cache.js +104 -0
  6. package/dist/core/anchor-cache.js.map +1 -0
  7. package/dist/core/cache.js +80 -0
  8. package/dist/core/cache.js.map +1 -0
  9. package/dist/core/canonical-json.js +44 -0
  10. package/dist/core/canonical-json.js.map +1 -0
  11. package/dist/core/codec.js +119 -0
  12. package/dist/core/codec.js.map +1 -0
  13. package/dist/core/codecs/index.js +6 -0
  14. package/dist/core/codecs/index.js.map +1 -0
  15. package/dist/core/codecs/ncp-codec.js +93 -0
  16. package/dist/core/codecs/ncp-codec.js.map +1 -0
  17. package/dist/core/codecs/tier1-json-codec.js +28 -0
  18. package/dist/core/codecs/tier1-json-codec.js.map +1 -0
  19. package/dist/core/codecs/tier2-msgpack-codec.js +26 -0
  20. package/dist/core/codecs/tier2-msgpack-codec.js.map +1 -0
  21. package/dist/core/crypto-provider.js +10 -0
  22. package/dist/core/crypto-provider.js.map +1 -0
  23. package/dist/core/exceptions.js +52 -0
  24. package/dist/core/exceptions.js.map +1 -0
  25. package/dist/core/frame-header.js +185 -0
  26. package/dist/core/frame-header.js.map +1 -0
  27. package/dist/core/frame-registry.js +63 -0
  28. package/dist/core/frame-registry.js.map +1 -0
  29. package/dist/core/frames.js +154 -0
  30. package/dist/core/frames.js.map +1 -0
  31. package/dist/core/index.js +21 -405
  32. package/dist/core/index.js.map +1 -1
  33. package/dist/core/registry.js +17 -0
  34. package/dist/core/registry.js.map +1 -0
  35. package/dist/core/status-codes.js +38 -0
  36. package/dist/core/status-codes.js.map +1 -0
  37. package/dist/index.d.ts +1 -1
  38. package/dist/index.js +9 -5
  39. package/dist/index.js.map +1 -1
  40. package/dist/ncp/frames/anchor-frame.js +54 -0
  41. package/dist/ncp/frames/anchor-frame.js.map +1 -0
  42. package/dist/ncp/frames/caps-frame.js +29 -0
  43. package/dist/ncp/frames/caps-frame.js.map +1 -0
  44. package/dist/ncp/frames/diff-frame.js +37 -0
  45. package/dist/ncp/frames/diff-frame.js.map +1 -0
  46. package/dist/ncp/frames/error-frame.js +13 -0
  47. package/dist/ncp/frames/error-frame.js.map +1 -0
  48. package/dist/ncp/frames/hello-frame.js +25 -0
  49. package/dist/ncp/frames/hello-frame.js.map +1 -0
  50. package/dist/ncp/frames/stream-frame.js +18 -0
  51. package/dist/ncp/frames/stream-frame.js.map +1 -0
  52. package/dist/ncp/frames.js +192 -0
  53. package/dist/ncp/frames.js.map +1 -0
  54. package/dist/ncp/handshake.js +80 -0
  55. package/dist/ncp/handshake.js.map +1 -0
  56. package/dist/ncp/index.d.ts +1 -0
  57. package/dist/ncp/index.d.ts.map +1 -1
  58. package/dist/ncp/index.js +13 -368
  59. package/dist/ncp/index.js.map +1 -1
  60. package/dist/ncp/ncp-error-codes.d.ts +1 -0
  61. package/dist/ncp/ncp-error-codes.d.ts.map +1 -1
  62. package/dist/ncp/ncp-error-codes.js +34 -0
  63. package/dist/ncp/ncp-error-codes.js.map +1 -0
  64. package/dist/ncp/ncp-patch-format.js +13 -0
  65. package/dist/ncp/ncp-patch-format.js.map +1 -0
  66. package/dist/ncp/preamble.d.ts +47 -0
  67. package/dist/ncp/preamble.d.ts.map +1 -0
  68. package/dist/ncp/preamble.js +74 -0
  69. package/dist/ncp/preamble.js.map +1 -0
  70. package/dist/ncp/registry.js +13 -0
  71. package/dist/ncp/registry.js.map +1 -0
  72. package/dist/ncp/stream-manager.js +163 -0
  73. package/dist/ncp/stream-manager.js.map +1 -0
  74. package/dist/ndp/frames.js +87 -0
  75. package/dist/ndp/frames.js.map +1 -0
  76. package/dist/ndp/index.js +6 -223
  77. package/dist/ndp/index.js.map +1 -1
  78. package/dist/ndp/ndp-registry.js +79 -0
  79. package/dist/ndp/ndp-registry.js.map +1 -0
  80. package/dist/ndp/registry.js +10 -0
  81. package/dist/ndp/registry.js.map +1 -0
  82. package/dist/ndp/validator.js +48 -0
  83. package/dist/ndp/validator.js.map +1 -0
  84. package/dist/nip/acme/client.d.ts +31 -0
  85. package/dist/nip/acme/client.d.ts.map +1 -0
  86. package/dist/nip/acme/client.js +136 -0
  87. package/dist/nip/acme/client.js.map +1 -0
  88. package/dist/nip/acme/index.d.ts +6 -0
  89. package/dist/nip/acme/index.d.ts.map +1 -0
  90. package/dist/nip/acme/index.js +8 -0
  91. package/dist/nip/acme/index.js.map +1 -0
  92. package/dist/nip/acme/jws.d.ts +31 -0
  93. package/dist/nip/acme/jws.d.ts.map +1 -0
  94. package/dist/nip/acme/jws.js +76 -0
  95. package/dist/nip/acme/jws.js.map +1 -0
  96. package/dist/nip/acme/messages.d.ts +71 -0
  97. package/dist/nip/acme/messages.d.ts.map +1 -0
  98. package/dist/nip/acme/messages.js +4 -0
  99. package/dist/nip/acme/messages.js.map +1 -0
  100. package/dist/nip/acme/server.d.ts +41 -0
  101. package/dist/nip/acme/server.d.ts.map +1 -0
  102. package/dist/nip/acme/server.js +458 -0
  103. package/dist/nip/acme/server.js.map +1 -0
  104. package/dist/nip/acme/wire.d.ts +19 -0
  105. package/dist/nip/acme/wire.d.ts.map +1 -0
  106. package/dist/nip/acme/wire.js +21 -0
  107. package/dist/nip/acme/wire.js.map +1 -0
  108. package/dist/nip/assurance-level.d.ts +14 -0
  109. package/dist/nip/assurance-level.d.ts.map +1 -0
  110. package/dist/nip/assurance-level.js +33 -0
  111. package/dist/nip/assurance-level.js.map +1 -0
  112. package/dist/nip/cert-format.d.ts +5 -0
  113. package/dist/nip/cert-format.d.ts.map +1 -0
  114. package/dist/nip/cert-format.js +6 -0
  115. package/dist/nip/cert-format.js.map +1 -0
  116. package/dist/nip/error-codes.d.ts +23 -0
  117. package/dist/nip/error-codes.d.ts.map +1 -0
  118. package/dist/nip/error-codes.js +30 -0
  119. package/dist/nip/error-codes.js.map +1 -0
  120. package/dist/nip/frames.d.ts +10 -1
  121. package/dist/nip/frames.d.ts.map +1 -1
  122. package/dist/nip/frames.js +106 -0
  123. package/dist/nip/frames.js.map +1 -0
  124. package/dist/nip/identity.js +94 -0
  125. package/dist/nip/identity.js.map +1 -0
  126. package/dist/nip/index.d.ts +6 -0
  127. package/dist/nip/index.d.ts.map +1 -1
  128. package/dist/nip/index.js +12 -187
  129. package/dist/nip/index.js.map +1 -1
  130. package/dist/nip/registry.js +10 -0
  131. package/dist/nip/registry.js.map +1 -0
  132. package/dist/nip/verifier.d.ts +23 -0
  133. package/dist/nip/verifier.d.ts.map +1 -0
  134. package/dist/nip/verifier.js +90 -0
  135. package/dist/nip/verifier.js.map +1 -0
  136. package/dist/nip/x509/builder.d.ts +35 -0
  137. package/dist/nip/x509/builder.d.ts.map +1 -0
  138. package/dist/nip/x509/builder.js +59 -0
  139. package/dist/nip/x509/builder.js.map +1 -0
  140. package/dist/nip/x509/index.d.ts +4 -0
  141. package/dist/nip/x509/index.d.ts.map +1 -0
  142. package/dist/nip/x509/index.js +6 -0
  143. package/dist/nip/x509/index.js.map +1 -0
  144. package/dist/nip/x509/oids.d.ts +17 -0
  145. package/dist/nip/x509/oids.d.ts.map +1 -0
  146. package/dist/nip/x509/oids.js +23 -0
  147. package/dist/nip/x509/oids.js.map +1 -0
  148. package/dist/nip/x509/verifier.d.ts +26 -0
  149. package/dist/nip/x509/verifier.d.ts.map +1 -0
  150. package/dist/nip/x509/verifier.js +171 -0
  151. package/dist/nip/x509/verifier.js.map +1 -0
  152. package/dist/nop/client.js +90 -0
  153. package/dist/nop/client.js.map +1 -0
  154. package/dist/nop/frames.js +148 -0
  155. package/dist/nop/frames.js.map +1 -0
  156. package/dist/nop/index.js +6 -789
  157. package/dist/nop/index.js.map +1 -1
  158. package/dist/nop/models.js +50 -0
  159. package/dist/nop/models.js.map +1 -0
  160. package/dist/nop/nop-types.js +44 -0
  161. package/dist/nop/nop-types.js.map +1 -0
  162. package/dist/nop/registry.js +11 -0
  163. package/dist/nop/registry.js.map +1 -0
  164. package/dist/nwp/client.js +101 -0
  165. package/dist/nwp/client.js.map +1 -0
  166. package/dist/nwp/frames.js +81 -0
  167. package/dist/nwp/frames.js.map +1 -0
  168. package/dist/nwp/index.js +5 -693
  169. package/dist/nwp/index.js.map +1 -1
  170. package/dist/nwp/registry.js +9 -0
  171. package/dist/nwp/registry.js.map +1 -0
  172. package/dist/setup.js +29 -0
  173. package/dist/setup.js.map +1 -0
  174. package/package.json +2 -1
  175. package/src/index.ts +1 -1
  176. package/src/ncp/index.ts +1 -0
  177. package/src/ncp/ncp-error-codes.ts +2 -0
  178. package/src/ncp/preamble.ts +79 -0
  179. package/src/nip/acme/client.ts +185 -0
  180. package/src/nip/acme/index.ts +8 -0
  181. package/src/nip/acme/jws.ts +109 -0
  182. package/src/nip/acme/messages.ts +85 -0
  183. package/src/nip/acme/server.ts +480 -0
  184. package/src/nip/acme/wire.ts +24 -0
  185. package/src/nip/assurance-level.ts +35 -0
  186. package/src/nip/cert-format.ts +9 -0
  187. package/src/nip/error-codes.ts +36 -0
  188. package/src/nip/frames.ts +35 -3
  189. package/src/nip/index.ts +8 -0
  190. package/src/nip/verifier.ts +122 -0
  191. package/src/nip/x509/builder.ts +91 -0
  192. package/src/nip/x509/index.ts +6 -0
  193. package/src/nip/x509/oids.ts +28 -0
  194. package/src/nip/x509/verifier.ts +214 -0
  195. package/tests/_rfc0002-keys.ts +57 -0
  196. package/tests/ncp/preamble.test.ts +93 -0
  197. package/tests/nip-acme-agent01.test.ts +192 -0
  198. package/tests/nip-x509.test.ts +280 -0
  199. package/dist/core/index.cjs +0 -452
  200. package/dist/core/index.cjs.map +0 -1
  201. package/dist/index.cjs +0 -8
  202. package/dist/index.cjs.map +0 -1
  203. package/dist/ncp/index.cjs +0 -388
  204. package/dist/ncp/index.cjs.map +0 -1
  205. package/dist/ndp/index.cjs +0 -252
  206. package/dist/ndp/index.cjs.map +0 -1
  207. package/dist/nip/index.cjs +0 -214
  208. package/dist/nip/index.cjs.map +0 -1
  209. package/dist/nop/index.cjs +0 -823
  210. package/dist/nop/index.cjs.map +0 -1
  211. package/dist/nwp/index.cjs +0 -720
  212. package/dist/nwp/index.cjs.map +0 -1
@@ -0,0 +1,90 @@
1
+ // Copyright 2026 INNO LOTUS PTY LTD
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * NipIdentVerifier — Phase 1 dual-trust IdentFrame verifier per NPS-RFC-0002 §8.1.
5
+ *
6
+ * Steps:
7
+ * 1. v1 Ed25519 signature check against the issuer's CA public key.
8
+ * 2. Optional minimum assurance level check.
9
+ * 3b. X.509 chain validation (only if `cert_format === "v2-x509"` AND
10
+ * `trustedX509Roots` is configured).
11
+ */
12
+ import * as ed25519 from "@noble/ed25519";
13
+ import { sha512 } from "@noble/hashes/sha512";
14
+ import { AssuranceLevel } from "./assurance-level.js";
15
+ import * as cf from "./cert-format.js";
16
+ import * as ec from "./error-codes.js";
17
+ import { verify as verifyX509 } from "./x509/verifier.js";
18
+ // noble/ed25519 needs sha512 wired up.
19
+ ed25519.etc.sha512Sync = (...m) => sha512(ed25519.etc.concatBytes(...m));
20
+ function ok() { return { valid: true, stepFailed: 0 }; }
21
+ function fail(stepFailed, errorCode, message) {
22
+ return { valid: false, stepFailed, errorCode, message };
23
+ }
24
+ export class NipIdentVerifier {
25
+ options;
26
+ constructor(options) {
27
+ this.options = options;
28
+ }
29
+ async verify(frame, issuerNid) {
30
+ // Step 1: v1 Ed25519 signature check ────────────────────────────────
31
+ const caPubKeyStr = this.options.trustedCaPublicKeys?.[issuerNid];
32
+ if (caPubKeyStr === undefined) {
33
+ return fail(1, ec.CERT_UNTRUSTED_ISSUER, `no trusted CA public key for issuer: ${issuerNid}`);
34
+ }
35
+ if (!frame.signature?.startsWith("ed25519:")) {
36
+ return fail(1, ec.CERT_SIGNATURE_INVALID, "missing or malformed signature");
37
+ }
38
+ try {
39
+ const caPubBytes = parsePubKeyString(caPubKeyStr);
40
+ const sigBytes = Buffer.from(frame.signature.slice("ed25519:".length), "base64");
41
+ const canonical = canonicalJson(frame.unsignedDict());
42
+ const msg = new TextEncoder().encode(canonical);
43
+ if (!ed25519.verify(sigBytes, msg, caPubBytes)) {
44
+ return fail(1, ec.CERT_SIGNATURE_INVALID, "v1 Ed25519 signature did not verify against issuer CA key");
45
+ }
46
+ }
47
+ catch (e) {
48
+ return fail(1, ec.CERT_SIGNATURE_INVALID, `v1 signature verification error: ${e.message}`);
49
+ }
50
+ // Step 2: minimum assurance level ───────────────────────────────────
51
+ const minLevel = this.options.minAssuranceLevel;
52
+ if (minLevel !== undefined) {
53
+ const got = frame.assuranceLevel ?? AssuranceLevel.ANONYMOUS;
54
+ if (!got.meetsOrExceeds(minLevel)) {
55
+ return fail(2, ec.ASSURANCE_MISMATCH, `assurance_level (${got.wire}) below required minimum (${minLevel.wire})`);
56
+ }
57
+ }
58
+ // Step 3b: X.509 chain check (only if both opt-ins present) ──────────
59
+ const trustedRoots = this.options.trustedX509Roots ?? [];
60
+ const hasV2Trust = trustedRoots.length > 0;
61
+ const isV2Frame = frame.certFormat === cf.V2_X509;
62
+ if (hasV2Trust && isV2Frame) {
63
+ const x509Result = await verifyX509({
64
+ certChainBase64UrlDer: frame.certChain ?? [],
65
+ assertedNid: frame.nid,
66
+ assertedAssuranceLevel: frame.assuranceLevel,
67
+ trustedRootCerts: trustedRoots,
68
+ });
69
+ if (!x509Result.valid) {
70
+ return fail(3, x509Result.errorCode ?? ec.CERT_FORMAT_INVALID, x509Result.message ?? "X.509 chain validation failed");
71
+ }
72
+ }
73
+ return ok();
74
+ }
75
+ }
76
+ /**
77
+ * Canonical JSON matching NipIdentity.sign — top-level keys filtered/ordered
78
+ * via `Object.keys(payload).sort()` as JSON.stringify replacer.
79
+ */
80
+ function canonicalJson(payload) {
81
+ return JSON.stringify(payload, Object.keys(payload).sort());
82
+ }
83
+ /** Parse `ed25519:<hex>` into a 32-byte Uint8Array public key. */
84
+ function parsePubKeyString(s) {
85
+ if (!s.startsWith("ed25519:")) {
86
+ throw new Error(`Unsupported public key format: ${s}`);
87
+ }
88
+ return new Uint8Array(Buffer.from(s.slice("ed25519:".length), "hex"));
89
+ }
90
+ //# sourceMappingURL=verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier.js","sourceRoot":"","sources":["../../src/nip/verifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Issues NPS X.509 NID certificates per NPS-RFC-0002 §4.
3
+ *
4
+ * Backed by @peculiar/x509 + Web Crypto Ed25519 (Node 22+).
5
+ *
6
+ * Two factory functions:
7
+ * - {@link issueLeaf} — leaf cert with critical NPS EKU + SAN URI = NID + assurance-level extension.
8
+ * - {@link issueRoot} — self-signed root for testing / private-CA use.
9
+ */
10
+ import * as x509 from "@peculiar/x509";
11
+ import { AssuranceLevel } from "../assurance-level.js";
12
+ export type LeafRole = "agent" | "node";
13
+ export interface IssueLeafOptions {
14
+ subjectNid: string;
15
+ subjectPublicKey: CryptoKey;
16
+ caKeys: CryptoKeyPair;
17
+ issuerNid: string;
18
+ role: LeafRole;
19
+ assuranceLevel: AssuranceLevel;
20
+ notBefore: Date;
21
+ notAfter: Date;
22
+ serialNumber: string;
23
+ }
24
+ export interface IssueRootOptions {
25
+ caNid: string;
26
+ caKeys: CryptoKeyPair;
27
+ notBefore: Date;
28
+ notAfter: Date;
29
+ serialNumber: string;
30
+ }
31
+ /** Issue a leaf NPS NID certificate (RFC-0002 §4.1). */
32
+ export declare function issueLeaf(opts: IssueLeafOptions): Promise<x509.X509Certificate>;
33
+ /** Issue a self-signed CA root cert (testing / private CA). */
34
+ export declare function issueRoot(opts: IssueRootOptions): Promise<x509.X509Certificate>;
35
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/nip/x509/builder.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAOvD,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAExC,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAU,MAAM,CAAC;IAC3B,gBAAgB,EAAI,SAAS,CAAC;IAC9B,MAAM,EAAc,aAAa,CAAC;IAClC,SAAS,EAAW,MAAM,CAAC;IAC3B,IAAI,EAAgB,QAAQ,CAAC;IAC7B,cAAc,EAAM,cAAc,CAAC;IACnC,SAAS,EAAW,IAAI,CAAC;IACzB,QAAQ,EAAY,IAAI,CAAC;IACzB,YAAY,EAAQ,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAe,MAAM,CAAC;IAC3B,MAAM,EAAc,aAAa,CAAC;IAClC,SAAS,EAAW,IAAI,CAAC;IACzB,QAAQ,EAAY,IAAI,CAAC;IACzB,YAAY,EAAQ,MAAM,CAAC;CAC5B;AAED,wDAAwD;AACxD,wBAAsB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAuBrF;AAED,+DAA+D;AAC/D,wBAAsB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAcrF"}
@@ -0,0 +1,59 @@
1
+ // Copyright 2026 INNO LOTUS PTY LTD
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Issues NPS X.509 NID certificates per NPS-RFC-0002 §4.
5
+ *
6
+ * Backed by @peculiar/x509 + Web Crypto Ed25519 (Node 22+).
7
+ *
8
+ * Two factory functions:
9
+ * - {@link issueLeaf} — leaf cert with critical NPS EKU + SAN URI = NID + assurance-level extension.
10
+ * - {@link issueRoot} — self-signed root for testing / private-CA use.
11
+ */
12
+ import * as x509 from "@peculiar/x509";
13
+ import { EKU_AGENT_IDENTITY, EKU_NODE_IDENTITY, NID_ASSURANCE_LEVEL } from "./oids.js";
14
+ // Initialize @peculiar/x509 cryptoProvider once on first import. Web Crypto
15
+ // (globalThis.crypto) supports Ed25519 in Node 18+.
16
+ x509.cryptoProvider.set(globalThis.crypto);
17
+ /** Issue a leaf NPS NID certificate (RFC-0002 §4.1). */
18
+ export async function issueLeaf(opts) {
19
+ const ekuOid = opts.role === "node" ? EKU_NODE_IDENTITY : EKU_AGENT_IDENTITY;
20
+ // ASN.1 ENUMERATED encoding of assurance level: tag=0x0A, len=0x01, value=<rank>.
21
+ const assuranceDer = new Uint8Array([0x0A, 0x01, opts.assuranceLevel.rank]);
22
+ return x509.X509CertificateGenerator.create({
23
+ serialNumber: opts.serialNumber,
24
+ issuer: `CN=${escapeDn(opts.issuerNid)}`,
25
+ subject: `CN=${escapeDn(opts.subjectNid)}`,
26
+ notBefore: opts.notBefore,
27
+ notAfter: opts.notAfter,
28
+ publicKey: opts.subjectPublicKey,
29
+ signingAlgorithm: { name: "Ed25519" },
30
+ signingKey: opts.caKeys.privateKey,
31
+ extensions: [
32
+ new x509.BasicConstraintsExtension(false, undefined, true),
33
+ new x509.KeyUsagesExtension(x509.KeyUsageFlags.digitalSignature, true),
34
+ new x509.ExtendedKeyUsageExtension([ekuOid], true),
35
+ new x509.SubjectAlternativeNameExtension([{ type: "url", value: opts.subjectNid }], false),
36
+ new x509.Extension(NID_ASSURANCE_LEVEL, false, assuranceDer),
37
+ ],
38
+ });
39
+ }
40
+ /** Issue a self-signed CA root cert (testing / private CA). */
41
+ export async function issueRoot(opts) {
42
+ return x509.X509CertificateGenerator.createSelfSigned({
43
+ serialNumber: opts.serialNumber,
44
+ name: `CN=${escapeDn(opts.caNid)}`,
45
+ notBefore: opts.notBefore,
46
+ notAfter: opts.notAfter,
47
+ signingAlgorithm: { name: "Ed25519" },
48
+ keys: opts.caKeys,
49
+ extensions: [
50
+ new x509.BasicConstraintsExtension(true, undefined, true),
51
+ new x509.KeyUsagesExtension(x509.KeyUsageFlags.keyCertSign | x509.KeyUsageFlags.cRLSign, true),
52
+ ],
53
+ });
54
+ }
55
+ function escapeDn(value) {
56
+ // Escape characters that have special meaning in RFC 4514 DN syntax.
57
+ return value.replace(/([",+;<>\\])/g, "\\$1");
58
+ }
59
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.js","sourceRoot":"","sources":["../../../src/nip/x509/builder.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,sCAAsC;AAEtC;;;;;;;;GAQG;AAEH,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AAGvC,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEvF,4EAA4E;AAC5E,oDAAoD;AACpD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAwB3C,wDAAwD;AACxD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAsB;IACpD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,kBAAkB,CAAC;IAE7E,kFAAkF;IAClF,MAAM,YAAY,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;IAE5E,OAAO,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC;QAC1C,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,MAAM,EAAQ,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;QAC9C,OAAO,EAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE;QAC/C,SAAS,EAAK,IAAI,CAAC,SAAS;QAC5B,QAAQ,EAAM,IAAI,CAAC,QAAQ;QAC3B,SAAS,EAAK,IAAI,CAAC,gBAAgB;QACnC,gBAAgB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QACrC,UAAU,EAAI,IAAI,CAAC,MAAM,CAAC,UAAU;QACpC,UAAU,EAAE;YACV,IAAI,IAAI,CAAC,yBAAyB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC;YAC1D,IAAI,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,gBAAgB,EAAE,IAAI,CAAC;YACtE,IAAI,IAAI,CAAC,yBAAyB,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC;YAClD,IAAI,IAAI,CAAC,+BAA+B,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,KAAK,CAAC;YAC1F,IAAI,IAAI,CAAC,SAAS,CAAC,mBAAmB,EAAE,KAAK,EAAE,YAAY,CAAC;SAC7D;KACF,CAAC,CAAC;AACL,CAAC;AAED,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAsB;IACpD,OAAO,IAAI,CAAC,wBAAwB,CAAC,gBAAgB,CAAC;QACpD,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,IAAI,EAAU,MAAM,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;QAC1C,SAAS,EAAK,IAAI,CAAC,SAAS;QAC5B,QAAQ,EAAM,IAAI,CAAC,QAAQ;QAC3B,gBAAgB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QACrC,IAAI,EAAU,IAAI,CAAC,MAAM;QACzB,UAAU,EAAE;YACV,IAAI,IAAI,CAAC,yBAAyB,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC;YACzD,IAAI,IAAI,CAAC,kBAAkB,CACzB,IAAI,CAAC,aAAa,CAAC,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC;SACrE;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa;IAC7B,qEAAqE;IACrE,OAAO,KAAK,CAAC,OAAO,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from "./builder.js";
2
+ export * from "./oids.js";
3
+ export * from "./verifier.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/nip/x509/index.ts"],"names":[],"mappings":"AAGA,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,6 @@
1
+ // Copyright 2026 INNO LOTUS PTY LTD
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ export * from "./builder.js";
4
+ export * from "./oids.js";
5
+ export * from "./verifier.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/nip/x509/index.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,sCAAsC;AAEtC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * OID constants for NPS X.509 certificates per NPS-RFC-0002 §4.
3
+ *
4
+ * The 1.3.6.1.4.1.99999 arc is provisional pending IANA Private Enterprise
5
+ * Number assignment (RFC-0002 §10 OQ-2). All implementations MUST update
6
+ * these constants when the official PEN is granted.
7
+ */
8
+ export declare const LAB_ACACIA_PEN_ARC = "1.3.6.1.4.1.99999";
9
+ export declare const EKU_ARC = "1.3.6.1.4.1.99999.1";
10
+ export declare const EXTENSION_ARC = "1.3.6.1.4.1.99999.2";
11
+ export declare const EKU_AGENT_IDENTITY = "1.3.6.1.4.1.99999.1.1";
12
+ export declare const EKU_NODE_IDENTITY = "1.3.6.1.4.1.99999.1.2";
13
+ export declare const EKU_CA_INTERMEDIATE_AGENT = "1.3.6.1.4.1.99999.1.3";
14
+ export declare const NID_ASSURANCE_LEVEL = "1.3.6.1.4.1.99999.2.1";
15
+ export declare const ED25519 = "1.3.101.112";
16
+ export declare const OID_EXTENDED_KEY_USAGE = "2.5.29.37";
17
+ //# sourceMappingURL=oids.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oids.d.ts","sourceRoot":"","sources":["../../../src/nip/x509/oids.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AAEH,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AACtD,eAAO,MAAM,OAAO,wBAAuC,CAAC;AAC5D,eAAO,MAAM,aAAa,wBAAiC,CAAC;AAG5D,eAAO,MAAM,kBAAkB,0BAAwB,CAAC;AACxD,eAAO,MAAM,iBAAiB,0BAAyB,CAAC;AACxD,eAAO,MAAM,yBAAyB,0BAAiB,CAAC;AAGxD,eAAO,MAAM,mBAAmB,0BAAuB,CAAC;AAGxD,eAAO,MAAM,OAAO,gBAAgB,CAAC;AAGrC,eAAO,MAAM,sBAAsB,cAAc,CAAC"}
@@ -0,0 +1,23 @@
1
+ // Copyright 2026 INNO LOTUS PTY LTD
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * OID constants for NPS X.509 certificates per NPS-RFC-0002 §4.
5
+ *
6
+ * The 1.3.6.1.4.1.99999 arc is provisional pending IANA Private Enterprise
7
+ * Number assignment (RFC-0002 §10 OQ-2). All implementations MUST update
8
+ * these constants when the official PEN is granted.
9
+ */
10
+ export const LAB_ACACIA_PEN_ARC = "1.3.6.1.4.1.99999";
11
+ export const EKU_ARC = `${LAB_ACACIA_PEN_ARC}.1`;
12
+ export const EXTENSION_ARC = `${LAB_ACACIA_PEN_ARC}.2`;
13
+ // ── EKUs (NPS-RFC-0002 §4.1) ─────────────────────────────────────────────────
14
+ export const EKU_AGENT_IDENTITY = `${EKU_ARC}.1`;
15
+ export const EKU_NODE_IDENTITY = `${EKU_ARC}.2`;
16
+ export const EKU_CA_INTERMEDIATE_AGENT = `${EKU_ARC}.3`;
17
+ // ── Custom extensions ────────────────────────────────────────────────────────
18
+ export const NID_ASSURANCE_LEVEL = `${EXTENSION_ARC}.1`;
19
+ // ── Ed25519 algorithm OID per RFC 8410 ───────────────────────────────────────
20
+ export const ED25519 = "1.3.101.112";
21
+ // ── Standard X.509 OIDs we reference ─────────────────────────────────────────
22
+ export const OID_EXTENDED_KEY_USAGE = "2.5.29.37";
23
+ //# sourceMappingURL=oids.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oids.js","sourceRoot":"","sources":["../../../src/nip/x509/oids.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,sCAAsC;AAEtC;;;;;;GAMG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AACtD,MAAM,CAAC,MAAM,OAAO,GAAc,GAAG,kBAAkB,IAAI,CAAC;AAC5D,MAAM,CAAC,MAAM,aAAa,GAAQ,GAAG,kBAAkB,IAAI,CAAC;AAE5D,gFAAgF;AAChF,MAAM,CAAC,MAAM,kBAAkB,GAAU,GAAG,OAAO,IAAI,CAAC;AACxD,MAAM,CAAC,MAAM,iBAAiB,GAAW,GAAG,OAAO,IAAI,CAAC;AACxD,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,OAAO,IAAI,CAAC;AAExD,gFAAgF;AAChF,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,aAAa,IAAI,CAAC;AAExD,gFAAgF;AAChF,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC;AAErC,gFAAgF;AAChF,MAAM,CAAC,MAAM,sBAAsB,GAAG,WAAW,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Verifies NPS X.509 NID certificate chains per NPS-RFC-0002 §4.
3
+ *
4
+ * Stages (RFC §4.6):
5
+ * 1. Decode chain (base64url DER → @peculiar/x509 X509Certificate).
6
+ * 2. Leaf EKU check — critical, contains agent-identity OR node-identity OID.
7
+ * 3. Subject CN / SAN URI match against asserted NID.
8
+ * 4. Assurance-level extension match against asserted level (if both present).
9
+ * 5. Chain signature verification — leaf → intermediates → trusted root.
10
+ */
11
+ import * as x509 from "@peculiar/x509";
12
+ import { AssuranceLevel } from "../assurance-level.js";
13
+ export interface NipX509VerifyResult {
14
+ valid: boolean;
15
+ errorCode?: string;
16
+ message?: string;
17
+ leaf?: x509.X509Certificate;
18
+ }
19
+ export interface VerifyOptions {
20
+ certChainBase64UrlDer: readonly string[];
21
+ assertedNid: string;
22
+ assertedAssuranceLevel: AssuranceLevel | null;
23
+ trustedRootCerts: readonly x509.X509Certificate[];
24
+ }
25
+ export declare function verify(opts: VerifyOptions): Promise<NipX509VerifyResult>;
26
+ //# sourceMappingURL=verifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../../../src/nip/x509/verifier.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAWvD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAQ,OAAO,CAAC;IACrB,SAAS,CAAC,EAAG,MAAM,CAAC;IACpB,OAAO,CAAC,EAAK,MAAM,CAAC;IACpB,IAAI,CAAC,EAAQ,IAAI,CAAC,eAAe,CAAC;CACnC;AAUD,MAAM,WAAW,aAAa;IAC5B,qBAAqB,EAAK,SAAS,MAAM,EAAE,CAAC;IAC5C,WAAW,EAAe,MAAM,CAAC;IACjC,sBAAsB,EAAI,cAAc,GAAG,IAAI,CAAC;IAChD,gBAAgB,EAAU,SAAS,IAAI,CAAC,eAAe,EAAE,CAAC;CAC3D;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA+B9E"}
@@ -0,0 +1,171 @@
1
+ // Copyright 2026 INNO LOTUS PTY LTD
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Verifies NPS X.509 NID certificate chains per NPS-RFC-0002 §4.
5
+ *
6
+ * Stages (RFC §4.6):
7
+ * 1. Decode chain (base64url DER → @peculiar/x509 X509Certificate).
8
+ * 2. Leaf EKU check — critical, contains agent-identity OR node-identity OID.
9
+ * 3. Subject CN / SAN URI match against asserted NID.
10
+ * 4. Assurance-level extension match against asserted level (if both present).
11
+ * 5. Chain signature verification — leaf → intermediates → trusted root.
12
+ */
13
+ import * as x509 from "@peculiar/x509";
14
+ import { AssuranceLevel } from "../assurance-level.js";
15
+ import * as ec from "../error-codes.js";
16
+ import { EKU_AGENT_IDENTITY, EKU_NODE_IDENTITY, NID_ASSURANCE_LEVEL, OID_EXTENDED_KEY_USAGE, } from "./oids.js";
17
+ x509.cryptoProvider.set(globalThis.crypto);
18
+ function ok(leaf) {
19
+ return { valid: true, leaf };
20
+ }
21
+ function fail(errorCode, message) {
22
+ return { valid: false, errorCode, message };
23
+ }
24
+ export async function verify(opts) {
25
+ // Stage 1: decode chain ─────────────────────────────────────────────────
26
+ if (!opts.certChainBase64UrlDer.length) {
27
+ return fail(ec.CERT_FORMAT_INVALID, "cert_chain is empty");
28
+ }
29
+ let chain;
30
+ try {
31
+ chain = opts.certChainBase64UrlDer.map((s) => new x509.X509Certificate(b64uDecode(s).buffer));
32
+ }
33
+ catch (e) {
34
+ return fail(ec.CERT_FORMAT_INVALID, `DER decode failed: ${e.message}`);
35
+ }
36
+ const leaf = chain[0];
37
+ // Stage 2: EKU check ────────────────────────────────────────────────────
38
+ const ekuResult = checkLeafEku(leaf);
39
+ if (!ekuResult.valid)
40
+ return ekuResult;
41
+ // Stage 3: subject CN / SAN URI match ──────────────────────────────────
42
+ const subjectResult = checkSubjectNid(leaf, opts.assertedNid);
43
+ if (!subjectResult.valid)
44
+ return subjectResult;
45
+ // Stage 4: assurance-level extension ───────────────────────────────────
46
+ const assuranceResult = checkAssuranceLevel(leaf, opts.assertedAssuranceLevel);
47
+ if (!assuranceResult.valid)
48
+ return assuranceResult;
49
+ // Stage 5: chain signature verification ────────────────────────────────
50
+ const chainResult = await checkChainSignature(chain, opts.trustedRootCerts);
51
+ if (!chainResult.valid)
52
+ return chainResult;
53
+ return ok(leaf);
54
+ }
55
+ // ── Stage helpers ──────────────────────────────────────────────────────────
56
+ function checkLeafEku(leaf) {
57
+ const ekuExt = leaf.extensions.find((e) => e.type === OID_EXTENDED_KEY_USAGE);
58
+ if (!ekuExt) {
59
+ return fail(ec.CERT_EKU_MISSING, "leaf has no ExtendedKeyUsage extension");
60
+ }
61
+ if (!ekuExt.critical) {
62
+ return fail(ec.CERT_EKU_MISSING, "ExtendedKeyUsage extension is not marked critical");
63
+ }
64
+ const usages = ekuExt.usages;
65
+ if (!usages.includes(EKU_AGENT_IDENTITY) && !usages.includes(EKU_NODE_IDENTITY)) {
66
+ return fail(ec.CERT_EKU_MISSING, "ExtendedKeyUsage does not contain agent-identity or node-identity OID");
67
+ }
68
+ return ok(leaf);
69
+ }
70
+ function checkSubjectNid(leaf, assertedNid) {
71
+ // @peculiar/x509 parses the subject DN; iterate to find CN.
72
+ const cn = extractCn(leaf.subject);
73
+ if (cn !== assertedNid) {
74
+ return fail(ec.CERT_SUBJECT_NID_MISMATCH, `leaf subject CN (${cn ?? "<missing>"}) does not match asserted NID (${assertedNid})`);
75
+ }
76
+ const sanExt = leaf.getExtension(x509.SubjectAlternativeNameExtension);
77
+ if (!sanExt) {
78
+ return fail(ec.CERT_SUBJECT_NID_MISMATCH, "leaf has no Subject Alternative Name extension");
79
+ }
80
+ // SubjectAlternativeNameExtension exposes general-name objects with `type: "url"` for URIs.
81
+ const uris = sanExt.names
82
+ .toJSON()
83
+ .filter((n) => n.type === "url")
84
+ .map((n) => n.value);
85
+ if (!uris.includes(assertedNid)) {
86
+ return fail(ec.CERT_SUBJECT_NID_MISMATCH, "no SAN URI matches asserted NID");
87
+ }
88
+ return ok(leaf);
89
+ }
90
+ function checkAssuranceLevel(leaf, asserted) {
91
+ if (asserted === null)
92
+ return ok(leaf);
93
+ const ext = leaf.extensions.find((e) => e.type === NID_ASSURANCE_LEVEL);
94
+ if (!ext) {
95
+ // Optional in v0.1 — pass silently.
96
+ return ok(leaf);
97
+ }
98
+ const der = new Uint8Array(ext.value);
99
+ // Decode ASN.1 ENUMERATED: tag=0x0A, len=0x01, content=<rank>.
100
+ if (der.length !== 3 || der[0] !== 0x0A || der[1] !== 0x01) {
101
+ return fail(ec.CERT_FORMAT_INVALID, `malformed assurance-level extension: ${Buffer.from(der).toString("hex")}`);
102
+ }
103
+ const rank = der[2];
104
+ let certLevel;
105
+ try {
106
+ certLevel = AssuranceLevel.fromRank(rank);
107
+ }
108
+ catch {
109
+ return fail(ec.ASSURANCE_UNKNOWN, `assurance-level extension contains unknown value: ${rank}`);
110
+ }
111
+ if (certLevel !== asserted) {
112
+ return fail(ec.ASSURANCE_MISMATCH, `cert assurance-level (${certLevel.wire}) does not match asserted (${asserted.wire})`);
113
+ }
114
+ return ok(leaf);
115
+ }
116
+ async function checkChainSignature(chain, trustedRoots) {
117
+ if (!trustedRoots.length) {
118
+ return fail(ec.CERT_FORMAT_INVALID, "no trusted X.509 roots configured");
119
+ }
120
+ try {
121
+ // Walk leaf → intermediates: each must be signed by its successor.
122
+ for (let i = 0; i < chain.length - 1; i++) {
123
+ const okStep = await chain[i].verify({ publicKey: await chain[i + 1].publicKey.export(), signatureOnly: true });
124
+ if (!okStep) {
125
+ return fail(ec.CERT_FORMAT_INVALID, `chain link ${i} signature did not verify`);
126
+ }
127
+ }
128
+ // The last cert in the chain MUST chain to a trusted root.
129
+ const last = chain[chain.length - 1];
130
+ for (const root of trustedRoots) {
131
+ if (Buffer.from(last.rawData).equals(Buffer.from(root.rawData))) {
132
+ return ok(chain[0]);
133
+ }
134
+ try {
135
+ const okStep = await last.verify({ publicKey: await root.publicKey.export(), signatureOnly: true });
136
+ if (okStep)
137
+ return ok(chain[0]);
138
+ }
139
+ catch {
140
+ /* try next root */
141
+ }
142
+ }
143
+ return fail(ec.CERT_FORMAT_INVALID, "chain does not anchor to any trusted root");
144
+ }
145
+ catch (e) {
146
+ return fail(ec.CERT_FORMAT_INVALID, `chain signature verification error: ${e.message}`);
147
+ }
148
+ }
149
+ // ── helpers ────────────────────────────────────────────────────────────────
150
+ function extractCn(dn) {
151
+ // @peculiar/x509 returns DN strings in RFC 4514 format ("CN=...,O=...").
152
+ for (const rdn of dn.split(",")) {
153
+ const trimmed = rdn.trim();
154
+ if (trimmed.startsWith("CN=")) {
155
+ let value = trimmed.slice(3);
156
+ // Strip surrounding quotes if any.
157
+ if (value.startsWith("\"") && value.endsWith("\"")) {
158
+ value = value.slice(1, -1);
159
+ }
160
+ // Unescape.
161
+ return value.replace(/\\([",+;<>\\])/g, "$1");
162
+ }
163
+ }
164
+ return null;
165
+ }
166
+ function b64uDecode(s) {
167
+ const padded = s + "=".repeat((4 - (s.length % 4)) % 4);
168
+ const std = padded.replace(/-/g, "+").replace(/_/g, "/");
169
+ return new Uint8Array(Buffer.from(std, "base64"));
170
+ }
171
+ //# sourceMappingURL=verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier.js","sourceRoot":"","sources":["../../../src/nip/x509/verifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ // Copyright 2026 INNO LOTUS PTY LTD
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { NpsFrameCodec } from "../core/codec.js";
4
+ import { EncodingTier } from "../core/frames.js";
5
+ import { FrameRegistry } from "../core/registry.js";
6
+ import { registerNcpFrames } from "../ncp/registry.js";
7
+ import { registerNopFrames } from "./registry.js";
8
+ import { TaskState } from "./models.js";
9
+ const TERMINAL_STATES = new Set([
10
+ TaskState.COMPLETED,
11
+ TaskState.FAILED,
12
+ TaskState.CANCELLED,
13
+ ]);
14
+ export class NopTaskStatus {
15
+ _raw;
16
+ constructor(_raw) {
17
+ this._raw = _raw;
18
+ }
19
+ get taskId() { return this._raw["task_id"]; }
20
+ get state() { return this._raw["state"]; }
21
+ get isTerminal() { return TERMINAL_STATES.has(this._raw["state"]); }
22
+ get aggregatedResult() { return this._raw["aggregated_result"]; }
23
+ get errorCode() { return this._raw["error_code"] ?? undefined; }
24
+ get errorMessage() { return this._raw["error_message"] ?? undefined; }
25
+ get nodeResults() { return this._raw["node_results"] ?? {}; }
26
+ get raw() { return this._raw; }
27
+ toString() {
28
+ return `NopTaskStatus(taskId=${this.taskId}, state=${String(this._raw["state"])})`;
29
+ }
30
+ }
31
+ export class NopClient {
32
+ _baseUrl;
33
+ _codec;
34
+ _tier;
35
+ constructor(baseUrl, options = {}) {
36
+ this._baseUrl = baseUrl.replace(/\/$/, "");
37
+ this._tier = options.defaultTier ?? EncodingTier.MSGPACK;
38
+ const registry = options.registry ?? (() => {
39
+ const r = new FrameRegistry();
40
+ registerNcpFrames(r);
41
+ registerNopFrames(r);
42
+ return r;
43
+ })();
44
+ this._codec = new NpsFrameCodec(registry);
45
+ }
46
+ async submit(frame) {
47
+ const wire = this._codec.encode(frame, { overrideTier: this._tier });
48
+ const res = await fetch(`${this._baseUrl}/task`, {
49
+ method: "POST",
50
+ body: wire,
51
+ headers: { "Content-Type": "application/x-nps-frame", "Accept": "application/json" },
52
+ });
53
+ if (!res.ok)
54
+ throw new Error(`NOP /task failed: HTTP ${res.status}`);
55
+ const data = await res.json();
56
+ return data["task_id"];
57
+ }
58
+ async getStatus(taskId) {
59
+ const res = await fetch(`${this._baseUrl}/task/${taskId}`, {
60
+ headers: { "Accept": "application/json" },
61
+ });
62
+ if (!res.ok)
63
+ throw new Error(`NOP /task/${taskId} failed: HTTP ${res.status}`);
64
+ return new NopTaskStatus(await res.json());
65
+ }
66
+ async cancel(taskId) {
67
+ const res = await fetch(`${this._baseUrl}/task/${taskId}/cancel`, {
68
+ method: "POST",
69
+ headers: { "Accept": "application/json" },
70
+ });
71
+ if (!res.ok)
72
+ throw new Error(`NOP /task/${taskId}/cancel failed: HTTP ${res.status}`);
73
+ }
74
+ async wait(taskId, options = {}) {
75
+ const pollIntervalMs = options.pollIntervalMs ?? 1000;
76
+ const timeoutMs = options.timeoutMs ?? 30_000;
77
+ const deadline = Date.now() + timeoutMs;
78
+ while (true) {
79
+ const status = await this.getStatus(taskId);
80
+ if (status.isTerminal)
81
+ return status;
82
+ const remaining = deadline - Date.now();
83
+ if (remaining <= 0) {
84
+ throw new Error(`Task '${taskId}' did not complete within ${timeoutMs}ms (state: ${String(status.raw["state"])}).`);
85
+ }
86
+ await new Promise((resolve) => setTimeout(resolve, Math.min(pollIntervalMs, remaining)));
87
+ }
88
+ }
89
+ }
90
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/nop/client.ts"],"names":[],"mappings":"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"}