@labacacia/nps-sdk 1.0.0-alpha.3 → 1.0.0-alpha.5
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.
- package/CHANGELOG.cn.md +73 -0
- package/CHANGELOG.md +82 -0
- package/README.cn.md +17 -4
- package/README.md +17 -4
- package/dist/core/anchor-cache.js +104 -0
- package/dist/core/anchor-cache.js.map +1 -0
- package/dist/core/cache.js +80 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/canonical-json.js +44 -0
- package/dist/core/canonical-json.js.map +1 -0
- package/dist/core/codec.js +119 -0
- package/dist/core/codec.js.map +1 -0
- package/dist/core/codecs/index.js +6 -0
- package/dist/core/codecs/index.js.map +1 -0
- package/dist/core/codecs/ncp-codec.js +93 -0
- package/dist/core/codecs/ncp-codec.js.map +1 -0
- package/dist/core/codecs/tier1-json-codec.js +28 -0
- package/dist/core/codecs/tier1-json-codec.js.map +1 -0
- package/dist/core/codecs/tier2-msgpack-codec.js +26 -0
- package/dist/core/codecs/tier2-msgpack-codec.js.map +1 -0
- package/dist/core/crypto-provider.js +10 -0
- package/dist/core/crypto-provider.js.map +1 -0
- package/dist/core/exceptions.js +52 -0
- package/dist/core/exceptions.js.map +1 -0
- package/dist/core/frame-header.js +185 -0
- package/dist/core/frame-header.js.map +1 -0
- package/dist/core/frame-registry.js +63 -0
- package/dist/core/frame-registry.js.map +1 -0
- package/dist/core/frames.js +154 -0
- package/dist/core/frames.js.map +1 -0
- package/dist/core/index.js +21 -405
- package/dist/core/index.js.map +1 -1
- package/dist/core/registry.js +17 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/status-codes.d.ts +1 -0
- package/dist/core/status-codes.d.ts.map +1 -1
- package/dist/core/status-codes.js +39 -0
- package/dist/core/status-codes.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/ncp/frames/anchor-frame.js +54 -0
- package/dist/ncp/frames/anchor-frame.js.map +1 -0
- package/dist/ncp/frames/caps-frame.js +29 -0
- package/dist/ncp/frames/caps-frame.js.map +1 -0
- package/dist/ncp/frames/diff-frame.js +37 -0
- package/dist/ncp/frames/diff-frame.js.map +1 -0
- package/dist/ncp/frames/error-frame.js +13 -0
- package/dist/ncp/frames/error-frame.js.map +1 -0
- package/dist/ncp/frames/hello-frame.js +25 -0
- package/dist/ncp/frames/hello-frame.js.map +1 -0
- package/dist/ncp/frames/stream-frame.js +18 -0
- package/dist/ncp/frames/stream-frame.js.map +1 -0
- package/dist/ncp/frames.js +192 -0
- package/dist/ncp/frames.js.map +1 -0
- package/dist/ncp/handshake.js +80 -0
- package/dist/ncp/handshake.js.map +1 -0
- package/dist/ncp/index.d.ts +1 -0
- package/dist/ncp/index.d.ts.map +1 -1
- package/dist/ncp/index.js +13 -368
- package/dist/ncp/index.js.map +1 -1
- package/dist/ncp/ncp-error-codes.d.ts +1 -0
- package/dist/ncp/ncp-error-codes.d.ts.map +1 -1
- package/dist/ncp/ncp-error-codes.js +34 -0
- package/dist/ncp/ncp-error-codes.js.map +1 -0
- package/dist/ncp/ncp-patch-format.js +13 -0
- package/dist/ncp/ncp-patch-format.js.map +1 -0
- package/dist/ncp/preamble.d.ts +47 -0
- package/dist/ncp/preamble.d.ts.map +1 -0
- package/dist/ncp/preamble.js +74 -0
- package/dist/ncp/preamble.js.map +1 -0
- package/dist/ncp/registry.js +13 -0
- package/dist/ncp/registry.js.map +1 -0
- package/dist/ncp/stream-manager.js +163 -0
- package/dist/ncp/stream-manager.js.map +1 -0
- package/dist/ndp/dns-txt.d.ts +35 -0
- package/dist/ndp/dns-txt.d.ts.map +1 -0
- package/dist/ndp/dns-txt.js +67 -0
- package/dist/ndp/dns-txt.js.map +1 -0
- package/dist/ndp/frames.js +87 -0
- package/dist/ndp/frames.js.map +1 -0
- package/dist/ndp/index.d.ts +1 -0
- package/dist/ndp/index.d.ts.map +1 -1
- package/dist/ndp/index.js +7 -223
- package/dist/ndp/index.js.map +1 -1
- package/dist/ndp/ndp-registry.d.ts +2 -0
- package/dist/ndp/ndp-registry.d.ts.map +1 -1
- package/dist/ndp/ndp-registry.js +104 -0
- package/dist/ndp/ndp-registry.js.map +1 -0
- package/dist/ndp/registry.js +10 -0
- package/dist/ndp/registry.js.map +1 -0
- package/dist/ndp/validator.js +48 -0
- package/dist/ndp/validator.js.map +1 -0
- package/dist/nip/acme/client.d.ts +31 -0
- package/dist/nip/acme/client.d.ts.map +1 -0
- package/dist/nip/acme/client.js +136 -0
- package/dist/nip/acme/client.js.map +1 -0
- package/dist/nip/acme/index.d.ts +6 -0
- package/dist/nip/acme/index.d.ts.map +1 -0
- package/dist/nip/acme/index.js +8 -0
- package/dist/nip/acme/index.js.map +1 -0
- package/dist/nip/acme/jws.d.ts +31 -0
- package/dist/nip/acme/jws.d.ts.map +1 -0
- package/dist/nip/acme/jws.js +76 -0
- package/dist/nip/acme/jws.js.map +1 -0
- package/dist/nip/acme/messages.d.ts +71 -0
- package/dist/nip/acme/messages.d.ts.map +1 -0
- package/dist/nip/acme/messages.js +4 -0
- package/dist/nip/acme/messages.js.map +1 -0
- package/dist/nip/acme/server.d.ts +41 -0
- package/dist/nip/acme/server.d.ts.map +1 -0
- package/dist/nip/acme/server.js +458 -0
- package/dist/nip/acme/server.js.map +1 -0
- package/dist/nip/acme/wire.d.ts +19 -0
- package/dist/nip/acme/wire.d.ts.map +1 -0
- package/dist/nip/acme/wire.js +21 -0
- package/dist/nip/acme/wire.js.map +1 -0
- package/dist/nip/assurance-level.d.ts +19 -0
- package/dist/nip/assurance-level.d.ts.map +1 -0
- package/dist/nip/assurance-level.js +38 -0
- package/dist/nip/assurance-level.js.map +1 -0
- package/dist/nip/cert-format.d.ts +5 -0
- package/dist/nip/cert-format.d.ts.map +1 -0
- package/dist/nip/cert-format.js +6 -0
- package/dist/nip/cert-format.js.map +1 -0
- package/dist/nip/error-codes.d.ts +25 -0
- package/dist/nip/error-codes.d.ts.map +1 -0
- package/dist/nip/error-codes.js +32 -0
- package/dist/nip/error-codes.js.map +1 -0
- package/dist/nip/frames.d.ts +10 -1
- package/dist/nip/frames.d.ts.map +1 -1
- package/dist/nip/frames.js +106 -0
- package/dist/nip/frames.js.map +1 -0
- package/dist/nip/identity.js +94 -0
- package/dist/nip/identity.js.map +1 -0
- package/dist/nip/index.d.ts +6 -0
- package/dist/nip/index.d.ts.map +1 -1
- package/dist/nip/index.js +12 -187
- package/dist/nip/index.js.map +1 -1
- package/dist/nip/registry.js +10 -0
- package/dist/nip/registry.js.map +1 -0
- package/dist/nip/verifier.d.ts +23 -0
- package/dist/nip/verifier.d.ts.map +1 -0
- package/dist/nip/verifier.js +90 -0
- package/dist/nip/verifier.js.map +1 -0
- package/dist/nip/x509/builder.d.ts +35 -0
- package/dist/nip/x509/builder.d.ts.map +1 -0
- package/dist/nip/x509/builder.js +59 -0
- package/dist/nip/x509/builder.js.map +1 -0
- package/dist/nip/x509/index.d.ts +4 -0
- package/dist/nip/x509/index.d.ts.map +1 -0
- package/dist/nip/x509/index.js +6 -0
- package/dist/nip/x509/index.js.map +1 -0
- package/dist/nip/x509/oids.d.ts +17 -0
- package/dist/nip/x509/oids.d.ts.map +1 -0
- package/dist/nip/x509/oids.js +23 -0
- package/dist/nip/x509/oids.js.map +1 -0
- package/dist/nip/x509/verifier.d.ts +26 -0
- package/dist/nip/x509/verifier.d.ts.map +1 -0
- package/dist/nip/x509/verifier.js +171 -0
- package/dist/nip/x509/verifier.js.map +1 -0
- package/dist/nop/client.js +90 -0
- package/dist/nop/client.js.map +1 -0
- package/dist/nop/frames.js +148 -0
- package/dist/nop/frames.js.map +1 -0
- package/dist/nop/index.js +6 -789
- package/dist/nop/index.js.map +1 -1
- package/dist/nop/models.js +50 -0
- package/dist/nop/models.js.map +1 -0
- package/dist/nop/nop-types.js +44 -0
- package/dist/nop/nop-types.js.map +1 -0
- package/dist/nop/registry.js +11 -0
- package/dist/nop/registry.js.map +1 -0
- package/dist/nwp/client.js +101 -0
- package/dist/nwp/client.js.map +1 -0
- package/dist/nwp/error-codes.d.ts +42 -0
- package/dist/nwp/error-codes.d.ts.map +1 -0
- package/dist/nwp/error-codes.js +53 -0
- package/dist/nwp/error-codes.js.map +1 -0
- package/dist/nwp/frames.js +81 -0
- package/dist/nwp/frames.js.map +1 -0
- package/dist/nwp/index.d.ts +1 -0
- package/dist/nwp/index.d.ts.map +1 -1
- package/dist/nwp/index.js +6 -693
- package/dist/nwp/index.js.map +1 -1
- package/dist/nwp/registry.js +9 -0
- package/dist/nwp/registry.js.map +1 -0
- package/dist/setup.js +29 -0
- package/dist/setup.js.map +1 -0
- package/doc/nps-sdk.nip.cn.md +30 -0
- package/doc/nps-sdk.nip.md +30 -0
- package/doc/nps-sdk.nwp.cn.md +71 -0
- package/doc/nps-sdk.nwp.md +71 -0
- package/package.json +2 -1
- package/src/core/status-codes.ts +1 -0
- package/src/index.ts +1 -1
- package/src/ncp/index.ts +1 -0
- package/src/ncp/ncp-error-codes.ts +2 -0
- package/src/ncp/preamble.ts +79 -0
- package/src/ndp/dns-txt.ts +86 -0
- package/src/ndp/index.ts +1 -0
- package/src/ndp/ndp-registry.ts +34 -0
- package/src/nip/acme/client.ts +185 -0
- package/src/nip/acme/index.ts +8 -0
- package/src/nip/acme/jws.ts +109 -0
- package/src/nip/acme/messages.ts +85 -0
- package/src/nip/acme/server.ts +480 -0
- package/src/nip/acme/wire.ts +24 -0
- package/src/nip/assurance-level.ts +40 -0
- package/src/nip/cert-format.ts +9 -0
- package/src/nip/error-codes.ts +38 -0
- package/src/nip/frames.ts +35 -3
- package/src/nip/index.ts +8 -0
- package/src/nip/verifier.ts +122 -0
- package/src/nip/x509/builder.ts +91 -0
- package/src/nip/x509/index.ts +6 -0
- package/src/nip/x509/oids.ts +28 -0
- package/src/nip/x509/verifier.ts +214 -0
- package/src/nop/client.ts +1 -1
- package/src/nwp/client.ts +4 -4
- package/src/nwp/error-codes.ts +62 -0
- package/src/nwp/index.ts +1 -0
- package/tests/_rfc0002-keys.ts +57 -0
- package/tests/ncp/preamble.test.ts +93 -0
- package/tests/ndp.test.ts +106 -0
- package/tests/nip-acme-agent01.test.ts +192 -0
- package/tests/nip-x509.test.ts +280 -0
- package/dist/core/index.cjs +0 -452
- package/dist/core/index.cjs.map +0 -1
- package/dist/index.cjs +0 -8
- package/dist/index.cjs.map +0 -1
- package/dist/ncp/index.cjs +0 -388
- package/dist/ncp/index.cjs.map +0 -1
- package/dist/ndp/index.cjs +0 -252
- package/dist/ndp/index.cjs.map +0 -1
- package/dist/nip/index.cjs +0 -214
- package/dist/nip/index.cjs.map +0 -1
- package/dist/nop/index.cjs +0 -823
- package/dist/nop/index.cjs.map +0 -1
- package/dist/nwp/index.cjs +0 -720
- package/dist/nwp/index.cjs.map +0 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 LabAcacia / INNO LOTUS PTY LTD
|
|
3
|
+
//
|
|
4
|
+
// AnchorFrame (0x01) — Schema anchor for global reference
|
|
5
|
+
// NPS-1 §4.1
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
// canonicalize ships CJS with TS `export default` — NodeNext resolves as namespace
|
|
8
|
+
import canonicalizeDefault from "canonicalize";
|
|
9
|
+
const canonicalize = canonicalizeDefault;
|
|
10
|
+
import { NcpError } from "../../core/frame-header.js";
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Types
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
const VALID_FIELD_TYPES = [
|
|
15
|
+
"string", "uint64", "int64", "decimal", "bool",
|
|
16
|
+
"timestamp", "bytes", "object", "array",
|
|
17
|
+
];
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// anchor_id computation (RFC 8785 JCS + SHA-256)
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
/**
|
|
22
|
+
* Compute anchor_id from schema using RFC 8785 JCS canonicalization + SHA-256.
|
|
23
|
+
* Format: "sha256:{64 lowercase hex chars}"
|
|
24
|
+
*/
|
|
25
|
+
export function computeAnchorId(schema) {
|
|
26
|
+
const canonical = canonicalize(schema);
|
|
27
|
+
if (!canonical) {
|
|
28
|
+
throw new NcpError("NCP-ANCHOR-SCHEMA-INVALID", "Schema cannot be canonicalized");
|
|
29
|
+
}
|
|
30
|
+
const hash = createHash("sha256").update(canonical).digest("hex");
|
|
31
|
+
return `sha256:${hash}`;
|
|
32
|
+
}
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Validation
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
/**
|
|
37
|
+
* Validate an AnchorFrame.
|
|
38
|
+
* @throws {NcpError} NCP-ANCHOR-SCHEMA-INVALID if anchor_id doesn't match or schema is invalid.
|
|
39
|
+
*/
|
|
40
|
+
export function validateAnchorFrame(frame) {
|
|
41
|
+
// Validate schema field types
|
|
42
|
+
for (const field of frame.schema.fields) {
|
|
43
|
+
if (!VALID_FIELD_TYPES.includes(field.type)) {
|
|
44
|
+
throw new NcpError("NCP-ANCHOR-SCHEMA-INVALID", `Unsupported field type "${field.type}" for field "${field.name}". ` +
|
|
45
|
+
`Valid types: ${VALID_FIELD_TYPES.join(", ")}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Validate anchor_id matches computed hash
|
|
49
|
+
const expected = computeAnchorId(frame.schema);
|
|
50
|
+
if (frame.anchor_id !== expected) {
|
|
51
|
+
throw new NcpError("NCP-ANCHOR-SCHEMA-INVALID", `anchor_id mismatch: expected ${expected}, got ${frame.anchor_id}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=anchor-frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor-frame.js","sourceRoot":"","sources":["../../../src/ncp/frames/anchor-frame.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,oDAAoD;AACpD,EAAE;AACF,0DAA0D;AAC1D,aAAa;AAEb,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,mFAAmF;AACnF,OAAO,mBAAmB,MAAM,cAAc,CAAC;AAC/C,MAAM,YAAY,GAAG,mBAAwE,CAAC;AAC9F,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAEtD,8EAA8E;AAC9E,QAAQ;AACR,8EAA8E;AAE9E,MAAM,iBAAiB,GAAG;IACxB,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM;IAC9C,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO;CAC/B,CAAC;AAsBX,8EAA8E;AAC9E,iDAAiD;AACjD,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAAmB;IACjD,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,QAAQ,CAAC,2BAA2B,EAAE,gCAAgC,CAAC,CAAC;IACpF,CAAC;IACD,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAClE,OAAO,UAAU,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAkB;IACpD,8BAA8B;IAC9B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACxC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAuB,CAAC,EAAE,CAAC;YAC/D,MAAM,IAAI,QAAQ,CAChB,2BAA2B,EAC3B,2BAA2B,KAAK,CAAC,IAAI,gBAAgB,KAAK,CAAC,IAAI,KAAK;gBAClE,gBAAgB,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACjD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,2CAA2C;IAC3C,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,KAAK,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,IAAI,QAAQ,CAChB,2BAA2B,EAC3B,gCAAgC,QAAQ,SAAS,KAAK,CAAC,SAAS,EAAE,CACnE,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 LabAcacia / INNO LOTUS PTY LTD
|
|
3
|
+
//
|
|
4
|
+
// CapsFrame (0x04) — Capsule response envelope
|
|
5
|
+
// NPS-1 §4.4
|
|
6
|
+
import { NcpError } from "../../core/frame-header.js";
|
|
7
|
+
import { computeAnchorId, } from "./anchor-frame.js";
|
|
8
|
+
/**
|
|
9
|
+
* Validate a CapsFrame.
|
|
10
|
+
*
|
|
11
|
+
* Checks:
|
|
12
|
+
* - count matches data.length (NPS-CLIENT-BAD-FRAME)
|
|
13
|
+
* - if inline_anchor present, recomputes anchor_id and validates match (NCP-ANCHOR-SCHEMA-INVALID)
|
|
14
|
+
*
|
|
15
|
+
* @throws {NcpError} NPS-CLIENT-BAD-FRAME if count doesn't match data length.
|
|
16
|
+
* @throws {NcpError} NCP-ANCHOR-SCHEMA-INVALID if inline_anchor.anchor_id doesn't match schema.
|
|
17
|
+
*/
|
|
18
|
+
export function validateCapsFrame(frame) {
|
|
19
|
+
if (frame.count !== frame.data.length) {
|
|
20
|
+
throw new NcpError("NPS-CLIENT-BAD-FRAME", `CapsFrame count mismatch: count=${frame.count}, data.length=${frame.data.length}`);
|
|
21
|
+
}
|
|
22
|
+
if (frame.inline_anchor !== undefined) {
|
|
23
|
+
const computed = computeAnchorId(frame.inline_anchor.schema);
|
|
24
|
+
if (frame.inline_anchor.anchor_id !== computed) {
|
|
25
|
+
throw new NcpError("NCP-ANCHOR-SCHEMA-INVALID", `inline_anchor anchor_id mismatch: expected ${computed}, got ${frame.inline_anchor.anchor_id}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=caps-frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caps-frame.js","sourceRoot":"","sources":["../../../src/ncp/frames/caps-frame.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,oDAAoD;AACpD,EAAE;AACF,+CAA+C;AAC/C,aAAa;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EACL,eAAe,GAGhB,MAAM,mBAAmB,CAAC;AAoB3B;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAgB;IAChD,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACtC,MAAM,IAAI,QAAQ,CAChB,sBAAsB,EACtB,mCAAmC,KAAK,CAAC,KAAK,iBAAiB,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CACnF,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAC7D,IAAI,KAAK,CAAC,aAAa,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;YAC/C,MAAM,IAAI,QAAQ,CAChB,2BAA2B,EAC3B,8CAA8C,QAAQ,SAAS,KAAK,CAAC,aAAa,CAAC,SAAS,EAAE,CAC/F,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 LabAcacia / INNO LOTUS PTY LTD
|
|
3
|
+
//
|
|
4
|
+
// DiffFrame (0x02) — Incremental data patch
|
|
5
|
+
// NPS-1 §4.2
|
|
6
|
+
import { NcpError, EncodingTier } from "../../core/frame-header.js";
|
|
7
|
+
import { isValidPatchFormat } from "../ncp-patch-format.js";
|
|
8
|
+
/**
|
|
9
|
+
* Validate DiffFrame base_seq against current sequence.
|
|
10
|
+
* @throws {NcpError} NCP-STREAM-SEQ-GAP if sequences don't match.
|
|
11
|
+
*/
|
|
12
|
+
export function validateDiffSeq(frame, currentSeq) {
|
|
13
|
+
if (frame.base_seq !== currentSeq) {
|
|
14
|
+
throw new NcpError("NCP-STREAM-SEQ-GAP", `DiffFrame base_seq=${frame.base_seq} does not match current seq=${currentSeq}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Validate DiffFrame patch_format against the encoding tier.
|
|
19
|
+
*
|
|
20
|
+
* binary_bitset is only supported on Tier-2 (MsgPack) frames.
|
|
21
|
+
* Unknown patch_format values are also rejected.
|
|
22
|
+
*
|
|
23
|
+
* @throws {NcpError} NCP-DIFF-FORMAT-UNSUPPORTED if binary_bitset on non-Tier-2,
|
|
24
|
+
* or if patch_format is an unknown value.
|
|
25
|
+
*/
|
|
26
|
+
export function validateDiffFrame(frame, encodingTier) {
|
|
27
|
+
const fmt = frame.patch_format;
|
|
28
|
+
// Unknown patch_format
|
|
29
|
+
if (fmt !== undefined && !isValidPatchFormat(fmt)) {
|
|
30
|
+
throw new NcpError("NCP-DIFF-FORMAT-UNSUPPORTED", `Unknown patch_format "${String(fmt)}"`);
|
|
31
|
+
}
|
|
32
|
+
// binary_bitset requires Tier-2 MsgPack
|
|
33
|
+
if (fmt === "binary_bitset" && encodingTier !== EncodingTier.MsgPack) {
|
|
34
|
+
throw new NcpError("NCP-DIFF-FORMAT-UNSUPPORTED", "patch_format=binary_bitset requires Tier-2 MsgPack encoding");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=diff-frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-frame.js","sourceRoot":"","sources":["../../../src/ncp/frames/diff-frame.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,oDAAoD;AACpD,EAAE;AACF,4CAA4C;AAC5C,aAAa;AAEb,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAoB,MAAM,wBAAwB,CAAC;AAkB9E;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAgB,EAAE,UAAkB;IAClE,IAAI,KAAK,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;QAClC,MAAM,IAAI,QAAQ,CAChB,oBAAoB,EACpB,sBAAsB,KAAK,CAAC,QAAQ,+BAA+B,UAAU,EAAE,CAChF,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAgB,EAChB,YAAmC;IAEnC,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,CAAC;IAE/B,uBAAuB;IACvB,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,QAAQ,CAChB,6BAA6B,EAC7B,yBAAyB,MAAM,CAAC,GAAG,CAAC,GAAG,CACxC,CAAC;IACJ,CAAC;IAED,wCAAwC;IACxC,IAAI,GAAG,KAAK,eAAe,IAAI,YAAY,KAAK,YAAY,CAAC,OAAO,EAAE,CAAC;QACrE,MAAM,IAAI,QAAQ,CAChB,6BAA6B,EAC7B,6DAA6D,CAC9D,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 LabAcacia / INNO LOTUS PTY LTD
|
|
3
|
+
//
|
|
4
|
+
// ErrorFrame (0xFE) — Unified error frame for all NPS protocol layers
|
|
5
|
+
// NPS-1 §4.7
|
|
6
|
+
/** Type guard for ErrorFrame. */
|
|
7
|
+
export function isErrorFrame(obj) {
|
|
8
|
+
if (typeof obj !== "object" || obj === null)
|
|
9
|
+
return false;
|
|
10
|
+
const o = obj;
|
|
11
|
+
return o.frame === "0xFE" && typeof o.status === "string" && typeof o.error === "string";
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=error-frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-frame.js","sourceRoot":"","sources":["../../../src/ncp/frames/error-frame.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,oDAAoD;AACpD,EAAE;AACF,sEAAsE;AACtE,aAAa;AAgBb,iCAAiC;AACjC,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC1D,MAAM,CAAC,GAAG,GAA8B,CAAC;IACzC,OAAO,CAAC,CAAC,KAAK,KAAK,MAAM,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC;AAC3F,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 LabAcacia / INNO LOTUS PTY LTD
|
|
3
|
+
//
|
|
4
|
+
// HelloFrame (0x06) — Native-mode client handshake
|
|
5
|
+
// NPS-1 §4.6
|
|
6
|
+
import { NcpError } from "../../core/frame-header.js";
|
|
7
|
+
/**
|
|
8
|
+
* Validate a HelloFrame.
|
|
9
|
+
*
|
|
10
|
+
* Required fields: nps_version, supported_encodings (non-empty), supported_protocols (non-empty).
|
|
11
|
+
*
|
|
12
|
+
* @throws {NcpError} NPS-CLIENT-BAD-FRAME if any required field is missing or empty.
|
|
13
|
+
*/
|
|
14
|
+
export function validateHelloFrame(frame) {
|
|
15
|
+
if (!frame.nps_version) {
|
|
16
|
+
throw new NcpError("NPS-CLIENT-BAD-FRAME", "HelloFrame missing required field: nps_version");
|
|
17
|
+
}
|
|
18
|
+
if (!frame.supported_encodings || frame.supported_encodings.length === 0) {
|
|
19
|
+
throw new NcpError("NPS-CLIENT-BAD-FRAME", "HelloFrame missing required field: supported_encodings (must be non-empty)");
|
|
20
|
+
}
|
|
21
|
+
if (!frame.supported_protocols || frame.supported_protocols.length === 0) {
|
|
22
|
+
throw new NcpError("NPS-CLIENT-BAD-FRAME", "HelloFrame missing required field: supported_protocols (must be non-empty)");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=hello-frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hello-frame.js","sourceRoot":"","sources":["../../../src/ncp/frames/hello-frame.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,oDAAoD;AACpD,EAAE;AACF,mDAAmD;AACnD,aAAa;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAetD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAiB;IAClD,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QACvB,MAAM,IAAI,QAAQ,CAChB,sBAAsB,EACtB,gDAAgD,CACjD,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,mBAAmB,IAAI,KAAK,CAAC,mBAAmB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzE,MAAM,IAAI,QAAQ,CAChB,sBAAsB,EACtB,4EAA4E,CAC7E,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,mBAAmB,IAAI,KAAK,CAAC,mBAAmB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzE,MAAM,IAAI,QAAQ,CAChB,sBAAsB,EACtB,4EAA4E,CAC7E,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 LabAcacia / INNO LOTUS PTY LTD
|
|
3
|
+
//
|
|
4
|
+
// StreamFrame (0x03) — Streaming data chunks with flow control
|
|
5
|
+
// NPS-1 §4.3
|
|
6
|
+
import { NcpError } from "../../core/frame-header.js";
|
|
7
|
+
// UUID v4 format: xxxxxxxx-xxxx-4xxx-[89ab]xxx-xxxxxxxxxxxx
|
|
8
|
+
const 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;
|
|
9
|
+
/**
|
|
10
|
+
* Validate stream_id is a valid UUID v4.
|
|
11
|
+
* @throws {NcpError} NPS-CLIENT-BAD-FRAME if stream_id is not a valid UUID v4.
|
|
12
|
+
*/
|
|
13
|
+
export function validateStreamFrame(frame) {
|
|
14
|
+
if (!UUID_V4_RE.test(frame.stream_id)) {
|
|
15
|
+
throw new NcpError("NPS-CLIENT-BAD-FRAME", `stream_id "${frame.stream_id}" is not a valid UUID v4`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=stream-frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-frame.js","sourceRoot":"","sources":["../../../src/ncp/frames/stream-frame.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,oDAAoD;AACpD,EAAE;AACF,+DAA+D;AAC/D,aAAa;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAatD,4DAA4D;AAC5D,MAAM,UAAU,GACd,wEAAwE,CAAC;AAE3E;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAkB;IACpD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,QAAQ,CAChB,sBAAsB,EACtB,cAAc,KAAK,CAAC,SAAS,0BAA0B,CACxD,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// Copyright 2026 INNO LOTUS PTY LTD
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { EncodingTier, FrameType } from "../core/frames.js";
|
|
4
|
+
// ── AnchorFrame ───────────────────────────────────────────────────────────────
|
|
5
|
+
export class AnchorFrame {
|
|
6
|
+
anchorId;
|
|
7
|
+
schema;
|
|
8
|
+
ttl;
|
|
9
|
+
frameType = FrameType.ANCHOR;
|
|
10
|
+
preferredTier = EncodingTier.MSGPACK;
|
|
11
|
+
constructor(anchorId, schema, ttl = 3600) {
|
|
12
|
+
this.anchorId = anchorId;
|
|
13
|
+
this.schema = schema;
|
|
14
|
+
this.ttl = ttl;
|
|
15
|
+
}
|
|
16
|
+
toDict() {
|
|
17
|
+
return {
|
|
18
|
+
anchor_id: this.anchorId,
|
|
19
|
+
schema: { fields: this.schema.fields.map((f) => ({ ...f })) },
|
|
20
|
+
ttl: this.ttl,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
static fromDict(data) {
|
|
24
|
+
const schemaRaw = data["schema"];
|
|
25
|
+
return new AnchorFrame(data["anchor_id"], { fields: schemaRaw.fields }, data["ttl"] ?? 3600);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// ── DiffFrame ─────────────────────────────────────────────────────────────────
|
|
29
|
+
export class DiffFrame {
|
|
30
|
+
anchorRef;
|
|
31
|
+
baseSeq;
|
|
32
|
+
patch;
|
|
33
|
+
entityId;
|
|
34
|
+
frameType = FrameType.DIFF;
|
|
35
|
+
preferredTier = EncodingTier.MSGPACK;
|
|
36
|
+
constructor(anchorRef, baseSeq, patch, entityId) {
|
|
37
|
+
this.anchorRef = anchorRef;
|
|
38
|
+
this.baseSeq = baseSeq;
|
|
39
|
+
this.patch = patch;
|
|
40
|
+
this.entityId = entityId;
|
|
41
|
+
}
|
|
42
|
+
toDict() {
|
|
43
|
+
return {
|
|
44
|
+
anchor_ref: this.anchorRef,
|
|
45
|
+
base_seq: this.baseSeq,
|
|
46
|
+
patch: this.patch.map((p) => ({ ...p })),
|
|
47
|
+
entity_id: this.entityId ?? null,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
static fromDict(data) {
|
|
51
|
+
return new DiffFrame(data["anchor_ref"], data["base_seq"], data["patch"], data["entity_id"] ?? undefined);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// ── StreamFrame ───────────────────────────────────────────────────────────────
|
|
55
|
+
export class StreamFrame {
|
|
56
|
+
streamId;
|
|
57
|
+
seq;
|
|
58
|
+
isLast;
|
|
59
|
+
data;
|
|
60
|
+
anchorRef;
|
|
61
|
+
windowSize;
|
|
62
|
+
frameType = FrameType.STREAM;
|
|
63
|
+
preferredTier = EncodingTier.MSGPACK;
|
|
64
|
+
constructor(streamId, seq, isLast, data, anchorRef, windowSize) {
|
|
65
|
+
this.streamId = streamId;
|
|
66
|
+
this.seq = seq;
|
|
67
|
+
this.isLast = isLast;
|
|
68
|
+
this.data = data;
|
|
69
|
+
this.anchorRef = anchorRef;
|
|
70
|
+
this.windowSize = windowSize;
|
|
71
|
+
}
|
|
72
|
+
toDict() {
|
|
73
|
+
return {
|
|
74
|
+
stream_id: this.streamId,
|
|
75
|
+
seq: this.seq,
|
|
76
|
+
is_last: this.isLast,
|
|
77
|
+
data: this.data,
|
|
78
|
+
anchor_ref: this.anchorRef ?? null,
|
|
79
|
+
window_size: this.windowSize ?? null,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
static fromDict(data) {
|
|
83
|
+
return new StreamFrame(data["stream_id"], data["seq"], data["is_last"], data["data"], data["anchor_ref"] ?? undefined, data["window_size"] ?? undefined);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// ── CapsFrame ─────────────────────────────────────────────────────────────────
|
|
87
|
+
export class CapsFrame {
|
|
88
|
+
anchorRef;
|
|
89
|
+
count;
|
|
90
|
+
data;
|
|
91
|
+
nextCursor;
|
|
92
|
+
tokenEst;
|
|
93
|
+
cached;
|
|
94
|
+
tokenizerUsed;
|
|
95
|
+
frameType = FrameType.CAPS;
|
|
96
|
+
preferredTier = EncodingTier.MSGPACK;
|
|
97
|
+
constructor(anchorRef, count, data, nextCursor, tokenEst, cached, tokenizerUsed) {
|
|
98
|
+
this.anchorRef = anchorRef;
|
|
99
|
+
this.count = count;
|
|
100
|
+
this.data = data;
|
|
101
|
+
this.nextCursor = nextCursor;
|
|
102
|
+
this.tokenEst = tokenEst;
|
|
103
|
+
this.cached = cached;
|
|
104
|
+
this.tokenizerUsed = tokenizerUsed;
|
|
105
|
+
}
|
|
106
|
+
toDict() {
|
|
107
|
+
return {
|
|
108
|
+
anchor_ref: this.anchorRef,
|
|
109
|
+
count: this.count,
|
|
110
|
+
data: this.data,
|
|
111
|
+
next_cursor: this.nextCursor ?? null,
|
|
112
|
+
token_est: this.tokenEst ?? null,
|
|
113
|
+
cached: this.cached ?? null,
|
|
114
|
+
tokenizer_used: this.tokenizerUsed ?? null,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
static fromDict(data) {
|
|
118
|
+
return new CapsFrame(data["anchor_ref"], data["count"], data["data"], data["next_cursor"] ?? undefined, data["token_est"] ?? undefined, data["cached"] ?? undefined, data["tokenizer_used"] ?? undefined);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// ── ErrorFrame ────────────────────────────────────────────────────────────────
|
|
122
|
+
export class ErrorFrame {
|
|
123
|
+
status;
|
|
124
|
+
error;
|
|
125
|
+
message;
|
|
126
|
+
details;
|
|
127
|
+
frameType = FrameType.ERROR;
|
|
128
|
+
preferredTier = EncodingTier.MSGPACK;
|
|
129
|
+
constructor(status, error, message, details) {
|
|
130
|
+
this.status = status;
|
|
131
|
+
this.error = error;
|
|
132
|
+
this.message = message;
|
|
133
|
+
this.details = details;
|
|
134
|
+
}
|
|
135
|
+
toDict() {
|
|
136
|
+
return {
|
|
137
|
+
status: this.status,
|
|
138
|
+
error: this.error,
|
|
139
|
+
message: this.message ?? null,
|
|
140
|
+
details: this.details ?? null,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
static fromDict(data) {
|
|
144
|
+
return new ErrorFrame(data["status"], data["error"], data["message"] ?? undefined, data["details"] ?? undefined);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// ── HelloFrame ────────────────────────────────────────────────────────────────
|
|
148
|
+
// NPS-1 §4.6 — Native-mode handshake (0x06). Always Tier-1 JSON: encoding
|
|
149
|
+
// is not yet negotiated when this frame is sent.
|
|
150
|
+
export class HelloFrame {
|
|
151
|
+
npsVersion;
|
|
152
|
+
supportedEncodings;
|
|
153
|
+
supportedProtocols;
|
|
154
|
+
minVersion;
|
|
155
|
+
agentId;
|
|
156
|
+
maxFramePayload;
|
|
157
|
+
extSupport;
|
|
158
|
+
maxConcurrentStreams;
|
|
159
|
+
e2eEncAlgorithms;
|
|
160
|
+
frameType = FrameType.HELLO;
|
|
161
|
+
preferredTier = EncodingTier.JSON;
|
|
162
|
+
static DEFAULT_MAX_FRAME_PAYLOAD = 0xFFFF;
|
|
163
|
+
static DEFAULT_MAX_CONCURRENT_STREAMS = 32;
|
|
164
|
+
constructor(npsVersion, supportedEncodings, supportedProtocols, minVersion, agentId, maxFramePayload = HelloFrame.DEFAULT_MAX_FRAME_PAYLOAD, extSupport = false, maxConcurrentStreams = HelloFrame.DEFAULT_MAX_CONCURRENT_STREAMS, e2eEncAlgorithms) {
|
|
165
|
+
this.npsVersion = npsVersion;
|
|
166
|
+
this.supportedEncodings = supportedEncodings;
|
|
167
|
+
this.supportedProtocols = supportedProtocols;
|
|
168
|
+
this.minVersion = minVersion;
|
|
169
|
+
this.agentId = agentId;
|
|
170
|
+
this.maxFramePayload = maxFramePayload;
|
|
171
|
+
this.extSupport = extSupport;
|
|
172
|
+
this.maxConcurrentStreams = maxConcurrentStreams;
|
|
173
|
+
this.e2eEncAlgorithms = e2eEncAlgorithms;
|
|
174
|
+
}
|
|
175
|
+
toDict() {
|
|
176
|
+
return {
|
|
177
|
+
nps_version: this.npsVersion,
|
|
178
|
+
supported_encodings: [...this.supportedEncodings],
|
|
179
|
+
supported_protocols: [...this.supportedProtocols],
|
|
180
|
+
min_version: this.minVersion ?? null,
|
|
181
|
+
agent_id: this.agentId ?? null,
|
|
182
|
+
max_frame_payload: this.maxFramePayload,
|
|
183
|
+
ext_support: this.extSupport,
|
|
184
|
+
max_concurrent_streams: this.maxConcurrentStreams,
|
|
185
|
+
e2e_enc_algorithms: this.e2eEncAlgorithms ? [...this.e2eEncAlgorithms] : null,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
static fromDict(data) {
|
|
189
|
+
return new HelloFrame(data["nps_version"], data["supported_encodings"] ?? [], data["supported_protocols"] ?? [], data["min_version"] ?? undefined, data["agent_id"] ?? undefined, data["max_frame_payload"] ?? HelloFrame.DEFAULT_MAX_FRAME_PAYLOAD, data["ext_support"] ?? false, data["max_concurrent_streams"] ?? HelloFrame.DEFAULT_MAX_CONCURRENT_STREAMS, data["e2e_enc_algorithms"] ?? undefined);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=frames.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frames.js","sourceRoot":"","sources":["../../src/ncp/frames.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) 2026 LabAcacia / INNO LOTUS PTY LTD
|
|
3
|
+
//
|
|
4
|
+
// Handshake — Version negotiation and encoding negotiation
|
|
5
|
+
// NPS-1 §2.6
|
|
6
|
+
/**
|
|
7
|
+
* Parse a "major.minor" (optionally "major.minor.patch") version string into a
|
|
8
|
+
* tuple of numeric components. Invalid parts become NaN which makes subsequent
|
|
9
|
+
* comparisons return false in both directions (safe failure).
|
|
10
|
+
*/
|
|
11
|
+
function parseVersion(v) {
|
|
12
|
+
return v.split(".").map((p) => Number.parseInt(p, 10));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Numeric component-wise comparison of two version strings.
|
|
16
|
+
* Returns negative if a < b, zero if equal, positive if a > b.
|
|
17
|
+
* Avoids the lexicographic pitfall where "0.9" > "0.10".
|
|
18
|
+
*/
|
|
19
|
+
function compareVersions(a, b) {
|
|
20
|
+
const partsA = parseVersion(a);
|
|
21
|
+
const partsB = parseVersion(b);
|
|
22
|
+
const len = Math.max(partsA.length, partsB.length);
|
|
23
|
+
for (let i = 0; i < len; i += 1) {
|
|
24
|
+
const x = partsA[i] ?? 0;
|
|
25
|
+
const y = partsB[i] ?? 0;
|
|
26
|
+
if (x !== y)
|
|
27
|
+
return x - y;
|
|
28
|
+
}
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Negotiate the session NPS version between client and server.
|
|
33
|
+
*
|
|
34
|
+
* Session version = numeric min of client.nps_version and server.nps_version
|
|
35
|
+
* (component-wise — "0.9" < "0.10" < "1.0").
|
|
36
|
+
* If the effective client minimum (min_version ?? nps_version) > server.nps_version,
|
|
37
|
+
* the versions are incompatible.
|
|
38
|
+
*
|
|
39
|
+
* Spec: NPS-1 §2.6
|
|
40
|
+
*/
|
|
41
|
+
export function negotiateVersion(client, server) {
|
|
42
|
+
const clientMin = client.min_version ?? client.nps_version;
|
|
43
|
+
const serverVersion = server.nps_version;
|
|
44
|
+
if (compareVersions(clientMin, serverVersion) > 0) {
|
|
45
|
+
return {
|
|
46
|
+
session_version: serverVersion,
|
|
47
|
+
compatible: false,
|
|
48
|
+
error_code: "NCP-VERSION-INCOMPATIBLE",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// Session version = component-wise min of client.nps_version and server.nps_version
|
|
52
|
+
const sessionVersion = compareVersions(client.nps_version, serverVersion) <= 0
|
|
53
|
+
? client.nps_version
|
|
54
|
+
: serverVersion;
|
|
55
|
+
return { session_version: sessionVersion, compatible: true };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Negotiate the encoding between client and server preferred lists.
|
|
59
|
+
*
|
|
60
|
+
* Returns the first mutually supported encoding, preferring "msgpack" over "json".
|
|
61
|
+
* Returns null if there is no intersection.
|
|
62
|
+
*/
|
|
63
|
+
export function negotiateEncoding(client, server) {
|
|
64
|
+
const serverSet = new Set(server);
|
|
65
|
+
// Prefer msgpack over json (and over any other encoding)
|
|
66
|
+
if (client.includes("msgpack") && serverSet.has("msgpack")) {
|
|
67
|
+
return { encoding: "msgpack" };
|
|
68
|
+
}
|
|
69
|
+
if (client.includes("json") && serverSet.has("json")) {
|
|
70
|
+
return { encoding: "json" };
|
|
71
|
+
}
|
|
72
|
+
// Fall back to first intersection in client-preference order
|
|
73
|
+
for (const enc of client) {
|
|
74
|
+
if (serverSet.has(enc)) {
|
|
75
|
+
return { encoding: enc };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { encoding: null };
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=handshake.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handshake.js","sourceRoot":"","sources":["../../src/ncp/handshake.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,oDAAoD;AACpD,EAAE;AACF,2DAA2D;AAC3D,aAAa;AAEb;;;;GAIG;AACH,SAAS,YAAY,CAAC,CAAS;IAC7B,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AACzD,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,CAAS,EAAE,CAAS;IAC3C,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAqD,EACrD,MAA+B;IAE/B,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,CAAC;IAC3D,MAAM,aAAa,GAAG,MAAM,CAAC,WAAW,CAAC;IAEzC,IAAI,eAAe,CAAC,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QAClD,OAAO;YACL,eAAe,EAAE,aAAa;YAC9B,UAAU,EAAE,KAAK;YACjB,UAAU,EAAE,0BAA0B;SACvC,CAAC;IACJ,CAAC;IAED,oFAAoF;IACpF,MAAM,cAAc,GAClB,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,IAAI,CAAC;QACrD,CAAC,CAAC,MAAM,CAAC,WAAW;QACpB,CAAC,CAAC,aAAa,CAAC;IAEpB,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAC/D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAgB,EAChB,MAAgB;IAEhB,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAElC,yDAAyD;IACzD,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IACjC,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAC9B,CAAC;IAED,6DAA6D;IAC7D,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC"}
|
package/dist/ncp/index.d.ts
CHANGED
package/dist/ncp/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ncp/index.ts"],"names":[],"mappings":"AAEA,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ncp/index.ts"],"names":[],"mappings":"AAEA,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC"}
|