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

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 (46) hide show
  1. package/.npmrc.publish +1 -0
  2. package/CHANGELOG.cn.md +39 -0
  3. package/CHANGELOG.md +39 -0
  4. package/CONTRIBUTING.cn.md +35 -0
  5. package/CONTRIBUTING.md +2 -0
  6. package/README.cn.md +155 -0
  7. package/README.md +5 -3
  8. package/dist/core/frames.d.ts +1 -0
  9. package/dist/core/frames.d.ts.map +1 -1
  10. package/dist/core/frames.js +1 -0
  11. package/dist/core/frames.js.map +1 -1
  12. package/dist/core/index.d.ts +6 -4
  13. package/dist/core/index.d.ts.map +1 -1
  14. package/dist/core/index.js +17 -5
  15. package/dist/core/index.js.map +1 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/ncp/frames.d.ts +18 -0
  21. package/dist/ncp/frames.d.ts.map +1 -1
  22. package/dist/ncp/frames.js +45 -0
  23. package/dist/ncp/frames.js.map +1 -1
  24. package/dist/ncp/registry.d.ts.map +1 -1
  25. package/dist/ncp/registry.js +2 -1
  26. package/dist/ncp/registry.js.map +1 -1
  27. package/doc/nps-sdk.core.cn.md +321 -0
  28. package/doc/nps-sdk.core.md +326 -0
  29. package/doc/nps-sdk.ncp.cn.md +270 -0
  30. package/doc/nps-sdk.ncp.md +276 -0
  31. package/doc/nps-sdk.ndp.cn.md +267 -0
  32. package/doc/nps-sdk.ndp.md +273 -0
  33. package/doc/nps-sdk.nip.cn.md +235 -0
  34. package/doc/nps-sdk.nip.md +242 -0
  35. package/doc/nps-sdk.nop.cn.md +329 -0
  36. package/doc/nps-sdk.nop.md +332 -0
  37. package/doc/nps-sdk.nwp.cn.md +217 -0
  38. package/doc/nps-sdk.nwp.md +224 -0
  39. package/doc/overview.cn.md +149 -0
  40. package/doc/overview.md +153 -0
  41. package/package.json +21 -4
  42. package/src/core/frames.ts +1 -0
  43. package/src/core/index.ts +37 -5
  44. package/src/index.ts +1 -1
  45. package/src/ncp/frames.ts +52 -0
  46. package/src/ncp/registry.ts +2 -1
@@ -0,0 +1,270 @@
1
+ [English Version](./nps-sdk.ncp.md) | 中文版
2
+
3
+ # `@labacacia/nps-sdk/ncp` — 类与方法参考
4
+
5
+ > 规范:[NPS-1 NCP v0.4](https://github.com/labacacia/NPS-Release/blob/main/spec/NPS-1-NCP.md)
6
+
7
+ NCP 是线路与 schema 层。本模块提供五个核心帧
8
+ (`AnchorFrame`、`DiffFrame`、`StreamFrame`、`CapsFrame`、`ErrorFrame`),
9
+ 以及原生模式握手辅助(`HelloFrame`)和接收方用于重组分块流的 stream manager。
10
+
11
+ ---
12
+
13
+ ## 目录
14
+
15
+ - [`AnchorFrame` (0x01)](#anchorframe-0x01)
16
+ - [`DiffFrame` (0x02)](#diffframe-0x02)
17
+ - [`StreamFrame` (0x03)](#streamframe-0x03)
18
+ - [`CapsFrame` (0x04)](#capsframe-0x04)
19
+ - [`HelloFrame` (0x06)](#helloframe-0x06)
20
+ - [`ErrorFrame` (0xFE)](#errorframe-0xfe)
21
+ - [握手辅助](#握手辅助)
22
+ - [`StreamManager`](#streammanager)
23
+ - [`NCP_ERROR_CODES`](#ncp_error_codes)
24
+
25
+ ---
26
+
27
+ ## `AnchorFrame` (0x01)
28
+
29
+ Schema 锚点 —— 内容寻址的 schema 广告。
30
+
31
+ ```typescript
32
+ interface SchemaField {
33
+ name: string;
34
+ type: string; // "string" | "uint64" | "int64" | "decimal" |
35
+ // "bool" | "timestamp" | "bytes" | "object" | "array"
36
+ semantic?: string; // 可选的 NPS 语义标签
37
+ nullable?: boolean;
38
+ }
39
+
40
+ interface FrameSchema {
41
+ fields: SchemaField[];
42
+ }
43
+
44
+ interface AnchorFrame {
45
+ frame: "0x01";
46
+ anchor_id: string; // "sha256:{64 位小写 hex}"
47
+ schema: FrameSchema;
48
+ ttl?: number; // 秒;0 = 仅 session
49
+ }
50
+
51
+ function computeAnchorId(schema: FrameSchema): string;
52
+ function validateAnchorFrame(frame: AnchorFrame): void;
53
+ ```
54
+
55
+ `computeAnchorId` 通过 RFC 8785 JCS 规范化 schema,用 SHA-256 哈希,
56
+ 返回 `"sha256:{hex}"`。
57
+
58
+ `validateAnchorFrame` 在以下情况抛 `NcpError("NCP-ANCHOR-SCHEMA-INVALID")`:
59
+ - 字段拥有未知的 `type`,或
60
+ - `anchor_id` 与计算出的规范哈希不匹配。
61
+
62
+ ---
63
+
64
+ ## `DiffFrame` (0x02)
65
+
66
+ 锚定到之前某个 `AnchorFrame` 的增量数据补丁。
67
+
68
+ ```typescript
69
+ interface JsonPatchOperation {
70
+ op: "add" | "remove" | "replace" | "move" | "copy" | "test";
71
+ path: string; // JSON Pointer
72
+ value?: unknown;
73
+ from?: string; // 用于 move/copy
74
+ }
75
+
76
+ type PatchFormat = "json_patch" | "binary_bitset";
77
+
78
+ interface DiffFrame {
79
+ frame: "0x02";
80
+ anchor_ref: string;
81
+ base_seq: number;
82
+ patch_format?: PatchFormat;
83
+ patch: JsonPatchOperation[] | Uint8Array;
84
+ entity_id?: string;
85
+ }
86
+
87
+ function validateDiffSeq(frame: DiffFrame, currentSeq: number): void;
88
+ function validateDiffFrame(frame: DiffFrame, encodingTier: EncodingTier): void;
89
+ ```
90
+
91
+ - 若 `base_seq !== currentSeq`,`validateDiffSeq` 抛
92
+ `NcpError("NCP-STREAM-SEQ-GAP")`。
93
+ - 当 `patch_format` 未知,或在非 Tier-2 MsgPack 帧上使用 `binary_bitset` 时,
94
+ `validateDiffFrame` 抛 `NcpError("NCP-DIFF-FORMAT-UNSUPPORTED")`。
95
+
96
+ ---
97
+
98
+ ## `StreamFrame` (0x03)
99
+
100
+ 流式分块帧。
101
+
102
+ ```typescript
103
+ interface StreamFrame {
104
+ frame: "0x03";
105
+ stream_id: string; // UUID v4
106
+ seq: number;
107
+ is_last: boolean;
108
+ anchor_ref?: string;
109
+ data: unknown[];
110
+ window_size?: number; // 反压提示
111
+ error_code?: string; // 终止错误 —— 隐含 is_last=true
112
+ }
113
+
114
+ function validateStreamFrame(frame: StreamFrame): void;
115
+ ```
116
+
117
+ `stream_id` 必须匹配 UUID-v4 形状,否则抛
118
+ `NcpError("NPS-CLIENT-BAD-FRAME")`。
119
+
120
+ ---
121
+
122
+ ## `CapsFrame` (0x04)
123
+
124
+ 胶囊 —— 引用某个已缓存 schema 的完整结果页。
125
+
126
+ ```typescript
127
+ interface CapsFrameInlineAnchor {
128
+ anchor_id: string;
129
+ schema: FrameSchema;
130
+ ttl?: number;
131
+ }
132
+
133
+ interface CapsFrame {
134
+ frame: "0x04";
135
+ anchor_ref: string;
136
+ count: number;
137
+ data: unknown[];
138
+ next_cursor?: string | null;
139
+ token_est?: number;
140
+ tokenizer_used?: string;
141
+ cached?: boolean;
142
+ inline_anchor?: CapsFrameInlineAnchor;
143
+ }
144
+
145
+ function validateCapsFrame(frame: CapsFrame): void;
146
+ ```
147
+
148
+ `validateCapsFrame` 强制:
149
+ - `count === data.length` —— 否则 `NpsStatusCodes.NPS_CLIENT_BAD_FRAME`。
150
+ - 若 `inline_anchor` 存在,`inline_anchor.anchor_id` 必须与
151
+ `inline_anchor.schema` 的规范哈希匹配 —— 否则
152
+ `NcpError("NCP-ANCHOR-SCHEMA-INVALID")`。
153
+
154
+ ---
155
+
156
+ ## `HelloFrame` (0x06)
157
+
158
+ 原生模式客户端握手(NPS-1 §4.6)。
159
+
160
+ ```typescript
161
+ interface HelloFrame {
162
+ frame: "0x06";
163
+ nps_version: string;
164
+ min_version?: string;
165
+ supported_encodings: string[]; // 非空
166
+ supported_protocols: string[]; // 非空
167
+ agent_id?: string;
168
+ max_frame_payload?: number;
169
+ ext_support?: boolean;
170
+ max_concurrent_streams?: number;
171
+ e2e_enc_algorithms?: string[];
172
+ }
173
+
174
+ function validateHelloFrame(frame: HelloFrame): void;
175
+ ```
176
+
177
+ `validateHelloFrame` 检查三个必填字段存在且两个数组字段非空。
178
+
179
+ ---
180
+
181
+ ## `ErrorFrame` (0xFE)
182
+
183
+ 所有 NPS 协议层共用的统一错误帧(NPS-0 §9)。
184
+
185
+ ```typescript
186
+ interface ErrorFrame {
187
+ frame: "0xFE";
188
+ status: string; // NPS 状态码,如 "NPS-CLIENT-NOT-FOUND"
189
+ error: string; // 协议码,如 "NCP-ANCHOR-NOT-FOUND"
190
+ message?: string;
191
+ details?: Record<string, unknown>;
192
+ }
193
+
194
+ function isErrorFrame(obj: unknown): obj is ErrorFrame;
195
+ ```
196
+
197
+ 在解码后的 payload 上把 `isErrorFrame` 用作类型 guard。
198
+
199
+ ---
200
+
201
+ ## 握手辅助
202
+
203
+ 原生模式的版本与编码协商(NPS-1 §2.6)。
204
+
205
+ ```typescript
206
+ function negotiateVersion(
207
+ client: { nps_version: string; min_version?: string },
208
+ server: { nps_version: string },
209
+ ): { session_version: string; compatible: boolean; error_code?: string };
210
+
211
+ function negotiateEncoding(
212
+ client: string[],
213
+ server: string[],
214
+ ): { encoding: string | null };
215
+ ```
216
+
217
+ - 版本比较按分量数字进行 —— `"0.9" < "0.10" < "1.0"`。
218
+ - 当双方都广告 `"msgpack"` 时 `negotiateEncoding` 返回它,
219
+ 否则降级到 `"json"`,再否则按客户端偏好顺序选择第一个共有项。
220
+
221
+ ---
222
+
223
+ ## `StreamManager`
224
+
225
+ 追踪并发 `StreamFrame` 流,强制顺序与流控窗口。
226
+
227
+ ```typescript
228
+ class StreamManager {
229
+ constructor(options?: { maxConcurrent?: number }); // 默认 32
230
+
231
+ receive(frame: StreamFrame): boolean; // 流完成时返回 true
232
+ send(frame: StreamFrame): void; // 强制发出窗口
233
+ updateWindow(streamId: string, newSize: number): void;
234
+ isPaused(streamId: string): boolean;
235
+
236
+ getData(streamId: string): unknown[] | null; // 完成后扁平化分块
237
+ getError(streamId: string): string | undefined;
238
+ readonly activeCount: number;
239
+ }
240
+ ```
241
+
242
+ ### 失败模式
243
+
244
+ | 条件 | 抛出 |
245
+ |------|------|
246
+ | 未知流上 `seq !== 0` | `NcpError("NCP-STREAM-NOT-FOUND")` |
247
+ | 并发流过多 | `NcpError("NCP-STREAM-LIMIT-EXCEEDED")` |
248
+ | 写入已完成的流 | `NcpError("NPS-CLIENT-CONFLICT")` |
249
+ | 接收顺序中的 `seq` 跳号 | `NcpError("NCP-STREAM-SEQ-GAP")` |
250
+ | 发送窗口耗尽 | `NcpError("NCP-STREAM-WINDOW-OVERFLOW")` |
251
+
252
+ `seq` 小于 `expectedSeq` 的重复帧被静默忽略(幂等)。
253
+
254
+ ---
255
+
256
+ ## `NCP_ERROR_CODES`
257
+
258
+ NCP 层协议码常量包(NPS-1 §6、§7.4)。
259
+
260
+ ```typescript
261
+ import { NCP_ERROR_CODES } from "@labacacia/nps-sdk/ncp";
262
+
263
+ NCP_ERROR_CODES.NCP_ANCHOR_NOT_FOUND; // "NCP-ANCHOR-NOT-FOUND"
264
+ NCP_ERROR_CODES.NCP_STREAM_SEQ_GAP; // "NCP-STREAM-SEQ-GAP"
265
+ NCP_ERROR_CODES.NCP_VERSION_INCOMPATIBLE; // "NCP-VERSION-INCOMPATIBLE"
266
+ // …
267
+ ```
268
+
269
+ `NCP_FRAME_PARSE_ERROR` 和 `NCP_FRAME_INCOMPLETE` 为规范 §6 未定义的
270
+ 实现专属码;其余均为规范标准。
@@ -0,0 +1,276 @@
1
+ English | [中文版](./nps-sdk.ncp.cn.md)
2
+
3
+ # `@labacacia/nps-sdk/ncp` — Class and Method Reference
4
+
5
+ > Spec: [NPS-1 NCP v0.4](https://github.com/labacacia/NPS-Release/blob/main/spec/NPS-1-NCP.md)
6
+
7
+ NCP is the wire-and-schema layer. This module provides the five core frames
8
+ (`AnchorFrame`, `DiffFrame`, `StreamFrame`, `CapsFrame`, `ErrorFrame`) plus
9
+ the native-mode handshake helpers (`HelloFrame`) and the stream manager used
10
+ by receivers to reassemble chunked streams.
11
+
12
+ ---
13
+
14
+ ## Table of contents
15
+
16
+ - [`AnchorFrame` (0x01)](#anchorframe-0x01)
17
+ - [`DiffFrame` (0x02)](#diffframe-0x02)
18
+ - [`StreamFrame` (0x03)](#streamframe-0x03)
19
+ - [`CapsFrame` (0x04)](#capsframe-0x04)
20
+ - [`HelloFrame` (0x06)](#helloframe-0x06)
21
+ - [`ErrorFrame` (0xFE)](#errorframe-0xfe)
22
+ - [Handshake helpers](#handshake-helpers)
23
+ - [`StreamManager`](#streammanager)
24
+ - [`NCP_ERROR_CODES`](#ncp_error_codes)
25
+
26
+ ---
27
+
28
+ ## `AnchorFrame` (0x01)
29
+
30
+ Schema anchor — content-addressed schema advertisement.
31
+
32
+ ```typescript
33
+ interface SchemaField {
34
+ name: string;
35
+ type: string; // "string" | "uint64" | "int64" | "decimal" |
36
+ // "bool" | "timestamp" | "bytes" | "object" | "array"
37
+ semantic?: string; // optional NPS semantic tag
38
+ nullable?: boolean;
39
+ }
40
+
41
+ interface FrameSchema {
42
+ fields: SchemaField[];
43
+ }
44
+
45
+ interface AnchorFrame {
46
+ frame: "0x01";
47
+ anchor_id: string; // "sha256:{64 lowercase hex}"
48
+ schema: FrameSchema;
49
+ ttl?: number; // seconds; 0 = session-only
50
+ }
51
+
52
+ function computeAnchorId(schema: FrameSchema): string;
53
+ function validateAnchorFrame(frame: AnchorFrame): void;
54
+ ```
55
+
56
+ `computeAnchorId` canonicalises the schema via RFC 8785 JCS, hashes with
57
+ SHA-256 and returns `"sha256:{hex}"`.
58
+
59
+ `validateAnchorFrame` raises `NcpError("NCP-ANCHOR-SCHEMA-INVALID")` when:
60
+ - a field has an unknown `type`, OR
61
+ - `anchor_id` does not match the computed canonical hash.
62
+
63
+ ---
64
+
65
+ ## `DiffFrame` (0x02)
66
+
67
+ Incremental data patch anchored to a prior `AnchorFrame`.
68
+
69
+ ```typescript
70
+ interface JsonPatchOperation {
71
+ op: "add" | "remove" | "replace" | "move" | "copy" | "test";
72
+ path: string; // JSON Pointer
73
+ value?: unknown;
74
+ from?: string; // for move/copy
75
+ }
76
+
77
+ type PatchFormat = "json_patch" | "binary_bitset";
78
+
79
+ interface DiffFrame {
80
+ frame: "0x02";
81
+ anchor_ref: string;
82
+ base_seq: number;
83
+ patch_format?: PatchFormat;
84
+ patch: JsonPatchOperation[] | Uint8Array;
85
+ entity_id?: string;
86
+ }
87
+
88
+ function validateDiffSeq(frame: DiffFrame, currentSeq: number): void;
89
+ function validateDiffFrame(frame: DiffFrame, encodingTier: EncodingTier): void;
90
+ ```
91
+
92
+ - `validateDiffSeq` throws `NcpError("NCP-STREAM-SEQ-GAP")` if
93
+ `base_seq !== currentSeq`.
94
+ - `validateDiffFrame` throws `NcpError("NCP-DIFF-FORMAT-UNSUPPORTED")`
95
+ on unknown `patch_format`, or when `binary_bitset` is used on a
96
+ non-Tier-2 MsgPack frame.
97
+
98
+ ---
99
+
100
+ ## `StreamFrame` (0x03)
101
+
102
+ Streaming chunk frame.
103
+
104
+ ```typescript
105
+ interface StreamFrame {
106
+ frame: "0x03";
107
+ stream_id: string; // UUID v4
108
+ seq: number;
109
+ is_last: boolean;
110
+ anchor_ref?: string;
111
+ data: unknown[];
112
+ window_size?: number; // back-pressure hint
113
+ error_code?: string; // terminal error — implies is_last=true
114
+ }
115
+
116
+ function validateStreamFrame(frame: StreamFrame): void;
117
+ ```
118
+
119
+ `stream_id` must match the UUID-v4 shape, otherwise
120
+ `NcpError("NPS-CLIENT-BAD-FRAME")` is raised.
121
+
122
+ ---
123
+
124
+ ## `CapsFrame` (0x04)
125
+
126
+ Capsule — a complete result page that references a cached schema.
127
+
128
+ ```typescript
129
+ interface CapsFrameInlineAnchor {
130
+ anchor_id: string;
131
+ schema: FrameSchema;
132
+ ttl?: number;
133
+ }
134
+
135
+ interface CapsFrame {
136
+ frame: "0x04";
137
+ anchor_ref: string;
138
+ count: number;
139
+ data: unknown[];
140
+ next_cursor?: string | null;
141
+ token_est?: number;
142
+ tokenizer_used?: string;
143
+ cached?: boolean;
144
+ inline_anchor?: CapsFrameInlineAnchor;
145
+ }
146
+
147
+ function validateCapsFrame(frame: CapsFrame): void;
148
+ ```
149
+
150
+ `validateCapsFrame` enforces:
151
+ - `count === data.length` — otherwise `NpsStatusCodes.NPS_CLIENT_BAD_FRAME`.
152
+ - If `inline_anchor` is present, `inline_anchor.anchor_id` matches the
153
+ canonical hash of `inline_anchor.schema` — otherwise
154
+ `NcpError("NCP-ANCHOR-SCHEMA-INVALID")`.
155
+
156
+ ---
157
+
158
+ ## `HelloFrame` (0x06)
159
+
160
+ Native-mode client handshake (NPS-1 §4.6).
161
+
162
+ ```typescript
163
+ interface HelloFrame {
164
+ frame: "0x06";
165
+ nps_version: string;
166
+ min_version?: string;
167
+ supported_encodings: string[]; // non-empty
168
+ supported_protocols: string[]; // non-empty
169
+ agent_id?: string;
170
+ max_frame_payload?: number;
171
+ ext_support?: boolean;
172
+ max_concurrent_streams?: number;
173
+ e2e_enc_algorithms?: string[];
174
+ }
175
+
176
+ function validateHelloFrame(frame: HelloFrame): void;
177
+ ```
178
+
179
+ `validateHelloFrame` checks that the three required fields are present and
180
+ the two array fields are non-empty.
181
+
182
+ ---
183
+
184
+ ## `ErrorFrame` (0xFE)
185
+
186
+ Unified error frame shared by every NPS protocol layer (NPS-0 §9).
187
+
188
+ ```typescript
189
+ interface ErrorFrame {
190
+ frame: "0xFE";
191
+ status: string; // NPS status code, e.g. "NPS-CLIENT-NOT-FOUND"
192
+ error: string; // protocol code, e.g. "NCP-ANCHOR-NOT-FOUND"
193
+ message?: string;
194
+ details?: Record<string, unknown>;
195
+ }
196
+
197
+ function isErrorFrame(obj: unknown): obj is ErrorFrame;
198
+ ```
199
+
200
+ Use `isErrorFrame` as a type guard on decoded payloads.
201
+
202
+ ---
203
+
204
+ ## Handshake helpers
205
+
206
+ Version & encoding negotiation for native mode (NPS-1 §2.6).
207
+
208
+ ```typescript
209
+ function negotiateVersion(
210
+ client: { nps_version: string; min_version?: string },
211
+ server: { nps_version: string },
212
+ ): { session_version: string; compatible: boolean; error_code?: string };
213
+
214
+ function negotiateEncoding(
215
+ client: string[],
216
+ server: string[],
217
+ ): { encoding: string | null };
218
+ ```
219
+
220
+ - Version comparison is component-wise numeric — `"0.9" < "0.10" < "1.0"`.
221
+ - `negotiateEncoding` returns `"msgpack"` when both sides advertise it,
222
+ falling back to `"json"`, then the first mutual entry in the client's
223
+ preference order.
224
+
225
+ ---
226
+
227
+ ## `StreamManager`
228
+
229
+ Tracks concurrent `StreamFrame` streams, enforces sequence ordering and
230
+ flow-control windows.
231
+
232
+ ```typescript
233
+ class StreamManager {
234
+ constructor(options?: { maxConcurrent?: number }); // default 32
235
+
236
+ receive(frame: StreamFrame): boolean; // true when stream is complete
237
+ send(frame: StreamFrame): void; // enforces outgoing window
238
+ updateWindow(streamId: string, newSize: number): void;
239
+ isPaused(streamId: string): boolean;
240
+
241
+ getData(streamId: string): unknown[] | null; // flattened chunks after completion
242
+ getError(streamId: string): string | undefined;
243
+ readonly activeCount: number;
244
+ }
245
+ ```
246
+
247
+ ### Failure modes
248
+
249
+ | Condition | Thrown |
250
+ |-----------|--------|
251
+ | `seq !== 0` on an unknown stream | `NcpError("NCP-STREAM-NOT-FOUND")` |
252
+ | Too many concurrent streams open | `NcpError("NCP-STREAM-LIMIT-EXCEEDED")` |
253
+ | Writing to a stream already completed | `NcpError("NPS-CLIENT-CONFLICT")` |
254
+ | `seq` gap in received order | `NcpError("NCP-STREAM-SEQ-GAP")` |
255
+ | Outgoing window exhausted | `NcpError("NCP-STREAM-WINDOW-OVERFLOW")` |
256
+
257
+ Duplicate frames with a `seq` lower than `expectedSeq` are silently
258
+ ignored (idempotent).
259
+
260
+ ---
261
+
262
+ ## `NCP_ERROR_CODES`
263
+
264
+ Constant bundle of NCP-layer protocol codes (NPS-1 §6, §7.4).
265
+
266
+ ```typescript
267
+ import { NCP_ERROR_CODES } from "@labacacia/nps-sdk/ncp";
268
+
269
+ NCP_ERROR_CODES.NCP_ANCHOR_NOT_FOUND; // "NCP-ANCHOR-NOT-FOUND"
270
+ NCP_ERROR_CODES.NCP_STREAM_SEQ_GAP; // "NCP-STREAM-SEQ-GAP"
271
+ NCP_ERROR_CODES.NCP_VERSION_INCOMPATIBLE; // "NCP-VERSION-INCOMPATIBLE"
272
+ // …
273
+ ```
274
+
275
+ `NCP_FRAME_PARSE_ERROR` and `NCP_FRAME_INCOMPLETE` are implementation-only
276
+ codes not defined in the spec § 6; everything else is spec-canonical.