pi-cursor-sdk 0.1.62 → 0.2.0
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.md +23 -0
- package/README.md +5 -5
- package/docs/cursor-live-smoke-checklist.md +4 -4
- package/docs/cursor-model-ux-spec.md +5 -3
- package/docs/cursor-native-tool-visual-audit.md +1 -1
- package/docs/cursor-testing-lessons.md +1 -1
- package/docs/platform-smoke.md +3 -3
- package/node_modules/fast-uri/index.js +37 -1
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/fast-uri/test/security.test.js +136 -0
- package/node_modules/hono/dist/cjs/context.js +28 -13
- package/node_modules/hono/dist/cjs/helper/proxy/index.js +4 -0
- package/node_modules/hono/dist/cjs/helper/streaming/sse.js +1 -1
- package/node_modules/hono/dist/cjs/hono-base.js +3 -2
- package/node_modules/hono/dist/cjs/jsx/base.js +27 -23
- package/node_modules/hono/dist/cjs/jsx/hooks/index.js +16 -13
- package/node_modules/hono/dist/cjs/middleware/cache/index.js +103 -8
- package/node_modules/hono/dist/cjs/middleware/compress/index.js +5 -0
- package/node_modules/hono/dist/cjs/middleware/cors/index.js +2 -2
- package/node_modules/hono/dist/cjs/middleware/etag/index.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/jwk/jwk.js +9 -4
- package/node_modules/hono/dist/cjs/middleware/jwt/jwt.js +9 -4
- package/node_modules/hono/dist/cjs/middleware/language/language.js +10 -6
- package/node_modules/hono/dist/cjs/middleware/method-not-allowed/index.js +90 -0
- package/node_modules/hono/dist/cjs/middleware/secure-headers/secure-headers.js +10 -4
- package/node_modules/hono/dist/cjs/request.js +7 -9
- package/node_modules/hono/dist/cjs/router/reg-exp-router/node.js +55 -56
- package/node_modules/hono/dist/cjs/router/reg-exp-router/router.js +64 -85
- package/node_modules/hono/dist/cjs/router/reg-exp-router/trie.js +13 -5
- package/node_modules/hono/dist/cjs/router.js +1 -1
- package/node_modules/hono/dist/cjs/utils/accept.js +1 -1
- package/node_modules/hono/dist/cjs/utils/cookie.js +3 -2
- package/node_modules/hono/dist/cjs/utils/url.js +8 -8
- package/node_modules/hono/dist/context.js +28 -13
- package/node_modules/hono/dist/helper/proxy/index.js +4 -0
- package/node_modules/hono/dist/helper/streaming/sse.js +1 -1
- package/node_modules/hono/dist/hono-base.js +3 -2
- package/node_modules/hono/dist/jsx/base.js +27 -23
- package/node_modules/hono/dist/jsx/hooks/index.js +16 -13
- package/node_modules/hono/dist/middleware/cache/index.js +103 -8
- package/node_modules/hono/dist/middleware/compress/index.js +5 -0
- package/node_modules/hono/dist/middleware/cors/index.js +2 -2
- package/node_modules/hono/dist/middleware/etag/index.js +1 -1
- package/node_modules/hono/dist/middleware/jwk/jwk.js +9 -4
- package/node_modules/hono/dist/middleware/jwt/jwt.js +9 -4
- package/node_modules/hono/dist/middleware/language/language.js +10 -6
- package/node_modules/hono/dist/middleware/method-not-allowed/index.js +68 -0
- package/node_modules/hono/dist/middleware/secure-headers/secure-headers.js +10 -4
- package/node_modules/hono/dist/request.js +8 -10
- package/node_modules/hono/dist/router/reg-exp-router/node.js +55 -56
- package/node_modules/hono/dist/router/reg-exp-router/router.js +64 -85
- package/node_modules/hono/dist/router/reg-exp-router/trie.js +13 -5
- package/node_modules/hono/dist/router.js +1 -1
- package/node_modules/hono/dist/types/adapter/aws-lambda/types.d.ts +9 -0
- package/node_modules/hono/dist/types/client/types.d.ts +1 -1
- package/node_modules/hono/dist/types/hono-base.d.ts +4 -3
- package/node_modules/hono/dist/types/jsx/base.d.ts +4 -2
- package/node_modules/hono/dist/types/jsx/dom/index.d.ts +5 -5
- package/node_modules/hono/dist/types/jsx/dom/intrinsic-element/components.d.ts +2 -2
- package/node_modules/hono/dist/types/jsx/dom/server.d.ts +5 -5
- package/node_modules/hono/dist/types/jsx/hooks/index.d.ts +8 -6
- package/node_modules/hono/dist/types/jsx/index.d.ts +5 -5
- package/node_modules/hono/dist/types/middleware/cache/index.d.ts +6 -4
- package/node_modules/hono/dist/types/middleware/cors/index.d.ts +1 -1
- package/node_modules/hono/dist/types/middleware/jsx-renderer/index.d.ts +2 -2
- package/node_modules/hono/dist/types/middleware/jwk/jwk.d.ts +2 -0
- package/node_modules/hono/dist/types/middleware/jwt/jwt.d.ts +2 -0
- package/node_modules/hono/dist/types/middleware/method-not-allowed/index.d.ts +49 -0
- package/node_modules/hono/dist/types/router/reg-exp-router/node.d.ts +1 -1
- package/node_modules/hono/dist/types/router/reg-exp-router/trie.d.ts +2 -1
- package/node_modules/hono/dist/types/router.d.ts +1 -1
- package/node_modules/hono/dist/types/utils/headers.d.ts +2 -2
- package/node_modules/hono/dist/types/utils/url.d.ts +1 -0
- package/node_modules/hono/dist/utils/accept.js +1 -1
- package/node_modules/hono/dist/utils/cookie.js +4 -3
- package/node_modules/hono/dist/utils/url.js +6 -7
- package/node_modules/hono/package.json +10 -3
- package/node_modules/ip-address/README.md +146 -126
- package/node_modules/ip-address/dist/common.d.ts +29 -0
- package/node_modules/ip-address/dist/common.js +44 -5
- package/node_modules/ip-address/dist/common.js.map +1 -1
- package/node_modules/ip-address/dist/ipv4.d.ts +8 -1
- package/node_modules/ip-address/dist/ipv4.js +24 -20
- package/node_modules/ip-address/dist/ipv4.js.map +1 -1
- package/node_modules/ip-address/dist/ipv6.d.ts +68 -3
- package/node_modules/ip-address/dist/ipv6.js +180 -53
- package/node_modules/ip-address/dist/ipv6.js.map +1 -1
- package/node_modules/ip-address/dist/v4/constants.js +5 -1
- package/node_modules/ip-address/dist/v4/constants.js.map +1 -1
- package/node_modules/ip-address/dist/v6/constants.js +3 -2
- package/node_modules/ip-address/dist/v6/constants.js.map +1 -1
- package/node_modules/ip-address/package.json +6 -4
- package/package.json +5 -5
- package/scripts/platform-smoke/live-suite-runner.mjs +15 -39
- package/scripts/platform-smoke/platform-build-windows.ps1 +1 -1
- package/scripts/platform-smoke/scenarios.mjs +1 -1
- package/scripts/platform-smoke.mjs +5 -5
- package/scripts/refresh-cursor-model-snapshots.mjs +16 -7
- package/shared/cursor-model-selection-identities.d.mts +21 -0
- package/shared/cursor-model-selection-identities.mjs +95 -0
- package/src/bundled-context-windows.ts +18 -12
- package/src/context.ts +1 -1
- package/src/cursor-context-tools.ts +1 -1
- package/src/cursor-display-only-trace.ts +1 -1
- package/src/cursor-fallback-models.generated.ts +875 -361
- package/src/cursor-live-run-accounting.ts +1 -1
- package/src/cursor-live-run-coordinator.ts +1 -1
- package/src/cursor-native-replay-routing.ts +1 -1
- package/src/cursor-partial-content-emitter.ts +1 -1
- package/src/cursor-pi-tool-bridge-mcp.ts +1 -1
- package/src/cursor-pi-tool-bridge-run.ts +1 -1
- package/src/cursor-pi-tool-bridge-types.ts +1 -1
- package/src/cursor-provider-lazy.ts +1 -1
- package/src/cursor-provider-live-run-drain.ts +1 -1
- package/src/cursor-provider-overflow.ts +1 -1
- package/src/cursor-provider-run-finalizer.ts +1 -1
- package/src/cursor-provider-turn-coordinator.ts +1 -1
- package/src/cursor-provider-turn-lifecycle-emitter.ts +1 -1
- package/src/cursor-provider-turn-prepare.ts +1 -1
- package/src/cursor-provider-turn-types.ts +1 -1
- package/src/cursor-provider.ts +1 -1
- package/src/cursor-run-final-text.ts +1 -1
- package/src/cursor-sdk-event-debug.ts +1 -1
- package/src/cursor-session-agent.ts +1 -1
- package/src/cursor-session-send-policy.ts +1 -1
- package/src/cursor-usage-accounting.ts +1 -1
- package/src/model-discovery.ts +32 -89
- package/node_modules/cross-spawn/node_modules/which/CHANGELOG.md +0 -166
|
@@ -73,7 +73,6 @@ function paddedHex(octet) {
|
|
|
73
73
|
return parseInt(octet, 16).toString(16).padStart(4, '0');
|
|
74
74
|
}
|
|
75
75
|
function unsignByte(b) {
|
|
76
|
-
// eslint-disable-next-line no-bitwise
|
|
77
76
|
return b & 0xff;
|
|
78
77
|
}
|
|
79
78
|
/**
|
|
@@ -97,6 +96,13 @@ class Address6 {
|
|
|
97
96
|
* @returns {boolean}
|
|
98
97
|
*/
|
|
99
98
|
this.isInSubnet = common.isInSubnet;
|
|
99
|
+
/**
|
|
100
|
+
* Returns true if this address's host bits fall inside the given subnet,
|
|
101
|
+
* ignoring this address's own subnet mask. See
|
|
102
|
+
* {@link common.isHostInSubnet}.
|
|
103
|
+
* @returns {boolean}
|
|
104
|
+
*/
|
|
105
|
+
this.isHostInSubnet = common.isHostInSubnet;
|
|
100
106
|
/**
|
|
101
107
|
* Returns true if the address is correct, false otherwise
|
|
102
108
|
* @returns {boolean}
|
|
@@ -121,7 +127,10 @@ class Address6 {
|
|
|
121
127
|
}
|
|
122
128
|
address = address.replace(constants6.RE_SUBNET_STRING, '');
|
|
123
129
|
}
|
|
124
|
-
|
|
130
|
+
// RE_SUBNET_STRING anchors on the end of the address, so it strips only
|
|
131
|
+
// the trailing suffix. A second one left behind (`::/0/1`) is malformed
|
|
132
|
+
// and must be rejected rather than parsed as an address group.
|
|
133
|
+
if (/\//.test(address)) {
|
|
125
134
|
throw new address_error_1.AddressError('Invalid subnet mask.');
|
|
126
135
|
}
|
|
127
136
|
const zone = constants6.RE_ZONE_STRING.exec(address);
|
|
@@ -145,7 +154,7 @@ class Address6 {
|
|
|
145
154
|
new Address6(address);
|
|
146
155
|
return true;
|
|
147
156
|
}
|
|
148
|
-
catch
|
|
157
|
+
catch {
|
|
149
158
|
return false;
|
|
150
159
|
}
|
|
151
160
|
}
|
|
@@ -160,7 +169,7 @@ class Address6 {
|
|
|
160
169
|
* address.correctForm(); // '::e8:d4a5:1000'
|
|
161
170
|
*/
|
|
162
171
|
static fromBigInt(bigInt) {
|
|
163
|
-
if (bigInt <
|
|
172
|
+
if (bigInt < BigInt(0) || bigInt > (BigInt(1) << BigInt(constants6.BITS)) - BigInt(1)) {
|
|
164
173
|
throw new address_error_1.AddressError('IPv6 BigInt must be in the range 0 to 2**128 - 1');
|
|
165
174
|
}
|
|
166
175
|
const hex = bigInt.toString(16).padStart(32, '0');
|
|
@@ -181,12 +190,15 @@ class Address6 {
|
|
|
181
190
|
* addressAndPort.port; // 8080
|
|
182
191
|
*/
|
|
183
192
|
static fromURL(url) {
|
|
193
|
+
var _a;
|
|
184
194
|
let host;
|
|
185
195
|
let port = null;
|
|
186
196
|
let result;
|
|
197
|
+
// Remove the protocol prefix, if any
|
|
198
|
+
const stripped = url.replace(/^[a-z][a-z0-9+.-]*:\/\//i, '');
|
|
187
199
|
// If we have brackets parse them and find a port
|
|
188
|
-
if (
|
|
189
|
-
result = constants6.RE_URL_WITH_PORT.exec(
|
|
200
|
+
if (stripped.indexOf('[') !== -1 && stripped.indexOf(']:') !== -1) {
|
|
201
|
+
result = constants6.RE_URL_WITH_PORT.exec(stripped);
|
|
190
202
|
if (result === null) {
|
|
191
203
|
return {
|
|
192
204
|
error: 'failed to parse address with port',
|
|
@@ -196,13 +208,9 @@ class Address6 {
|
|
|
196
208
|
}
|
|
197
209
|
host = result[1];
|
|
198
210
|
port = result[2];
|
|
199
|
-
// If there's a URL extract the address
|
|
200
211
|
}
|
|
201
|
-
else
|
|
202
|
-
|
|
203
|
-
url = url.replace(/^[a-z0-9]+:\/\//, '');
|
|
204
|
-
// Parse the address
|
|
205
|
-
result = constants6.RE_URL.exec(url);
|
|
212
|
+
else {
|
|
213
|
+
result = constants6.RE_URL.exec(stripped);
|
|
206
214
|
if (result === null) {
|
|
207
215
|
return {
|
|
208
216
|
error: 'failed to parse address from URL',
|
|
@@ -210,17 +218,13 @@ class Address6 {
|
|
|
210
218
|
port: null,
|
|
211
219
|
};
|
|
212
220
|
}
|
|
213
|
-
host = result[1];
|
|
214
|
-
// Otherwise just assign the URL to the host and let the library parse it
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
host = url;
|
|
221
|
+
host = (_a = result[1]) !== null && _a !== void 0 ? _a : result[2];
|
|
218
222
|
}
|
|
219
223
|
// If there's a port convert it to an integer
|
|
220
224
|
if (port) {
|
|
221
225
|
port = parseInt(port, 10);
|
|
222
|
-
// squelch out of range ports
|
|
223
|
-
if (port < 0 || port >
|
|
226
|
+
// squelch out of range ports (valid ports are 0-65535)
|
|
227
|
+
if (port < 0 || port > 65535) {
|
|
224
228
|
port = null;
|
|
225
229
|
}
|
|
226
230
|
}
|
|
@@ -258,7 +262,6 @@ class Address6 {
|
|
|
258
262
|
static fromAddressAndWildcardMask(address, wildcardMask) {
|
|
259
263
|
const wildcard = new Address6(wildcardMask).bigInt();
|
|
260
264
|
const allOnes = (BigInt(1) << BigInt(constants6.BITS)) - BigInt(1);
|
|
261
|
-
// eslint-disable-next-line no-bitwise
|
|
262
265
|
const mask = wildcard ^ allOnes;
|
|
263
266
|
const bits = common.prefixLengthFromMask(mask, constants6.BITS);
|
|
264
267
|
return new Address6(`${address}/${bits}`);
|
|
@@ -493,7 +496,7 @@ class Address6 {
|
|
|
493
496
|
getType() {
|
|
494
497
|
for (let i = 0; i < TYPE_SUBNETS.length; i++) {
|
|
495
498
|
const entry = TYPE_SUBNETS[i];
|
|
496
|
-
if (this.
|
|
499
|
+
if (this.isHostInSubnet(entry[0])) {
|
|
497
500
|
return entry[1];
|
|
498
501
|
}
|
|
499
502
|
}
|
|
@@ -635,20 +638,27 @@ class Address6 {
|
|
|
635
638
|
}
|
|
636
639
|
const groups = address.split(':');
|
|
637
640
|
const lastGroup = groups.slice(-1)[0];
|
|
641
|
+
// RE_ADDRESS rejects octets with a leading zero, so a dotted-quad tail is
|
|
642
|
+
// matched permissively first: that way this notation still gets its own
|
|
643
|
+
// message with the offending octet highlighted, rather than falling
|
|
644
|
+
// through as an unrecognized group.
|
|
645
|
+
const v4Octets = lastGroup.split('.');
|
|
646
|
+
if (v4Octets.length === constants4.GROUPS &&
|
|
647
|
+
v4Octets.every((octet) => /^\d{1,3}$/.test(octet))) {
|
|
648
|
+
if (v4Octets.some((octet) => /^0\d/.test(octet))) {
|
|
649
|
+
// The prefix groups haven't been through the bad-character check
|
|
650
|
+
// yet, so escape them before including in the error HTML.
|
|
651
|
+
const highlighted = v4Octets.map(spanLeadingZeroes4).join('.');
|
|
652
|
+
const prefix = groups.slice(0, -1).map(helpers.escapeHtml).join(':');
|
|
653
|
+
const separator = groups.length > 1 ? ':' : '';
|
|
654
|
+
throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", `${prefix}${separator}${highlighted}`);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
638
657
|
const address4 = lastGroup.match(constants4.RE_ADDRESS);
|
|
639
658
|
if (address4) {
|
|
640
659
|
this.parsedAddress4 = address4[0];
|
|
641
|
-
this.
|
|
642
|
-
|
|
643
|
-
if (/^0[0-9]+/.test(this.address4.parsedAddress[i])) {
|
|
644
|
-
// The prefix groups haven't been through the bad-character check
|
|
645
|
-
// yet, so escape them before including in the error HTML.
|
|
646
|
-
const highlighted = this.address4.parsedAddress.map(spanLeadingZeroes4).join('.');
|
|
647
|
-
const prefix = groups.slice(0, -1).map(helpers.escapeHtml).join(':');
|
|
648
|
-
const separator = groups.length > 1 ? ':' : '';
|
|
649
|
-
throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", `${prefix}${separator}${highlighted}`);
|
|
650
|
-
}
|
|
651
|
-
}
|
|
660
|
+
const v4Suffix = this.subnetMask >= 96 ? `/${this.subnetMask - 96}` : '';
|
|
661
|
+
this.address4 = new ipv4_1.Address4(`${this.parsedAddress4}${v4Suffix}`);
|
|
652
662
|
this.v4 = true;
|
|
653
663
|
groups[groups.length - 1] = this.address4.toGroup6();
|
|
654
664
|
address = groups.join(':');
|
|
@@ -734,7 +744,11 @@ class Address6 {
|
|
|
734
744
|
return BigInt(`0x${this.parsedAddress.map(paddedHex).join('')}`);
|
|
735
745
|
}
|
|
736
746
|
/**
|
|
737
|
-
* Return the last two groups of this address as an IPv4 address string
|
|
747
|
+
* Return the last two groups of this address as an IPv4 address string.
|
|
748
|
+
* If this address carries a CIDR prefix that covers the trailing 32 bits
|
|
749
|
+
* (i.e. `subnetMask >= 96`), the resulting `Address4` inherits the
|
|
750
|
+
* corresponding v4 prefix (`subnetMask - 96`); otherwise it defaults to
|
|
751
|
+
* `/32`.
|
|
738
752
|
* @returns {Address4}
|
|
739
753
|
* @example
|
|
740
754
|
* var address = new Address6('2001:4860:4001::1825:bf11');
|
|
@@ -742,7 +756,18 @@ class Address6 {
|
|
|
742
756
|
*/
|
|
743
757
|
to4() {
|
|
744
758
|
const binary = this.binaryZeroPad().split('');
|
|
745
|
-
|
|
759
|
+
const hex = BigInt(`0b${binary.slice(96, 128).join('')}`)
|
|
760
|
+
.toString(16)
|
|
761
|
+
.padStart(8, '0');
|
|
762
|
+
if (this.subnetMask >= 96) {
|
|
763
|
+
const v4Mask = this.subnetMask - 96;
|
|
764
|
+
const groups = [];
|
|
765
|
+
for (let i = 0; i < 8; i += 2) {
|
|
766
|
+
groups.push(parseInt(hex.slice(i, i + 2), 16));
|
|
767
|
+
}
|
|
768
|
+
return new ipv4_1.Address4(`${groups.join('.')}/${v4Mask}`);
|
|
769
|
+
}
|
|
770
|
+
return ipv4_1.Address4.fromHex(hex);
|
|
746
771
|
}
|
|
747
772
|
/**
|
|
748
773
|
* Return the v4-in-v6 form of the address
|
|
@@ -756,7 +781,7 @@ class Address6 {
|
|
|
756
781
|
if (!/:$/.test(correct)) {
|
|
757
782
|
infix = ':';
|
|
758
783
|
}
|
|
759
|
-
return correct + infix + address4.
|
|
784
|
+
return correct + infix + address4.correctForm();
|
|
760
785
|
}
|
|
761
786
|
/**
|
|
762
787
|
* Decodes the Teredo tunneling fields embedded in this address. Returns the
|
|
@@ -788,11 +813,9 @@ class Address6 {
|
|
|
788
813
|
*/
|
|
789
814
|
const prefix = this.getBitsBase16(0, 32);
|
|
790
815
|
const bitsForUdpPort = this.getBits(80, 96);
|
|
791
|
-
// eslint-disable-next-line no-bitwise
|
|
792
816
|
const udpPort = (bitsForUdpPort ^ BigInt('0xffff')).toString();
|
|
793
817
|
const server4 = ipv4_1.Address4.fromHex(this.getBitsBase16(32, 64));
|
|
794
818
|
const bitsForClient4 = this.getBits(96, 128);
|
|
795
|
-
// eslint-disable-next-line no-bitwise
|
|
796
819
|
const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt('0xffffffff')).toString(16).padStart(8, '0'));
|
|
797
820
|
const flagsBase2 = this.getBitsBase2(64, 80);
|
|
798
821
|
const coneNat = (0, common_1.testBit)(flagsBase2, 15);
|
|
@@ -874,12 +897,14 @@ class Address6 {
|
|
|
874
897
|
}
|
|
875
898
|
else {
|
|
876
899
|
const beforeU = 64 - pl;
|
|
877
|
-
bits =
|
|
878
|
-
prefixBits.slice(0, pl)
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
900
|
+
bits = [
|
|
901
|
+
prefixBits.slice(0, pl),
|
|
902
|
+
v4Bits.slice(0, beforeU),
|
|
903
|
+
// Bits 64 to 71 are the reserved u octet and are always zero.
|
|
904
|
+
'00000000',
|
|
905
|
+
v4Bits.slice(beforeU),
|
|
906
|
+
'0'.repeat(128 - 72 - (32 - beforeU)),
|
|
907
|
+
].join('');
|
|
883
908
|
}
|
|
884
909
|
const hex = BigInt(`0b${bits}`).toString(16).padStart(32, '0');
|
|
885
910
|
const groups = [];
|
|
@@ -902,7 +927,7 @@ class Address6 {
|
|
|
902
927
|
if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) {
|
|
903
928
|
throw new address_error_1.AddressError('NAT64 prefix length must be 32, 40, 48, 56, 64, or 96');
|
|
904
929
|
}
|
|
905
|
-
if (!this.
|
|
930
|
+
if (!this.isHostInSubnet(prefix6)) {
|
|
906
931
|
return null;
|
|
907
932
|
}
|
|
908
933
|
const bits = this.binaryZeroPad();
|
|
@@ -927,9 +952,9 @@ class Address6 {
|
|
|
927
952
|
* @returns {Array}
|
|
928
953
|
*/
|
|
929
954
|
toByteArray() {
|
|
930
|
-
const
|
|
931
|
-
|
|
932
|
-
|
|
955
|
+
const value = this.bigInt()
|
|
956
|
+
.toString(16)
|
|
957
|
+
.padStart(constants6.BITS / 4, '0');
|
|
933
958
|
const bytes = [];
|
|
934
959
|
for (let i = 0, length = value.length; i < length; i += 2) {
|
|
935
960
|
bytes.push(parseInt(value.substring(i, i + 2), 16));
|
|
@@ -943,24 +968,39 @@ class Address6 {
|
|
|
943
968
|
* @returns {Array}
|
|
944
969
|
*/
|
|
945
970
|
toUnsignedByteArray() {
|
|
971
|
+
// toByteArray() emits 0 to 255, so unsigning it is an identity mapping and
|
|
972
|
+
// the two methods return equal arrays. 11.0.0 keeps one of them and makes
|
|
973
|
+
// this a deprecated alias; test/common-test.ts fails at that version.
|
|
946
974
|
return this.toByteArray().map(unsignByte);
|
|
947
975
|
}
|
|
948
976
|
/**
|
|
949
977
|
* Convert a byte array to an Address6 object.
|
|
950
978
|
*
|
|
979
|
+
* Accepts unsigned bytes (0 to 255) or signed bytes (-128 to 127, as an
|
|
980
|
+
* `Int8Array` or a Java `byte[]` holds them), folding signed values to their
|
|
981
|
+
* unsigned equivalent. Throws `AddressError` unless given exactly 16
|
|
982
|
+
* integers from -128 to 255.
|
|
983
|
+
*
|
|
951
984
|
* To convert from a Node.js `Buffer`, spread it: `Address6.fromByteArray([...buf])`.
|
|
952
985
|
* @returns {Address6}
|
|
953
986
|
*/
|
|
954
987
|
static fromByteArray(bytes) {
|
|
988
|
+
// Address4.fromByteArray takes unsigned bytes only. 11.0.0 aligns this
|
|
989
|
+
// method with it, at which point the -128 floor here, unsignByte, and the
|
|
990
|
+
// mapping below all go; test/common-test.ts fails at that version.
|
|
991
|
+
common.assertByteArray(bytes, 16, 'IPv6', -128);
|
|
955
992
|
return this.fromUnsignedByteArray(bytes.map(unsignByte));
|
|
956
993
|
}
|
|
957
994
|
/**
|
|
958
995
|
* Convert an unsigned byte array to an Address6 object.
|
|
959
996
|
*
|
|
997
|
+
* Throws `AddressError` unless given exactly 16 integers from 0 to 255.
|
|
998
|
+
*
|
|
960
999
|
* To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`.
|
|
961
1000
|
* @returns {Address6}
|
|
962
1001
|
*/
|
|
963
1002
|
static fromUnsignedByteArray(bytes) {
|
|
1003
|
+
common.assertByteArray(bytes, 16, 'IPv6', 0);
|
|
964
1004
|
const BYTE_MAX = BigInt('256');
|
|
965
1005
|
let result = BigInt('0');
|
|
966
1006
|
let multiplier = BigInt('1');
|
|
@@ -982,7 +1022,11 @@ class Address6 {
|
|
|
982
1022
|
* @returns {boolean}
|
|
983
1023
|
*/
|
|
984
1024
|
isLinkLocal() {
|
|
985
|
-
|
|
1025
|
+
const embedded = this.embeddedIPv4();
|
|
1026
|
+
if (embedded) {
|
|
1027
|
+
return embedded.isLinkLocal();
|
|
1028
|
+
}
|
|
1029
|
+
// Zeroes are required, i.e. we can't check isHostInSubnet with 'fe80::/10'
|
|
986
1030
|
if (this.getBitsBase2(0, 64) ===
|
|
987
1031
|
'1111111010000000000000000000000000000000000000000000000000000000') {
|
|
988
1032
|
return true;
|
|
@@ -994,6 +1038,10 @@ class Address6 {
|
|
|
994
1038
|
* @returns {boolean}
|
|
995
1039
|
*/
|
|
996
1040
|
isMulticast() {
|
|
1041
|
+
const embedded = this.embeddedIPv4();
|
|
1042
|
+
if (embedded) {
|
|
1043
|
+
return embedded.isMulticast();
|
|
1044
|
+
}
|
|
997
1045
|
const type = this.getType();
|
|
998
1046
|
return type === 'Multicast' || type.startsWith('Multicast ');
|
|
999
1047
|
}
|
|
@@ -1016,27 +1064,54 @@ class Address6 {
|
|
|
1016
1064
|
* @returns {boolean}
|
|
1017
1065
|
*/
|
|
1018
1066
|
isMapped4() {
|
|
1019
|
-
return this.
|
|
1067
|
+
return this.isHostInSubnet(IPV4_MAPPED_SUBNET);
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* If this address embeds a routable IPv4 address — i.e. it is IPv4-mapped
|
|
1071
|
+
* (`::ffff:0:0/96`) or sits in the NAT64 well-known prefix (`64:ff9b::/96`,
|
|
1072
|
+
* [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052)) — return that
|
|
1073
|
+
* embedded address as an {@link Address4}; otherwise return null.
|
|
1074
|
+
*
|
|
1075
|
+
* The special-property checks (`isLoopback`, `isLinkLocal`, `isMulticast`,
|
|
1076
|
+
* `isUnspecified`, `isPrivate`, `isCGNAT`, `isBroadcast`) call this first and
|
|
1077
|
+
* delegate to the embedded {@link Address4} when present, so a literal such as
|
|
1078
|
+
* `::ffff:127.0.0.1` is classified by what it actually reaches (loopback)
|
|
1079
|
+
* rather than by its IPv6 wrapper (which `getType()` reports as IPv4-mapped).
|
|
1080
|
+
* This matters wherever the checks back a trust-boundary decision (e.g. an
|
|
1081
|
+
* SSRF allow/deny filter): without normalization, `::ffff:10.0.0.1`,
|
|
1082
|
+
* `::ffff:169.254.169.254`, `64:ff9b::7f00:1`, etc. would all read as
|
|
1083
|
+
* non-internal.
|
|
1084
|
+
* @returns {Address4 | null}
|
|
1085
|
+
*/
|
|
1086
|
+
embeddedIPv4() {
|
|
1087
|
+
if (this.isMapped4() || this.isHostInSubnet(NAT64_WELL_KNOWN_SUBNET)) {
|
|
1088
|
+
return this.to4();
|
|
1089
|
+
}
|
|
1090
|
+
return null;
|
|
1020
1091
|
}
|
|
1021
1092
|
/**
|
|
1022
1093
|
* Returns true if the address is a Teredo address, false otherwise
|
|
1023
1094
|
* @returns {boolean}
|
|
1024
1095
|
*/
|
|
1025
1096
|
isTeredo() {
|
|
1026
|
-
return this.
|
|
1097
|
+
return this.isHostInSubnet(TEREDO_SUBNET);
|
|
1027
1098
|
}
|
|
1028
1099
|
/**
|
|
1029
1100
|
* Returns true if the address is a 6to4 address, false otherwise
|
|
1030
1101
|
* @returns {boolean}
|
|
1031
1102
|
*/
|
|
1032
1103
|
is6to4() {
|
|
1033
|
-
return this.
|
|
1104
|
+
return this.isHostInSubnet(SIX_TO_FOUR_SUBNET);
|
|
1034
1105
|
}
|
|
1035
1106
|
/**
|
|
1036
1107
|
* Returns true if the address is a loopback address, false otherwise
|
|
1037
1108
|
* @returns {boolean}
|
|
1038
1109
|
*/
|
|
1039
1110
|
isLoopback() {
|
|
1111
|
+
const embedded = this.embeddedIPv4();
|
|
1112
|
+
if (embedded) {
|
|
1113
|
+
return embedded.isLoopback();
|
|
1114
|
+
}
|
|
1040
1115
|
return this.getType() === 'Loopback';
|
|
1041
1116
|
}
|
|
1042
1117
|
/**
|
|
@@ -1044,13 +1119,64 @@ class Address6 {
|
|
|
1044
1119
|
* @returns {boolean}
|
|
1045
1120
|
*/
|
|
1046
1121
|
isULA() {
|
|
1047
|
-
return this.
|
|
1122
|
+
return this.isHostInSubnet(ULA_SUBNET);
|
|
1123
|
+
}
|
|
1124
|
+
/**
|
|
1125
|
+
* Returns true if the address is private, i.e. a Unique Local Address in
|
|
1126
|
+
* `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)) or an
|
|
1127
|
+
* IPv4-mapped / NAT64 address whose embedded IPv4 address is in one of the
|
|
1128
|
+
* [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private ranges
|
|
1129
|
+
* (e.g. `::ffff:10.0.0.1`). This is the IPv6 counterpart to
|
|
1130
|
+
* {@link Address4.isPrivate}; use it instead of {@link isULA} when you need to
|
|
1131
|
+
* catch mapped RFC 1918 addresses as well as native ULAs.
|
|
1132
|
+
* @returns {boolean}
|
|
1133
|
+
*/
|
|
1134
|
+
isPrivate() {
|
|
1135
|
+
const embedded = this.embeddedIPv4();
|
|
1136
|
+
if (embedded) {
|
|
1137
|
+
return embedded.isPrivate();
|
|
1138
|
+
}
|
|
1139
|
+
return this.isULA();
|
|
1140
|
+
}
|
|
1141
|
+
/**
|
|
1142
|
+
* Returns true if the address is an IPv4-mapped / NAT64 address whose embedded
|
|
1143
|
+
* IPv4 address is in the carrier-grade NAT range `100.64.0.0/10`
|
|
1144
|
+
* ([RFC 6598](https://datatracker.ietf.org/doc/html/rfc6598)), false
|
|
1145
|
+
* otherwise. There is no native IPv6 CGNAT range, so this only ever returns
|
|
1146
|
+
* true for an embedded IPv4 address (e.g. `::ffff:100.64.0.1`).
|
|
1147
|
+
* @returns {boolean}
|
|
1148
|
+
*/
|
|
1149
|
+
isCGNAT() {
|
|
1150
|
+
const embedded = this.embeddedIPv4();
|
|
1151
|
+
if (embedded) {
|
|
1152
|
+
return embedded.isCGNAT();
|
|
1153
|
+
}
|
|
1154
|
+
return false;
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
* Returns true if the address is an IPv4-mapped / NAT64 address whose embedded
|
|
1158
|
+
* IPv4 address is the limited broadcast address `255.255.255.255`
|
|
1159
|
+
* ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)), false otherwise.
|
|
1160
|
+
* There is no IPv6 broadcast, so this only ever returns true for an embedded
|
|
1161
|
+
* IPv4 address (e.g. `::ffff:255.255.255.255`).
|
|
1162
|
+
* @returns {boolean}
|
|
1163
|
+
*/
|
|
1164
|
+
isBroadcast() {
|
|
1165
|
+
const embedded = this.embeddedIPv4();
|
|
1166
|
+
if (embedded) {
|
|
1167
|
+
return embedded.isBroadcast();
|
|
1168
|
+
}
|
|
1169
|
+
return false;
|
|
1048
1170
|
}
|
|
1049
1171
|
/**
|
|
1050
1172
|
* Returns true if the address is the unspecified address `::`.
|
|
1051
1173
|
* @returns {boolean}
|
|
1052
1174
|
*/
|
|
1053
1175
|
isUnspecified() {
|
|
1176
|
+
const embedded = this.embeddedIPv4();
|
|
1177
|
+
if (embedded) {
|
|
1178
|
+
return embedded.isUnspecified();
|
|
1179
|
+
}
|
|
1054
1180
|
return this.getType() === 'Unspecified';
|
|
1055
1181
|
}
|
|
1056
1182
|
/**
|
|
@@ -1058,7 +1184,7 @@ class Address6 {
|
|
|
1058
1184
|
* @returns {boolean}
|
|
1059
1185
|
*/
|
|
1060
1186
|
isDocumentation() {
|
|
1061
|
-
return this.
|
|
1187
|
+
return this.isHostInSubnet(DOCUMENTATION_SUBNET);
|
|
1062
1188
|
}
|
|
1063
1189
|
// #endregion
|
|
1064
1190
|
// #region HTML
|
|
@@ -1214,4 +1340,5 @@ const SIX_TO_FOUR_SUBNET = new Address6('2002::/16');
|
|
|
1214
1340
|
const ULA_SUBNET = new Address6('fc00::/7');
|
|
1215
1341
|
const DOCUMENTATION_SUBNET = new Address6('2001:db8::/32');
|
|
1216
1342
|
const IPV4_MAPPED_SUBNET = new Address6('::ffff:0:0/96');
|
|
1343
|
+
const NAT64_WELL_KNOWN_SUBNET = new Address6('64:ff9b::/96');
|
|
1217
1344
|
//# sourceMappingURL=ipv6.js.map
|