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

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 (251) hide show
  1. package/CHANGELOG.cn.md +57 -0
  2. package/CHANGELOG.md +57 -0
  3. package/CONTRIBUTING.cn.md +35 -0
  4. package/CONTRIBUTING.md +2 -0
  5. package/README.cn.md +155 -0
  6. package/README.md +5 -3
  7. package/dist/core/anchor-cache.d.ts +0 -0
  8. package/dist/core/anchor-cache.d.ts.map +0 -0
  9. package/dist/core/cache.d.ts +0 -0
  10. package/dist/core/cache.d.ts.map +0 -0
  11. package/dist/core/canonical-json.d.ts +0 -0
  12. package/dist/core/canonical-json.d.ts.map +0 -0
  13. package/dist/core/codec.d.ts +0 -0
  14. package/dist/core/codec.d.ts.map +0 -0
  15. package/dist/core/codecs/index.d.ts +0 -0
  16. package/dist/core/codecs/index.d.ts.map +0 -0
  17. package/dist/core/codecs/ncp-codec.d.ts +0 -0
  18. package/dist/core/codecs/ncp-codec.d.ts.map +0 -0
  19. package/dist/core/codecs/tier1-json-codec.d.ts +0 -0
  20. package/dist/core/codecs/tier1-json-codec.d.ts.map +0 -0
  21. package/dist/core/codecs/tier2-msgpack-codec.d.ts +0 -0
  22. package/dist/core/codecs/tier2-msgpack-codec.d.ts.map +0 -0
  23. package/dist/core/crypto-provider.d.ts +0 -0
  24. package/dist/core/crypto-provider.d.ts.map +0 -0
  25. package/dist/core/exceptions.d.ts +0 -0
  26. package/dist/core/exceptions.d.ts.map +0 -0
  27. package/dist/core/frame-header.d.ts +0 -0
  28. package/dist/core/frame-header.d.ts.map +0 -0
  29. package/dist/core/frame-registry.d.ts +0 -0
  30. package/dist/core/frame-registry.d.ts.map +0 -0
  31. package/dist/core/frames.d.ts +1 -0
  32. package/dist/core/frames.d.ts.map +1 -1
  33. package/dist/core/index.cjs +90 -9
  34. package/dist/core/index.cjs.map +1 -1
  35. package/dist/core/index.d.ts +6 -4
  36. package/dist/core/index.d.ts.map +1 -1
  37. package/dist/core/index.js +405 -9
  38. package/dist/core/index.js.map +1 -1
  39. package/dist/core/registry.d.ts +0 -0
  40. package/dist/core/registry.d.ts.map +0 -0
  41. package/dist/core/status-codes.d.ts +0 -0
  42. package/dist/core/status-codes.d.ts.map +0 -0
  43. package/dist/index.cjs +3 -1551
  44. package/dist/index.cjs.map +1 -1
  45. package/dist/index.d.ts +1 -1
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +5 -9
  48. package/dist/index.js.map +1 -1
  49. package/dist/ncp/frames/anchor-frame.d.ts +0 -0
  50. package/dist/ncp/frames/anchor-frame.d.ts.map +0 -0
  51. package/dist/ncp/frames/caps-frame.d.ts +0 -0
  52. package/dist/ncp/frames/caps-frame.d.ts.map +0 -0
  53. package/dist/ncp/frames/diff-frame.d.ts +0 -0
  54. package/dist/ncp/frames/diff-frame.d.ts.map +0 -0
  55. package/dist/ncp/frames/error-frame.d.ts +0 -0
  56. package/dist/ncp/frames/error-frame.d.ts.map +0 -0
  57. package/dist/ncp/frames/hello-frame.d.ts +0 -0
  58. package/dist/ncp/frames/hello-frame.d.ts.map +0 -0
  59. package/dist/ncp/frames/stream-frame.d.ts +0 -0
  60. package/dist/ncp/frames/stream-frame.d.ts.map +0 -0
  61. package/dist/ncp/frames.d.ts +18 -0
  62. package/dist/ncp/frames.d.ts.map +1 -1
  63. package/dist/ncp/handshake.d.ts +0 -0
  64. package/dist/ncp/handshake.d.ts.map +0 -0
  65. package/dist/ncp/index.cjs +364 -164
  66. package/dist/ncp/index.cjs.map +1 -1
  67. package/dist/ncp/index.d.ts +0 -0
  68. package/dist/ncp/index.d.ts.map +0 -0
  69. package/dist/ncp/index.js +368 -12
  70. package/dist/ncp/index.js.map +1 -1
  71. package/dist/ncp/ncp-error-codes.d.ts +0 -0
  72. package/dist/ncp/ncp-error-codes.d.ts.map +0 -0
  73. package/dist/ncp/ncp-patch-format.d.ts +0 -0
  74. package/dist/ncp/ncp-patch-format.d.ts.map +0 -0
  75. package/dist/ncp/registry.d.ts +0 -0
  76. package/dist/ncp/registry.d.ts.map +1 -1
  77. package/dist/ncp/stream-manager.d.ts +0 -0
  78. package/dist/ncp/stream-manager.d.ts.map +0 -0
  79. package/dist/ndp/frames.d.ts +0 -0
  80. package/dist/ndp/frames.d.ts.map +0 -0
  81. package/dist/ndp/index.cjs +0 -0
  82. package/dist/ndp/index.cjs.map +0 -0
  83. package/dist/ndp/index.d.ts +0 -0
  84. package/dist/ndp/index.d.ts.map +0 -0
  85. package/dist/ndp/index.js +223 -6
  86. package/dist/ndp/index.js.map +1 -1
  87. package/dist/ndp/ndp-registry.d.ts +0 -0
  88. package/dist/ndp/ndp-registry.d.ts.map +0 -0
  89. package/dist/ndp/registry.d.ts +0 -0
  90. package/dist/ndp/registry.d.ts.map +0 -0
  91. package/dist/ndp/validator.d.ts +0 -0
  92. package/dist/ndp/validator.d.ts.map +0 -0
  93. package/dist/nip/frames.d.ts +0 -0
  94. package/dist/nip/frames.d.ts.map +0 -0
  95. package/dist/nip/identity.d.ts +0 -0
  96. package/dist/nip/identity.d.ts.map +0 -0
  97. package/dist/nip/index.cjs +0 -0
  98. package/dist/nip/index.cjs.map +0 -0
  99. package/dist/nip/index.d.ts +0 -0
  100. package/dist/nip/index.d.ts.map +0 -0
  101. package/dist/nip/index.js +187 -5
  102. package/dist/nip/index.js.map +1 -1
  103. package/dist/nip/registry.d.ts +0 -0
  104. package/dist/nip/registry.d.ts.map +0 -0
  105. package/dist/nop/client.d.ts +0 -0
  106. package/dist/nop/client.d.ts.map +0 -0
  107. package/dist/nop/frames.d.ts +0 -0
  108. package/dist/nop/frames.d.ts.map +0 -0
  109. package/dist/nop/index.cjs +62 -1
  110. package/dist/nop/index.cjs.map +1 -1
  111. package/dist/nop/index.d.ts +0 -0
  112. package/dist/nop/index.d.ts.map +0 -0
  113. package/dist/nop/index.js +789 -6
  114. package/dist/nop/index.js.map +1 -1
  115. package/dist/nop/models.d.ts +0 -0
  116. package/dist/nop/models.d.ts.map +0 -0
  117. package/dist/nop/nop-types.d.ts +0 -0
  118. package/dist/nop/nop-types.d.ts.map +0 -0
  119. package/dist/nop/registry.d.ts +0 -0
  120. package/dist/nop/registry.d.ts.map +0 -0
  121. package/dist/nwp/client.d.ts +0 -0
  122. package/dist/nwp/client.d.ts.map +0 -0
  123. package/dist/nwp/frames.d.ts +0 -0
  124. package/dist/nwp/frames.d.ts.map +0 -0
  125. package/dist/nwp/index.cjs +64 -2
  126. package/dist/nwp/index.cjs.map +1 -1
  127. package/dist/nwp/index.d.ts +0 -0
  128. package/dist/nwp/index.d.ts.map +0 -0
  129. package/dist/nwp/index.js +693 -5
  130. package/dist/nwp/index.js.map +1 -1
  131. package/dist/nwp/registry.d.ts +0 -0
  132. package/dist/nwp/registry.d.ts.map +0 -0
  133. package/dist/setup.d.ts +0 -0
  134. package/dist/setup.d.ts.map +0 -0
  135. package/doc/nps-sdk.core.cn.md +321 -0
  136. package/doc/nps-sdk.core.md +326 -0
  137. package/doc/nps-sdk.ncp.cn.md +270 -0
  138. package/doc/nps-sdk.ncp.md +276 -0
  139. package/doc/nps-sdk.ndp.cn.md +267 -0
  140. package/doc/nps-sdk.ndp.md +273 -0
  141. package/doc/nps-sdk.nip.cn.md +235 -0
  142. package/doc/nps-sdk.nip.md +242 -0
  143. package/doc/nps-sdk.nop.cn.md +329 -0
  144. package/doc/nps-sdk.nop.md +332 -0
  145. package/doc/nps-sdk.nwp.cn.md +217 -0
  146. package/doc/nps-sdk.nwp.md +224 -0
  147. package/doc/overview.cn.md +149 -0
  148. package/doc/overview.md +153 -0
  149. package/package.json +21 -4
  150. package/src/core/frames.ts +1 -0
  151. package/src/core/index.ts +37 -5
  152. package/src/index.ts +1 -1
  153. package/src/ncp/frames.ts +52 -0
  154. package/src/ncp/registry.ts +2 -1
  155. package/dist/codec-CmHeovTV.d.cts +0 -120
  156. package/dist/codec-CmHeovTV.d.ts +0 -120
  157. package/dist/core/anchor-cache.js +0 -104
  158. package/dist/core/anchor-cache.js.map +0 -1
  159. package/dist/core/cache.js +0 -80
  160. package/dist/core/cache.js.map +0 -1
  161. package/dist/core/canonical-json.js +0 -44
  162. package/dist/core/canonical-json.js.map +0 -1
  163. package/dist/core/codec.js +0 -119
  164. package/dist/core/codec.js.map +0 -1
  165. package/dist/core/codecs/index.js +0 -6
  166. package/dist/core/codecs/index.js.map +0 -1
  167. package/dist/core/codecs/ncp-codec.js +0 -93
  168. package/dist/core/codecs/ncp-codec.js.map +0 -1
  169. package/dist/core/codecs/tier1-json-codec.js +0 -28
  170. package/dist/core/codecs/tier1-json-codec.js.map +0 -1
  171. package/dist/core/codecs/tier2-msgpack-codec.js +0 -26
  172. package/dist/core/codecs/tier2-msgpack-codec.js.map +0 -1
  173. package/dist/core/crypto-provider.js +0 -10
  174. package/dist/core/crypto-provider.js.map +0 -1
  175. package/dist/core/exceptions.js +0 -52
  176. package/dist/core/exceptions.js.map +0 -1
  177. package/dist/core/frame-header.js +0 -185
  178. package/dist/core/frame-header.js.map +0 -1
  179. package/dist/core/frame-registry.js +0 -63
  180. package/dist/core/frame-registry.js.map +0 -1
  181. package/dist/core/frames.js +0 -153
  182. package/dist/core/frames.js.map +0 -1
  183. package/dist/core/index.d.cts +0 -41
  184. package/dist/core/registry.js +0 -17
  185. package/dist/core/registry.js.map +0 -1
  186. package/dist/core/status-codes.js +0 -38
  187. package/dist/core/status-codes.js.map +0 -1
  188. package/dist/frames-B3qLdl_g.d.cts +0 -77
  189. package/dist/frames-Ff7-ZPUl.d.ts +0 -77
  190. package/dist/index.d.cts +0 -21
  191. package/dist/ncp/frames/anchor-frame.js +0 -54
  192. package/dist/ncp/frames/anchor-frame.js.map +0 -1
  193. package/dist/ncp/frames/caps-frame.js +0 -29
  194. package/dist/ncp/frames/caps-frame.js.map +0 -1
  195. package/dist/ncp/frames/diff-frame.js +0 -37
  196. package/dist/ncp/frames/diff-frame.js.map +0 -1
  197. package/dist/ncp/frames/error-frame.js +0 -13
  198. package/dist/ncp/frames/error-frame.js.map +0 -1
  199. package/dist/ncp/frames/hello-frame.js +0 -25
  200. package/dist/ncp/frames/hello-frame.js.map +0 -1
  201. package/dist/ncp/frames/stream-frame.js +0 -18
  202. package/dist/ncp/frames/stream-frame.js.map +0 -1
  203. package/dist/ncp/frames.js +0 -147
  204. package/dist/ncp/frames.js.map +0 -1
  205. package/dist/ncp/handshake.js +0 -80
  206. package/dist/ncp/handshake.js.map +0 -1
  207. package/dist/ncp/index.d.cts +0 -6
  208. package/dist/ncp/ncp-error-codes.js +0 -32
  209. package/dist/ncp/ncp-error-codes.js.map +0 -1
  210. package/dist/ncp/ncp-patch-format.js +0 -13
  211. package/dist/ncp/ncp-patch-format.js.map +0 -1
  212. package/dist/ncp/registry.js +0 -12
  213. package/dist/ncp/registry.js.map +0 -1
  214. package/dist/ncp/stream-manager.js +0 -163
  215. package/dist/ncp/stream-manager.js.map +0 -1
  216. package/dist/ndp/frames.js +0 -87
  217. package/dist/ndp/frames.js.map +0 -1
  218. package/dist/ndp/index.d.cts +0 -86
  219. package/dist/ndp/ndp-registry.js +0 -79
  220. package/dist/ndp/ndp-registry.js.map +0 -1
  221. package/dist/ndp/registry.js +0 -10
  222. package/dist/ndp/registry.js.map +0 -1
  223. package/dist/ndp/validator.js +0 -48
  224. package/dist/ndp/validator.js.map +0 -1
  225. package/dist/nip/frames.js +0 -81
  226. package/dist/nip/frames.js.map +0 -1
  227. package/dist/nip/identity.js +0 -94
  228. package/dist/nip/identity.js.map +0 -1
  229. package/dist/nip/index.d.cts +0 -65
  230. package/dist/nip/registry.js +0 -10
  231. package/dist/nip/registry.js.map +0 -1
  232. package/dist/nop/client.js +0 -90
  233. package/dist/nop/client.js.map +0 -1
  234. package/dist/nop/frames.js +0 -148
  235. package/dist/nop/frames.js.map +0 -1
  236. package/dist/nop/index.d.cts +0 -155
  237. package/dist/nop/models.js +0 -50
  238. package/dist/nop/models.js.map +0 -1
  239. package/dist/nop/nop-types.js +0 -44
  240. package/dist/nop/nop-types.js.map +0 -1
  241. package/dist/nop/registry.js +0 -11
  242. package/dist/nop/registry.js.map +0 -1
  243. package/dist/nwp/client.js +0 -101
  244. package/dist/nwp/client.js.map +0 -1
  245. package/dist/nwp/frames.js +0 -81
  246. package/dist/nwp/frames.js.map +0 -1
  247. package/dist/nwp/index.d.cts +0 -65
  248. package/dist/nwp/registry.js +0 -9
  249. package/dist/nwp/registry.js.map +0 -1
  250. package/dist/setup.js +0 -29
  251. package/dist/setup.js.map +0 -1
@@ -1,188 +1,388 @@
1
1
  'use strict';
2
2
 
3
- // src/ncp/frames.ts
4
- var AnchorFrame = class _AnchorFrame {
5
- constructor(anchorId, schema, ttl = 3600) {
6
- this.anchorId = anchorId;
7
- this.schema = schema;
8
- this.ttl = ttl;
9
- }
10
- anchorId;
11
- schema;
12
- ttl;
13
- frameType = 1 /* ANCHOR */;
14
- preferredTier = 1 /* MSGPACK */;
15
- toDict() {
16
- return {
17
- anchor_id: this.anchorId,
18
- schema: { fields: this.schema.fields.map((f) => ({ ...f })) },
19
- ttl: this.ttl
20
- };
3
+ var crypto = require('crypto');
4
+ var canonicalizeDefault = require('canonicalize');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var canonicalizeDefault__default = /*#__PURE__*/_interopDefault(canonicalizeDefault);
9
+
10
+ // src/ncp/frames/anchor-frame.ts
11
+
12
+ // src/core/frame-header.ts
13
+ var NcpError = class extends Error {
14
+ // `code` accepts NcpErrorCode constants (preferred) as well as NPS status
15
+ // strings that are not NCP-prefixed (e.g. "NPS-CLIENT-CONFLICT") for cases
16
+ // where the spec delegates to NPS-level codes without assigning an NCP code.
17
+ constructor(code, message) {
18
+ super(message);
19
+ this.code = code;
20
+ this.name = "NcpError";
21
+ }
22
+ code;
23
+ };
24
+
25
+ // src/ncp/frames/anchor-frame.ts
26
+ var canonicalize = canonicalizeDefault__default.default;
27
+ var VALID_FIELD_TYPES = [
28
+ "string",
29
+ "uint64",
30
+ "int64",
31
+ "decimal",
32
+ "bool",
33
+ "timestamp",
34
+ "bytes",
35
+ "object",
36
+ "array"
37
+ ];
38
+ function computeAnchorId(schema) {
39
+ const canonical = canonicalize(schema);
40
+ if (!canonical) {
41
+ throw new NcpError("NCP-ANCHOR-SCHEMA-INVALID", "Schema cannot be canonicalized");
42
+ }
43
+ const hash = crypto.createHash("sha256").update(canonical).digest("hex");
44
+ return `sha256:${hash}`;
45
+ }
46
+ function validateAnchorFrame(frame) {
47
+ for (const field of frame.schema.fields) {
48
+ if (!VALID_FIELD_TYPES.includes(field.type)) {
49
+ throw new NcpError(
50
+ "NCP-ANCHOR-SCHEMA-INVALID",
51
+ `Unsupported field type "${field.type}" for field "${field.name}". Valid types: ${VALID_FIELD_TYPES.join(", ")}`
52
+ );
53
+ }
54
+ }
55
+ const expected = computeAnchorId(frame.schema);
56
+ if (frame.anchor_id !== expected) {
57
+ throw new NcpError(
58
+ "NCP-ANCHOR-SCHEMA-INVALID",
59
+ `anchor_id mismatch: expected ${expected}, got ${frame.anchor_id}`
60
+ );
21
61
  }
22
- static fromDict(data) {
23
- const schemaRaw = data["schema"];
24
- return new _AnchorFrame(
25
- data["anchor_id"],
26
- { fields: schemaRaw.fields },
27
- data["ttl"] ?? 3600
62
+ }
63
+
64
+ // src/ncp/frames/caps-frame.ts
65
+ function validateCapsFrame(frame) {
66
+ if (frame.count !== frame.data.length) {
67
+ throw new NcpError(
68
+ "NPS-CLIENT-BAD-FRAME",
69
+ `CapsFrame count mismatch: count=${frame.count}, data.length=${frame.data.length}`
28
70
  );
29
71
  }
72
+ if (frame.inline_anchor !== void 0) {
73
+ const computed = computeAnchorId(frame.inline_anchor.schema);
74
+ if (frame.inline_anchor.anchor_id !== computed) {
75
+ throw new NcpError(
76
+ "NCP-ANCHOR-SCHEMA-INVALID",
77
+ `inline_anchor anchor_id mismatch: expected ${computed}, got ${frame.inline_anchor.anchor_id}`
78
+ );
79
+ }
80
+ }
81
+ }
82
+
83
+ // src/ncp/ncp-patch-format.ts
84
+ var PATCH_FORMAT = {
85
+ JSON_PATCH: "json_patch",
86
+ BINARY_BITSET: "binary_bitset"
30
87
  };
31
- var DiffFrame = class _DiffFrame {
32
- constructor(anchorRef, baseSeq, patch, entityId) {
33
- this.anchorRef = anchorRef;
34
- this.baseSeq = baseSeq;
35
- this.patch = patch;
36
- this.entityId = entityId;
37
- }
38
- anchorRef;
39
- baseSeq;
40
- patch;
41
- entityId;
42
- frameType = 2 /* DIFF */;
43
- preferredTier = 1 /* MSGPACK */;
44
- toDict() {
45
- return {
46
- anchor_ref: this.anchorRef,
47
- base_seq: this.baseSeq,
48
- patch: this.patch.map((p) => ({ ...p })),
49
- entity_id: this.entityId ?? null
50
- };
88
+ function isValidPatchFormat(v) {
89
+ return v === PATCH_FORMAT.JSON_PATCH || v === PATCH_FORMAT.BINARY_BITSET;
90
+ }
91
+
92
+ // src/ncp/frames/diff-frame.ts
93
+ function validateDiffSeq(frame, currentSeq) {
94
+ if (frame.base_seq !== currentSeq) {
95
+ throw new NcpError(
96
+ "NCP-STREAM-SEQ-GAP",
97
+ `DiffFrame base_seq=${frame.base_seq} does not match current seq=${currentSeq}`
98
+ );
51
99
  }
52
- static fromDict(data) {
53
- return new _DiffFrame(
54
- data["anchor_ref"],
55
- data["base_seq"],
56
- data["patch"],
57
- data["entity_id"] ?? void 0
100
+ }
101
+ function validateDiffFrame(frame, encodingTier) {
102
+ const fmt = frame.patch_format;
103
+ if (fmt !== void 0 && !isValidPatchFormat(fmt)) {
104
+ throw new NcpError(
105
+ "NCP-DIFF-FORMAT-UNSUPPORTED",
106
+ `Unknown patch_format "${String(fmt)}"`
58
107
  );
59
108
  }
60
- };
61
- var StreamFrame = class _StreamFrame {
62
- constructor(streamId, seq, isLast, data, anchorRef, windowSize) {
63
- this.streamId = streamId;
64
- this.seq = seq;
65
- this.isLast = isLast;
66
- this.data = data;
67
- this.anchorRef = anchorRef;
68
- this.windowSize = windowSize;
69
- }
70
- streamId;
71
- seq;
72
- isLast;
73
- data;
74
- anchorRef;
75
- windowSize;
76
- frameType = 3 /* STREAM */;
77
- preferredTier = 1 /* MSGPACK */;
78
- toDict() {
79
- return {
80
- stream_id: this.streamId,
81
- seq: this.seq,
82
- is_last: this.isLast,
83
- data: this.data,
84
- anchor_ref: this.anchorRef ?? null,
85
- window_size: this.windowSize ?? null
86
- };
109
+ if (fmt === "binary_bitset" && encodingTier !== 1 /* MsgPack */) {
110
+ throw new NcpError(
111
+ "NCP-DIFF-FORMAT-UNSUPPORTED",
112
+ "patch_format=binary_bitset requires Tier-2 MsgPack encoding"
113
+ );
114
+ }
115
+ }
116
+
117
+ // src/ncp/frames/error-frame.ts
118
+ function isErrorFrame(obj) {
119
+ if (typeof obj !== "object" || obj === null) return false;
120
+ const o = obj;
121
+ return o.frame === "0xFE" && typeof o.status === "string" && typeof o.error === "string";
122
+ }
123
+
124
+ // src/ncp/frames/hello-frame.ts
125
+ function validateHelloFrame(frame) {
126
+ if (!frame.nps_version) {
127
+ throw new NcpError(
128
+ "NPS-CLIENT-BAD-FRAME",
129
+ "HelloFrame missing required field: nps_version"
130
+ );
87
131
  }
88
- static fromDict(data) {
89
- return new _StreamFrame(
90
- data["stream_id"],
91
- data["seq"],
92
- data["is_last"],
93
- data["data"],
94
- data["anchor_ref"] ?? void 0,
95
- data["window_size"] ?? void 0
132
+ if (!frame.supported_encodings || frame.supported_encodings.length === 0) {
133
+ throw new NcpError(
134
+ "NPS-CLIENT-BAD-FRAME",
135
+ "HelloFrame missing required field: supported_encodings (must be non-empty)"
96
136
  );
97
137
  }
98
- };
99
- var CapsFrame = class _CapsFrame {
100
- constructor(anchorRef, count, data, nextCursor, tokenEst, cached, tokenizerUsed) {
101
- this.anchorRef = anchorRef;
102
- this.count = count;
103
- this.data = data;
104
- this.nextCursor = nextCursor;
105
- this.tokenEst = tokenEst;
106
- this.cached = cached;
107
- this.tokenizerUsed = tokenizerUsed;
108
- }
109
- anchorRef;
110
- count;
111
- data;
112
- nextCursor;
113
- tokenEst;
114
- cached;
115
- tokenizerUsed;
116
- frameType = 4 /* CAPS */;
117
- preferredTier = 1 /* MSGPACK */;
118
- toDict() {
119
- return {
120
- anchor_ref: this.anchorRef,
121
- count: this.count,
122
- data: this.data,
123
- next_cursor: this.nextCursor ?? null,
124
- token_est: this.tokenEst ?? null,
125
- cached: this.cached ?? null,
126
- tokenizer_used: this.tokenizerUsed ?? null
127
- };
138
+ if (!frame.supported_protocols || frame.supported_protocols.length === 0) {
139
+ throw new NcpError(
140
+ "NPS-CLIENT-BAD-FRAME",
141
+ "HelloFrame missing required field: supported_protocols (must be non-empty)"
142
+ );
128
143
  }
129
- static fromDict(data) {
130
- return new _CapsFrame(
131
- data["anchor_ref"],
132
- data["count"],
133
- data["data"],
134
- data["next_cursor"] ?? void 0,
135
- data["token_est"] ?? void 0,
136
- data["cached"] ?? void 0,
137
- data["tokenizer_used"] ?? void 0
144
+ }
145
+
146
+ // src/ncp/frames/stream-frame.ts
147
+ var UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
148
+ function validateStreamFrame(frame) {
149
+ if (!UUID_V4_RE.test(frame.stream_id)) {
150
+ throw new NcpError(
151
+ "NPS-CLIENT-BAD-FRAME",
152
+ `stream_id "${frame.stream_id}" is not a valid UUID v4`
138
153
  );
139
154
  }
155
+ }
156
+
157
+ // src/ncp/ncp-error-codes.ts
158
+ var NCP_ERROR_CODES = {
159
+ // Implementation-only codes (not in spec §6 — see test_results.md spec question 2)
160
+ NCP_FRAME_PARSE_ERROR: "NCP-FRAME-PARSE-ERROR",
161
+ NCP_FRAME_INCOMPLETE: "NCP-FRAME-INCOMPLETE",
162
+ // Spec-defined codes
163
+ NCP_FRAME_UNKNOWN_TYPE: "NCP-FRAME-UNKNOWN-TYPE",
164
+ NCP_FRAME_PAYLOAD_TOO_LARGE: "NCP-FRAME-PAYLOAD-TOO-LARGE",
165
+ NCP_FRAME_FLAGS_INVALID: "NCP-FRAME-FLAGS-INVALID",
166
+ NCP_ANCHOR_NOT_FOUND: "NCP-ANCHOR-NOT-FOUND",
167
+ NCP_ANCHOR_SCHEMA_INVALID: "NCP-ANCHOR-SCHEMA-INVALID",
168
+ NCP_ANCHOR_ID_MISMATCH: "NCP-ANCHOR-ID-MISMATCH",
169
+ NCP_ANCHOR_STALE: "NCP-ANCHOR-STALE",
170
+ NCP_STREAM_SEQ_GAP: "NCP-STREAM-SEQ-GAP",
171
+ NCP_STREAM_NOT_FOUND: "NCP-STREAM-NOT-FOUND",
172
+ NCP_STREAM_LIMIT_EXCEEDED: "NCP-STREAM-LIMIT-EXCEEDED",
173
+ NCP_STREAM_WINDOW_OVERFLOW: "NCP-STREAM-WINDOW-OVERFLOW",
174
+ NCP_ENCODING_UNSUPPORTED: "NCP-ENCODING-UNSUPPORTED",
175
+ NCP_DIFF_FORMAT_UNSUPPORTED: "NCP-DIFF-FORMAT-UNSUPPORTED",
176
+ NCP_VERSION_INCOMPATIBLE: "NCP-VERSION-INCOMPATIBLE",
177
+ NCP_ENC_NOT_NEGOTIATED: "NCP-ENC-NOT-NEGOTIATED",
178
+ NCP_ENC_AUTH_FAILED: "NCP-ENC-AUTH-FAILED"
140
179
  };
141
- var ErrorFrame = class _ErrorFrame {
142
- constructor(status, error, message, details) {
143
- this.status = status;
144
- this.error = error;
145
- this.message = message;
146
- this.details = details;
147
- }
148
- status;
149
- error;
150
- message;
151
- details;
152
- frameType = 254 /* ERROR */;
153
- preferredTier = 1 /* MSGPACK */;
154
- toDict() {
180
+
181
+ // src/ncp/handshake.ts
182
+ function parseVersion(v) {
183
+ return v.split(".").map((p) => Number.parseInt(p, 10));
184
+ }
185
+ function compareVersions(a, b) {
186
+ const partsA = parseVersion(a);
187
+ const partsB = parseVersion(b);
188
+ const len = Math.max(partsA.length, partsB.length);
189
+ for (let i = 0; i < len; i += 1) {
190
+ const x = partsA[i] ?? 0;
191
+ const y = partsB[i] ?? 0;
192
+ if (x !== y) return x - y;
193
+ }
194
+ return 0;
195
+ }
196
+ function negotiateVersion(client, server) {
197
+ const clientMin = client.min_version ?? client.nps_version;
198
+ const serverVersion = server.nps_version;
199
+ if (compareVersions(clientMin, serverVersion) > 0) {
155
200
  return {
156
- status: this.status,
157
- error: this.error,
158
- message: this.message ?? null,
159
- details: this.details ?? null
201
+ session_version: serverVersion,
202
+ compatible: false,
203
+ error_code: "NCP-VERSION-INCOMPATIBLE"
160
204
  };
161
205
  }
162
- static fromDict(data) {
163
- return new _ErrorFrame(
164
- data["status"],
165
- data["error"],
166
- data["message"] ?? void 0,
167
- data["details"] ?? void 0
168
- );
206
+ const sessionVersion = compareVersions(client.nps_version, serverVersion) <= 0 ? client.nps_version : serverVersion;
207
+ return { session_version: sessionVersion, compatible: true };
208
+ }
209
+ function negotiateEncoding(client, server) {
210
+ const serverSet = new Set(server);
211
+ if (client.includes("msgpack") && serverSet.has("msgpack")) {
212
+ return { encoding: "msgpack" };
169
213
  }
170
- };
171
-
172
- // src/ncp/registry.ts
173
- function registerNcpFrames(registry) {
174
- registry.register(1 /* ANCHOR */, AnchorFrame);
175
- registry.register(2 /* DIFF */, DiffFrame);
176
- registry.register(3 /* STREAM */, StreamFrame);
177
- registry.register(4 /* CAPS */, CapsFrame);
178
- registry.register(254 /* ERROR */, ErrorFrame);
214
+ if (client.includes("json") && serverSet.has("json")) {
215
+ return { encoding: "json" };
216
+ }
217
+ for (const enc of client) {
218
+ if (serverSet.has(enc)) {
219
+ return { encoding: enc };
220
+ }
221
+ }
222
+ return { encoding: null };
179
223
  }
180
224
 
181
- exports.AnchorFrame = AnchorFrame;
182
- exports.CapsFrame = CapsFrame;
183
- exports.DiffFrame = DiffFrame;
184
- exports.ErrorFrame = ErrorFrame;
185
- exports.StreamFrame = StreamFrame;
186
- exports.registerNcpFrames = registerNcpFrames;
225
+ // src/ncp/stream-manager.ts
226
+ var StreamManager = class {
227
+ streams = /* @__PURE__ */ new Map();
228
+ outgoing = /* @__PURE__ */ new Map();
229
+ maxConcurrent;
230
+ constructor(options) {
231
+ this.maxConcurrent = options?.maxConcurrent ?? 32;
232
+ }
233
+ /**
234
+ * Receive a StreamFrame chunk.
235
+ *
236
+ * @returns true if stream is complete (is_last=true or error_code set).
237
+ * @throws {NcpError} NCP-STREAM-LIMIT-EXCEEDED if too many concurrent streams.
238
+ * @throws {NcpError} NCP-STREAM-NOT-FOUND if frame.seq > 0 for a stream that was never opened.
239
+ * @throws {NcpError} NPS-CLIENT-CONFLICT if the stream_id was already completed (stream-id reuse; see test_cases NCP-S-04).
240
+ * @throws {NcpError} NCP-STREAM-SEQ-GAP if sequence number is not expected.
241
+ */
242
+ receive(frame) {
243
+ let stream = this.streams.get(frame.stream_id);
244
+ if (!stream) {
245
+ if (frame.seq !== 0) {
246
+ throw new NcpError(
247
+ NCP_ERROR_CODES.NCP_STREAM_NOT_FOUND,
248
+ `Unknown stream_id ${frame.stream_id} \u2014 first frame must have seq=0`
249
+ );
250
+ }
251
+ if (this.streams.size >= this.maxConcurrent) {
252
+ throw new NcpError(
253
+ NCP_ERROR_CODES.NCP_STREAM_LIMIT_EXCEEDED,
254
+ `Max concurrent streams (${this.maxConcurrent}) exceeded`
255
+ );
256
+ }
257
+ stream = {
258
+ streamId: frame.stream_id,
259
+ expectedSeq: 0,
260
+ chunks: [],
261
+ completed: false
262
+ };
263
+ this.streams.set(frame.stream_id, stream);
264
+ }
265
+ if (stream.completed) {
266
+ throw new NcpError(
267
+ "NPS-CLIENT-CONFLICT",
268
+ `Stream ${frame.stream_id} is already completed \u2014 cannot reuse stream_id`
269
+ );
270
+ }
271
+ if (frame.seq !== stream.expectedSeq) {
272
+ if (frame.seq < stream.expectedSeq) {
273
+ return false;
274
+ }
275
+ throw new NcpError(
276
+ NCP_ERROR_CODES.NCP_STREAM_SEQ_GAP,
277
+ `Expected seq ${stream.expectedSeq}, got ${frame.seq} on stream ${frame.stream_id}`
278
+ );
279
+ }
280
+ stream.chunks.push(frame.data);
281
+ stream.expectedSeq = frame.seq + 1;
282
+ if (frame.error_code) {
283
+ stream.completed = true;
284
+ stream.errorCode = frame.error_code;
285
+ return true;
286
+ }
287
+ if (frame.is_last) {
288
+ stream.completed = true;
289
+ return true;
290
+ }
291
+ return false;
292
+ }
293
+ /**
294
+ * Send a StreamFrame on an outgoing stream, enforcing window-based flow control.
295
+ *
296
+ * - seq=0 with window_size initialises remainingWindow (no decrement for opening frame).
297
+ * - Subsequent sends decrement remainingWindow when flow control is active.
298
+ * - Throws NCP-STREAM-WINDOW-OVERFLOW when remainingWindow === 0.
299
+ *
300
+ * @throws {NcpError} NCP-STREAM-WINDOW-OVERFLOW if window is exhausted.
301
+ */
302
+ send(frame) {
303
+ let out = this.outgoing.get(frame.stream_id);
304
+ if (!out) {
305
+ out = {
306
+ streamId: frame.stream_id,
307
+ remainingWindow: void 0,
308
+ paused: false
309
+ };
310
+ this.outgoing.set(frame.stream_id, out);
311
+ }
312
+ if (frame.seq === 0 && frame.window_size !== void 0) {
313
+ out.remainingWindow = frame.window_size;
314
+ return;
315
+ }
316
+ if (out.remainingWindow !== void 0) {
317
+ if (out.remainingWindow === 0) {
318
+ throw new NcpError(
319
+ NCP_ERROR_CODES.NCP_STREAM_WINDOW_OVERFLOW,
320
+ `Window exhausted on stream ${frame.stream_id}`
321
+ );
322
+ }
323
+ out.remainingWindow -= 1;
324
+ }
325
+ }
326
+ /**
327
+ * Update the send window for a stream.
328
+ *
329
+ * Called when a reverse-direction StreamFrame arrives with data=[] and window_size set.
330
+ * Replaces remainingWindow with new_size. Sets paused=true when new_size === 0.
331
+ */
332
+ updateWindow(streamId, newSize) {
333
+ let out = this.outgoing.get(streamId);
334
+ if (!out) {
335
+ out = {
336
+ streamId,
337
+ remainingWindow: newSize,
338
+ paused: newSize === 0
339
+ };
340
+ this.outgoing.set(streamId, out);
341
+ return;
342
+ }
343
+ out.remainingWindow = newSize;
344
+ out.paused = newSize === 0;
345
+ }
346
+ /**
347
+ * Returns true when the outgoing stream is paused (window=0 was received).
348
+ * Resumes (returns false) once a non-zero window update arrives.
349
+ */
350
+ isPaused(streamId) {
351
+ return this.outgoing.get(streamId)?.paused ?? false;
352
+ }
353
+ /** Get reassembled data for a completed stream. */
354
+ getData(streamId) {
355
+ const stream = this.streams.get(streamId);
356
+ if (!stream || !stream.completed) return null;
357
+ return stream.chunks.flat();
358
+ }
359
+ /** Get error code if stream terminated with error. */
360
+ getError(streamId) {
361
+ return this.streams.get(streamId)?.errorCode;
362
+ }
363
+ /** Number of active (non-completed) streams. */
364
+ get activeCount() {
365
+ let count = 0;
366
+ for (const s of this.streams.values()) {
367
+ if (!s.completed) count++;
368
+ }
369
+ return count;
370
+ }
371
+ };
372
+
373
+ exports.NCP_ERROR_CODES = NCP_ERROR_CODES;
374
+ exports.PATCH_FORMAT = PATCH_FORMAT;
375
+ exports.StreamManager = StreamManager;
376
+ exports.computeAnchorId = computeAnchorId;
377
+ exports.isErrorFrame = isErrorFrame;
378
+ exports.isValidPatchFormat = isValidPatchFormat;
379
+ exports.negotiateEncoding = negotiateEncoding;
380
+ exports.negotiateVersion = negotiateVersion;
381
+ exports.validateAnchorFrame = validateAnchorFrame;
382
+ exports.validateCapsFrame = validateCapsFrame;
383
+ exports.validateDiffFrame = validateDiffFrame;
384
+ exports.validateDiffSeq = validateDiffSeq;
385
+ exports.validateHelloFrame = validateHelloFrame;
386
+ exports.validateStreamFrame = validateStreamFrame;
187
387
  //# sourceMappingURL=index.cjs.map
188
388
  //# sourceMappingURL=index.cjs.map