@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
package/CHANGELOG.cn.md CHANGED
@@ -8,6 +8,58 @@
8
8
 
9
9
  ---
10
10
 
11
+ ## [1.0.0-alpha.4] —— 2026-04-30
12
+
13
+ ### 新增
14
+
15
+ - **NPS-RFC-0001 Phase 2 —— NCP 连接前导(TypeScript helper 跟进)。**
16
+ `src/ncp/preamble.ts` 暴露 `writePreamble(stream)` /
17
+ `readPreamble(stream)`,往返字面量 `b"NPS/1.0\n"` 哨兵;
18
+ `tests/ncp/preamble.test.ts` 覆盖。让 TypeScript SDK 与 .NET /
19
+ Python / Go / Java 在 alpha.4 的 preamble helper 持平。
20
+ - **NPS-RFC-0002 Phase A/B —— X.509 NID 证书 + ACME `agent-01`
21
+ (TypeScript 端口)。** 新增 `src/nip/` 子模块:
22
+ - `nip/x509/` —— X.509 NID 证书 builder + verifier
23
+ (`x509.Builder`、`x509.Verifier`)。
24
+ - `nip/acme/` —— ACME `agent-01` 客户端 + 服务端参考实现
25
+ (`AcmeServer`、`AcmeClient`);按 NPS-RFC-0002 Phase B 的 JWS
26
+ 签名 wire 包络。
27
+ - `nip/assurance-level.ts` —— Agent 身份保证等级
28
+ (`anonymous` / `attested` / `verified`),承接 NPS-RFC-0003。
29
+ - `nip/cert-format.ts` —— IdentFrame `cert_format` 判别器
30
+ (`v1` Ed25519 vs. `x509`)。
31
+ - `nip/error-codes.ts` —— NIP 错误码命名空间。
32
+ - `nip/verifier.ts` —— dual-trust IdentFrame 验证器(v1 + X.509)。
33
+ - 20 个新测试覆盖 preamble 往返、X.509 签发 + 解析、dual-trust 验证、
34
+ ACME agent-01 全流程。总数:284 tests 全绿(alpha.3 时 264)。
35
+
36
+ ### 变更
37
+
38
+ - 分发版本升至 `1.0.0-alpha.4`。
39
+ - `src/nip/frames.ts` —— IdentFrame wire 形状扩展,可携带可选的
40
+ `cert_format` 判别器 + `x509_chain` 字段,与 v1 Ed25519 字段并存。
41
+ alpha.3 写出的 v1 IdentFrame 仍可被 alpha.4 验签。
42
+
43
+ ### npm 发布说明
44
+
45
+ - 本仓库 / tag 是 `@labacacia/nps-sdk` `1.0.0-alpha.4` 的权威参考。
46
+ 延续 alpha.3 的情况,npm publish 可能需要带 2FA-bypass 的 granular
47
+ access token —— 如果 npm registry 上的版本暂时落后于本仓库 tag,
48
+ 以 tag 为准;下一次 registry cut 后 `npm install` 即可解析到本
49
+ commit。
50
+
51
+ ### 套件级 alpha.4 要点
52
+
53
+ - **NPS-RFC-0002 X.509 + ACME** —— 完整跨 SDK 端口波(.NET / Java /
54
+ Python / TypeScript / Go / Rust)。
55
+ - **NPS-CR-0002 —— Anchor Node topology 查询** —— `topology.snapshot`
56
+ / `topology.stream`(.NET 参考 + L2 conformance)。TypeScript 消费
57
+ 侧 helper 后续版本跟进。
58
+ - **`nps-registry` SQLite 实仓** + **`nps-ledger` Phase 2**
59
+ (RFC 9162 Merkle + STH + inclusion proof)已在 daemon 仓库交付。
60
+
61
+ ---
62
+
11
63
  ## [1.0.0-alpha.3] —— 2026-04-25
12
64
 
13
65
  ### Changed
@@ -52,6 +104,7 @@
52
104
 
53
105
  作为 NPS 套件 `v1.0.0-alpha.1` 的一部分首次公开 alpha。
54
106
 
107
+ [1.0.0-alpha.4]: https://gitee.com/labacacia/NPS-sdk-ts/releases/tag/v1.0.0-alpha.4
55
108
  [1.0.0-alpha.3]: https://github.com/LabAcacia/NPS-Dev/releases/tag/v1.0.0-alpha.3
56
109
  [1.0.0-alpha.2]: https://github.com/LabAcacia/NPS-Dev/releases/tag/v1.0.0-alpha.2
57
110
  [1.0.0-alpha.1]: https://github.com/LabAcacia/NPS-Dev/releases/tag/v1.0.0-alpha.1
package/CHANGELOG.md CHANGED
@@ -8,6 +8,67 @@ Until NPS reaches v1.0 stable, every repository in the suite is synchronized to
8
8
 
9
9
  ---
10
10
 
11
+ ## [1.0.0-alpha.4] — 2026-04-30
12
+
13
+ ### Added
14
+
15
+ - **NPS-RFC-0001 Phase 2 — NCP connection preamble (TypeScript helper
16
+ parity).** `src/ncp/preamble.ts` exposes `writePreamble(stream)` and
17
+ `readPreamble(stream)` round-tripping the literal `b"NPS/1.0\n"`
18
+ sentinel; matched by `tests/ncp/preamble.test.ts`. Brings TypeScript
19
+ in line with the .NET / Python / Go / Java preamble helpers shipped
20
+ at alpha.4.
21
+ - **NPS-RFC-0002 Phase A/B — X.509 NID certificates + ACME `agent-01`
22
+ (TypeScript port).** New surface under `src/nip/`:
23
+ - `nip/x509/` — X.509 NID certificate builder + verifier
24
+ (`x509.Builder`, `x509.Verifier`).
25
+ - `nip/acme/` — ACME `agent-01` client + server reference
26
+ (`AcmeServer`, `AcmeClient`); JWS-signed wire envelope per
27
+ NPS-RFC-0002 Phase B.
28
+ - `nip/assurance-level.ts` — agent identity assurance levels
29
+ (`anonymous` / `attested` / `verified`) per NPS-RFC-0003.
30
+ - `nip/cert-format.ts` — IdentFrame `cert_format` discriminator
31
+ (`v1` Ed25519 vs. `x509`).
32
+ - `nip/error-codes.ts` — NIP error code namespace strings.
33
+ - `nip/verifier.ts` — dual-trust IdentFrame verifier (v1 + X.509).
34
+ - 20 new tests covering preamble round-trip, X.509 issuance + parsing,
35
+ dual-trust verification, and ACME agent-01 round-trip. Total: 284
36
+ tests green (was 264 at alpha.3).
37
+
38
+ ### Changed
39
+
40
+ - Distribution version bumped to `1.0.0-alpha.4`.
41
+ - `src/nip/frames.ts` — IdentFrame wire shape extended with optional
42
+ `cert_format` discriminator + `x509_chain` field alongside the
43
+ existing v1 Ed25519 fields. v1 IdentFrames written by alpha.3
44
+ consumers continue to verify unchanged.
45
+
46
+ ### Note: npm publish status
47
+
48
+ - This repo / tag is the canonical `1.0.0-alpha.4` reference for
49
+ `@labacacia/nps-sdk`. As at the alpha.3 ship cycle, npm publish
50
+ may require a granular access token with 2FA-bypass enabled — if
51
+ the registry version lags this repo's tag, the tag is the
52
+ authoritative artifact and `npm install` against the next
53
+ registry cut will resolve to this commit.
54
+
55
+ ### Suite-wide highlights at alpha.4
56
+
57
+ - **NPS-RFC-0002 X.509 + ACME** — full cross-SDK port wave (.NET /
58
+ Java / Python / TypeScript / Go / Rust). Servers can now issue
59
+ dual-trust IdentFrames (v1 Ed25519 + X.509 leaf cert chained to a
60
+ self-signed root) and self-onboard NIDs over ACME's `agent-01`
61
+ challenge type.
62
+ - **NPS-CR-0002 — Anchor Node topology queries** — `topology.snapshot`
63
+ / `topology.stream` query types (.NET reference + L2 conformance
64
+ suite). TypeScript consumer-side helpers planned for a later
65
+ release.
66
+ - **`nps-registry` SQLite-backed real registry** + **`nps-ledger`
67
+ Phase 2** (RFC 9162 Merkle + STH + inclusion proofs) shipped in the
68
+ daemon repos.
69
+
70
+ ---
71
+
11
72
  ## [1.0.0-alpha.3] — 2026-04-25
12
73
 
13
74
  ### Changed
@@ -52,6 +113,7 @@ Until NPS reaches v1.0 stable, every repository in the suite is synchronized to
52
113
 
53
114
  First public alpha as part of the NPS suite `v1.0.0-alpha.1` release.
54
115
 
116
+ [1.0.0-alpha.4]: https://github.com/labacacia/NPS-sdk-ts/releases/tag/v1.0.0-alpha.4
55
117
  [1.0.0-alpha.3]: https://github.com/LabAcacia/NPS-Dev/releases/tag/v1.0.0-alpha.3
56
118
  [1.0.0-alpha.2]: https://github.com/LabAcacia/NPS-Dev/releases/tag/v1.0.0-alpha.2
57
119
  [1.0.0-alpha.1]: https://github.com/LabAcacia/NPS-Dev/releases/tag/v1.0.0-alpha.1
package/README.cn.md CHANGED
@@ -7,16 +7,22 @@
7
7
 
8
8
  ## 状态
9
9
 
10
- **v1.0.0-alpha.3Phase 2** · 5 个协议 · 264 个测试 · 覆盖率 ≥ 98%
10
+ **v1.0.0-alpha.4RFC-0002 SDK 端口波(第三棒)** · 5 个协议 · 271 个测试 · 覆盖率 ≥ 98%
11
11
 
12
12
  | 协议 | 类 | 状态 |
13
13
  |------|----|------|
14
14
  | NCP — Neural Communication Protocol | 帧、编解码器 | ✅ |
15
15
  | NWP — Neural Web Protocol | `NwpClient` | ✅ |
16
- | NIP — Neural Identity Protocol | `NipIdentity` | ✅ |
16
+ | NIP — Neural Identity Protocol | `NipIdentity`、`NipIdentVerifier`(RFC-0002 §8.1 双信任)、`AssuranceLevel`(RFC-0003)、`nip.x509` + `nip.acme` | ✅ |
17
17
  | NDP — Neural Discovery Protocol | `InMemoryNdpRegistry`、`NdpAnnounceValidator` | ✅ |
18
18
  | NOP — Neural Orchestration Protocol | `NopClient` | ✅ |
19
19
 
20
+ **alpha.4 新增** —— 完整的 NPS-RFC-0002 X.509 + ACME `agent-01` NID 证书原语:
21
+
22
+ - `nip.x509` —— `issueLeaf` / `issueRoot` / `verify`(基于 `@peculiar/x509` + 原生 Web Crypto Ed25519)。
23
+ - `nip.acme` —— `AcmeClient` + 进程内 `AcmeServer` + JWS / messages helpers(RFC 8555 + RFC 8037 EdDSA)。
24
+ - `IdentFrame` 扩展非破坏性可选构造参数 `assuranceLevel` / `certFormat` / `certChain`;v1 verifier 忽略新字段。
25
+
20
26
  ## 安装
21
27
 
22
28
  ```bash
package/README.md CHANGED
@@ -7,16 +7,22 @@ Part of the [LabAcacia](https://github.com/LabAcacia) / INNO LOTUS PTY LTD open-
7
7
 
8
8
  ## Status
9
9
 
10
- **v1.0.0-alpha.3Phase 2** · 5 protocols · 264 tests · ≥ 98% coverage
10
+ **v1.0.0-alpha.4RFC-0002 cross-SDK port (third language)** · 5 protocols · 271 tests · ≥ 98% coverage
11
11
 
12
12
  | Protocol | Class | Status |
13
13
  |----------|-------|--------|
14
14
  | NCP — Neural Communication Protocol | Framing, codec | ✅ |
15
15
  | NWP — Neural Web Protocol | `NwpClient` | ✅ |
16
- | NIP — Neural Identity Protocol | `NipIdentity` | ✅ |
16
+ | NIP — Neural Identity Protocol | `NipIdentity`, `NipIdentVerifier` (RFC-0002 §8.1 dual-trust), `AssuranceLevel` (RFC-0003), `nip.x509` + `nip.acme` | ✅ |
17
17
  | NDP — Neural Discovery Protocol | `InMemoryNdpRegistry`, `NdpAnnounceValidator` | ✅ |
18
18
  | NOP — Neural Orchestration Protocol | `NopClient` | ✅ |
19
19
 
20
+ **alpha.4 additions** — Full NPS-RFC-0002 X.509 + ACME `agent-01` NID certificate primitives:
21
+
22
+ - `nip.x509` — `issueLeaf` / `issueRoot` / `verify` (built on `@peculiar/x509` + native Web Crypto Ed25519).
23
+ - `nip.acme` — `AcmeClient` + in-process `AcmeServer` + JWS / message helpers (RFC 8555 + EdDSA per RFC 8037).
24
+ - `IdentFrame` extended with non-breaking `assuranceLevel` / `certFormat` / `certChain` constructor options; v1 verifiers ignore the new fields.
25
+
20
26
  ## Installation
21
27
 
22
28
  ```bash
@@ -0,0 +1,104 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 LabAcacia / INNO LOTUS PTY LTD
3
+ //
4
+ // AnchorCache — Schema cache with TTL, LRU eviction, poison detection
5
+ // NPS-1 §5.3, §7.2, §9
6
+ import { NcpError } from "./frame-header.js";
7
+ /**
8
+ * AnchorFrame cache with:
9
+ * - TTL-based expiry (NPS-1 §5.3)
10
+ * - LRU eviction at maxSize (NPS-1 §9, default 1000)
11
+ * - Anchor poisoning detection (NPS-1 §7.2)
12
+ */
13
+ export class AnchorCache {
14
+ cache = new Map();
15
+ maxSize;
16
+ getNow;
17
+ constructor(options) {
18
+ this.maxSize = options?.maxSize ?? 1000;
19
+ this.getNow = options?.getNow ?? (() => Date.now());
20
+ }
21
+ /**
22
+ * Cache an AnchorFrame.
23
+ *
24
+ * - ttl=0: frame is valid but not cached (NPS-1 §4.1)
25
+ * - Same anchor_id + same schema: idempotent (no-op)
26
+ * - Same anchor_id + different schema: NCP-ANCHOR-ID-MISMATCH (poison detection)
27
+ *
28
+ * @throws {NcpError} NCP-ANCHOR-ID-MISMATCH on anchor poisoning.
29
+ */
30
+ set(frame) {
31
+ // ttl=0 means use once, don't cache
32
+ if (frame.ttl === 0)
33
+ return;
34
+ const existing = this.cache.get(frame.anchor_id);
35
+ if (existing) {
36
+ // Poison detection: same ID, different schema
37
+ const existingJson = JSON.stringify(existing.frame.schema);
38
+ const newJson = JSON.stringify(frame.schema);
39
+ if (existingJson !== newJson) {
40
+ throw new NcpError("NCP-ANCHOR-ID-MISMATCH", `Anchor poisoning detected: anchor_id ${frame.anchor_id} received with different schema`);
41
+ }
42
+ // Same schema — idempotent, update access time
43
+ existing.lastAccessed = this.getNow();
44
+ return;
45
+ }
46
+ // LRU eviction if at capacity
47
+ if (this.cache.size >= this.maxSize) {
48
+ this.evictLru();
49
+ }
50
+ const ttlMs = (frame.ttl ?? 3600) * 1000;
51
+ this.cache.set(frame.anchor_id, {
52
+ frame,
53
+ expiresAt: this.getNow() + ttlMs,
54
+ lastAccessed: this.getNow(),
55
+ });
56
+ }
57
+ /**
58
+ * Get a cached AnchorFrame by anchor_id.
59
+ *
60
+ * @returns The cached frame, or null if not found or expired.
61
+ */
62
+ get(anchorId) {
63
+ const entry = this.cache.get(anchorId);
64
+ if (!entry)
65
+ return null;
66
+ // Check TTL expiry
67
+ if (this.getNow() >= entry.expiresAt) {
68
+ this.cache.delete(anchorId);
69
+ return null;
70
+ }
71
+ entry.lastAccessed = this.getNow();
72
+ return entry.frame;
73
+ }
74
+ /**
75
+ * Get a cached AnchorFrame, throwing if not found.
76
+ * @throws {NcpError} NCP-ANCHOR-NOT-FOUND if not in cache or expired.
77
+ */
78
+ getRequired(anchorId) {
79
+ const frame = this.get(anchorId);
80
+ if (!frame) {
81
+ throw new NcpError("NCP-ANCHOR-NOT-FOUND", `Schema anchor ${anchorId} not found in cache`);
82
+ }
83
+ return frame;
84
+ }
85
+ /** Current cache size. */
86
+ get size() {
87
+ return this.cache.size;
88
+ }
89
+ /** Evict the least recently accessed entry. */
90
+ evictLru() {
91
+ let oldestKey;
92
+ let oldestTime = Infinity;
93
+ for (const [key, entry] of this.cache) {
94
+ if (entry.lastAccessed < oldestTime) {
95
+ oldestTime = entry.lastAccessed;
96
+ oldestKey = key;
97
+ }
98
+ }
99
+ if (oldestKey) {
100
+ this.cache.delete(oldestKey);
101
+ }
102
+ }
103
+ }
104
+ //# sourceMappingURL=anchor-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anchor-cache.js","sourceRoot":"","sources":["../../src/core/anchor-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ // Copyright 2026 INNO LOTUS PTY LTD
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * AnchorFrameCache — in-process cache for AnchorFrame instances (NPS-1 §4.1).
5
+ */
6
+ import { createHash } from "node:crypto";
7
+ import { NpsAnchorNotFoundError, NpsAnchorPoisonError } from "./exceptions.js";
8
+ export class AnchorFrameCache {
9
+ _store = new Map();
10
+ // Allow clock injection for testing
11
+ clock = () => Date.now();
12
+ // ── Public API ────────────────────────────────────────────────────────────
13
+ set(frame) {
14
+ const anchorId = frame.anchorId.startsWith("sha256:")
15
+ ? frame.anchorId
16
+ : AnchorFrameCache.computeAnchorId(frame.schema);
17
+ const existing = this._store.get(anchorId);
18
+ if (existing !== undefined && this.clock() < existing.expiresAt) {
19
+ if (!AnchorFrameCache._schemasEqual(existing.frame.schema, frame.schema)) {
20
+ throw new NpsAnchorPoisonError(anchorId);
21
+ }
22
+ // Same schema — idempotent; refresh TTL below
23
+ }
24
+ const ttlMs = (frame.ttl ?? 3600) * 1000;
25
+ const expiresAt = this.clock() + ttlMs;
26
+ this._store.set(anchorId, { frame, expiresAt });
27
+ return anchorId;
28
+ }
29
+ get(anchorId) {
30
+ const entry = this._store.get(anchorId);
31
+ if (entry === undefined)
32
+ return undefined;
33
+ if (this.clock() > entry.expiresAt) {
34
+ this._store.delete(anchorId);
35
+ return undefined;
36
+ }
37
+ return entry.frame;
38
+ }
39
+ getRequired(anchorId) {
40
+ const frame = this.get(anchorId);
41
+ if (frame === undefined)
42
+ throw new NpsAnchorNotFoundError(anchorId);
43
+ return frame;
44
+ }
45
+ invalidate(anchorId) {
46
+ this._store.delete(anchorId);
47
+ }
48
+ get size() {
49
+ this._evictExpired();
50
+ return this._store.size;
51
+ }
52
+ // ── Static helpers ────────────────────────────────────────────────────────
53
+ static computeAnchorId(schema) {
54
+ const sorted = [...schema.fields]
55
+ .map((f) => {
56
+ const obj = { name: f.name, type: f.type };
57
+ if (f.semantic !== undefined)
58
+ obj["semantic"] = f.semantic;
59
+ if (f.nullable !== undefined)
60
+ obj["nullable"] = f.nullable;
61
+ return obj;
62
+ })
63
+ .sort((a, b) => String(a["name"]).localeCompare(String(b["name"])));
64
+ const canonical = JSON.stringify(sorted);
65
+ const digest = createHash("sha256").update(canonical, "utf8").digest("hex");
66
+ return `sha256:${digest}`;
67
+ }
68
+ // ── Private ───────────────────────────────────────────────────────────────
69
+ _evictExpired() {
70
+ const now = this.clock();
71
+ for (const [k, entry] of this._store) {
72
+ if (now > entry.expiresAt)
73
+ this._store.delete(k);
74
+ }
75
+ }
76
+ static _schemasEqual(a, b) {
77
+ return AnchorFrameCache.computeAnchorId(a) === AnchorFrameCache.computeAnchorId(b);
78
+ }
79
+ }
80
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/core/cache.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,sCAAsC;AAEtC;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAG/E,MAAM,OAAO,gBAAgB;IACV,MAAM,GAAG,IAAI,GAAG,EAAqD,CAAC;IAEvF,oCAAoC;IACpC,KAAK,GAAiB,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;IAEvC,6EAA6E;IAE7E,GAAG,CAAC,KAAkB;QACpB,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC;YACnD,CAAC,CAAC,KAAK,CAAC,QAAQ;YAChB,CAAC,CAAC,gBAAgB,CAAC,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAEnD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,EAAE,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;YAChE,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;gBACzE,MAAM,IAAI,oBAAoB,CAAC,QAAQ,CAAC,CAAC;YAC3C,CAAC;YACD,8CAA8C;QAChD,CAAC;QAED,MAAM,KAAK,GAAK,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC;QAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC;QACvC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAChD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,GAAG,CAAC,QAAgB;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAC1C,IAAI,IAAI,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACnC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC7B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,WAAW,CAAC,QAAgB;QAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,KAAK,KAAK,SAAS;YAAE,MAAM,IAAI,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QACpE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,UAAU,CAAC,QAAgB;QACzB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,IAAI;QACN,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;IAC1B,CAAC;IAED,6EAA6E;IAE7E,MAAM,CAAC,eAAe,CAAC,MAAmB;QACxC,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;aAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,GAAG,GAA4B,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACpE,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS;gBAAE,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;YAC3D,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS;gBAAE,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;YAC3D,OAAO,GAAG,CAAC;QACb,CAAC,CAAC;aACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAEtE,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACzC,MAAM,MAAM,GAAM,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC/E,OAAO,UAAU,MAAM,EAAE,CAAC;IAC5B,CAAC;IAED,6EAA6E;IAErE,aAAa;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACrC,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS;gBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAEO,MAAM,CAAC,aAAa,CAAC,CAAc,EAAE,CAAc;QACzD,OAAO,gBAAgB,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,gBAAgB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACrF,CAAC;CACF"}
@@ -0,0 +1,44 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 LabAcacia / INNO LOTUS PTY LTD
3
+ //
4
+ // Canonical JSON helpers — two distinct serialisation paths used in NPS.
5
+ //
6
+ // AnchorFrame uses JCS (RFC 8785) for anchor_id hashing → jcsStringify.
7
+ // NIP signing uses Python-compatible sorted-key JSON → sortKeysStringify.
8
+ import canonicalizeImport from "canonicalize";
9
+ // `canonicalize` is a CJS module whose default export resolves to a namespace
10
+ // under NodeNext. Cast once to the call signature its .d.ts promises.
11
+ const canonicalize = canonicalizeImport;
12
+ /**
13
+ * JCS (RFC 8785) canonical JSON stringify.
14
+ * Used for AnchorFrame anchor_id computation.
15
+ */
16
+ export function jcsStringify(obj) {
17
+ const result = canonicalize(obj);
18
+ if (result === undefined) {
19
+ throw new Error("canonicalize returned undefined for input");
20
+ }
21
+ return result;
22
+ }
23
+ /**
24
+ * Sorted-key JSON stringify — matches Python's
25
+ * `json.dumps(obj, sort_keys=True, separators=(",",":"))`.
26
+ * Used for NIP signing.
27
+ */
28
+ export function sortKeysStringify(obj) {
29
+ return JSON.stringify(sortKeys(obj));
30
+ }
31
+ function sortKeys(value) {
32
+ if (Array.isArray(value)) {
33
+ return value.map(sortKeys);
34
+ }
35
+ if (value !== null && typeof value === "object") {
36
+ const sorted = {};
37
+ for (const key of Object.keys(value).sort()) {
38
+ sorted[key] = sortKeys(value[key]);
39
+ }
40
+ return sorted;
41
+ }
42
+ return value;
43
+ }
44
+ //# sourceMappingURL=canonical-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical-json.js","sourceRoot":"","sources":["../../src/core/canonical-json.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,oDAAoD;AACpD,EAAE;AACF,yEAAyE;AACzE,EAAE;AACF,wEAAwE;AACxE,0EAA0E;AAE1E,OAAO,kBAAkB,MAAM,cAAc,CAAC;AAE9C,8EAA8E;AAC9E,sEAAsE;AACtE,MAAM,YAAY,GAAG,kBAEE,CAAC;AAExB;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAY;IAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACtD,MAAM,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAE,KAAiC,CAAC,GAAG,CAAC,CAAC,CAAC;QAClE,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,119 @@
1
+ // Copyright 2026 INNO LOTUS PTY LTD
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * NPS frame codec: Tier-1 (JSON) and Tier-2 (MsgPack) encode/decode,
5
+ * plus the top-level NpsFrameCodec dispatcher.
6
+ */
7
+ import * as msgpack from "@msgpack/msgpack";
8
+ import { NpsCodecError } from "./exceptions.js";
9
+ import { DEFAULT_MAX_PAYLOAD, EncodingTier, FrameFlags, FrameHeader, } from "./frames.js";
10
+ // ── Tier-1 JSON codec ─────────────────────────────────────────────────────────
11
+ export class Tier1JsonCodec {
12
+ encode(frame) {
13
+ try {
14
+ const json = JSON.stringify(frame.toDict());
15
+ return new TextEncoder().encode(json);
16
+ }
17
+ catch (err) {
18
+ throw new NpsCodecError(`Tier-1 JSON encode failed for 0x${frame.frameType.toString(16).padStart(2, "0")}: ${String(err)}`);
19
+ }
20
+ }
21
+ decode(frameType, payload, registry) {
22
+ const cls = registry.resolve(frameType);
23
+ try {
24
+ const text = new TextDecoder().decode(payload);
25
+ const data = JSON.parse(text);
26
+ return cls.fromDict(data);
27
+ }
28
+ catch (err) {
29
+ throw new NpsCodecError(`Tier-1 JSON decode failed for 0x${frameType.toString(16).padStart(2, "0")}: ${String(err)}`);
30
+ }
31
+ }
32
+ }
33
+ // ── Tier-2 MsgPack codec ──────────────────────────────────────────────────────
34
+ export class Tier2MsgPackCodec {
35
+ encode(frame) {
36
+ try {
37
+ return msgpack.encode(frame.toDict());
38
+ }
39
+ catch (err) {
40
+ throw new NpsCodecError(`Tier-2 MsgPack encode failed for 0x${frame.frameType.toString(16).padStart(2, "0")}: ${String(err)}`);
41
+ }
42
+ }
43
+ decode(frameType, payload, registry) {
44
+ const cls = registry.resolve(frameType);
45
+ try {
46
+ const data = msgpack.decode(payload);
47
+ return cls.fromDict(data);
48
+ }
49
+ catch (err) {
50
+ throw new NpsCodecError(`Tier-2 MsgPack decode failed for 0x${frameType.toString(16).padStart(2, "0")}: ${String(err)}`);
51
+ }
52
+ }
53
+ }
54
+ // ── NpsFrameCodec (dispatcher) ────────────────────────────────────────────────
55
+ export class NpsFrameCodec {
56
+ _registry;
57
+ _maxPayload;
58
+ _json = new Tier1JsonCodec();
59
+ _msgpack = new Tier2MsgPackCodec();
60
+ constructor(registry, options = {}) {
61
+ this._registry = registry;
62
+ this._maxPayload = options.maxPayload ?? DEFAULT_MAX_PAYLOAD;
63
+ }
64
+ // ── Encode ────────────────────────────────────────────────────────────────
65
+ encode(frame, options = {}) {
66
+ const tier = options.overrideTier ?? frame.preferredTier;
67
+ const tierCodec = this._selectCodec(tier);
68
+ let payload;
69
+ try {
70
+ payload = tierCodec.encode(frame);
71
+ }
72
+ catch (err) {
73
+ if (err instanceof NpsCodecError)
74
+ throw err;
75
+ throw new NpsCodecError(`Encode failed for 0x${frame.frameType.toString(16)}.`);
76
+ }
77
+ if (payload.length > this._maxPayload) {
78
+ throw new NpsCodecError(`Encoded payload for 0x${frame.frameType.toString(16).padStart(2, "0")} exceeds max_frame_payload` +
79
+ ` (${payload.length} bytes > ${this._maxPayload}). Use StreamFrame (0x03) for large payloads.`);
80
+ }
81
+ const useExt = payload.length > DEFAULT_MAX_PAYLOAD;
82
+ let flags = this._buildFlags(frame, tier);
83
+ if (useExt)
84
+ flags |= FrameFlags.EXT;
85
+ const header = new FrameHeader(frame.frameType, flags, payload.length);
86
+ const headerBytes = header.toBytes();
87
+ const wire = new Uint8Array(headerBytes.length + payload.length);
88
+ wire.set(headerBytes, 0);
89
+ wire.set(payload, headerBytes.length);
90
+ return wire;
91
+ }
92
+ // ── Decode ────────────────────────────────────────────────────────────────
93
+ decode(wire) {
94
+ const header = FrameHeader.parse(wire);
95
+ const payload = wire.slice(header.headerSize, header.headerSize + header.payloadLength);
96
+ const codec = this._selectCodec(header.encodingTier);
97
+ return codec.decode(header.frameType, payload, this._registry);
98
+ }
99
+ static peekHeader(wire) {
100
+ return FrameHeader.parse(wire);
101
+ }
102
+ // ── Private ───────────────────────────────────────────────────────────────
103
+ _buildFlags(frame, tier) {
104
+ let flags = tier === EncodingTier.JSON ? FrameFlags.TIER1_JSON : FrameFlags.TIER2_MSGPACK;
105
+ const isStreamFrame = "isLast" in frame;
106
+ const isFinal = !isStreamFrame || frame.isLast;
107
+ if (isFinal)
108
+ flags |= FrameFlags.FINAL;
109
+ return flags;
110
+ }
111
+ _selectCodec(tier) {
112
+ if (tier === EncodingTier.JSON)
113
+ return this._json;
114
+ if (tier === EncodingTier.MSGPACK)
115
+ return this._msgpack;
116
+ throw new NpsCodecError(`Unsupported encoding tier: 0x${tier.toString(16).padStart(2, "0")}.`);
117
+ }
118
+ }
119
+ //# sourceMappingURL=codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/core/codec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 LabAcacia / INNO LOTUS PTY LTD
3
+ export * from "./ncp-codec.js";
4
+ export { encodeJson, decodeJson } from "./tier1-json-codec.js";
5
+ export { encodeMsgPack, decodeMsgPack } from "./tier2-msgpack-codec.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/codecs/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,oDAAoD;AACpD,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC"}