@heybox/hb-sdk 0.7.4-alpha.1 → 0.7.4-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.md +25 -0
- package/README.md +17 -1
- package/dist/cli-chunks/{build-Cej8ObyY.cjs → build-C-ufarA6.cjs} +2 -2
- package/dist/cli-chunks/{context-DATgeHkI.cjs → context-C839--TH.cjs} +1 -1
- package/dist/cli-chunks/{create-LXHV_lW5.cjs → create-CNcII_CB.cjs} +1 -1
- package/dist/cli-chunks/{dev-CDuVyGm9.cjs → dev-MpESCaMm.cjs} +5 -5
- package/dist/cli-chunks/{doctor-BqmQrPaV.cjs → doctor-bhfQwyYU.cjs} +1 -1
- package/dist/cli-chunks/{index-Ck7X1LRP.cjs → index-B_qJzSFo.cjs} +1 -1
- package/dist/cli-chunks/{index-BCd2vU5D.cjs → index-CT94XzyO.cjs} +14 -14
- package/dist/cli-chunks/{login-BLTILOf-.cjs → login-hYrDJ3dR.cjs} +2 -2
- package/dist/cli-chunks/{project-vite-BtIYxLkt.cjs → project-vite-zaw68V1G.cjs} +1 -1
- package/dist/cli-chunks/{remote-Bp9SK8C3.cjs → remote-DQZRAAHh.cjs} +4 -4
- package/dist/cli-chunks/{session-9ZWPGpqB.cjs → session-D692TU5N.cjs} +1 -1
- package/dist/cli.cjs +1 -1
- package/dist/devtools/browser-dev-host/main.js +1256 -46
- package/dist/index.cjs.js +1187 -3
- package/dist/index.esm.js +1187 -3
- package/dist/protocol.cjs.js +3 -0
- package/dist/protocol.esm.js +3 -1
- package/dist/vite.cjs.js +1 -1
- package/dist/vite.esm.js +1 -1
- package/package.json +5 -4
- package/skill/SKILL.md +1 -0
- package/skill/references/api-protocol.md +5 -2
- package/skill/references/api-root.md +6 -2
- package/skill/references/recipes.md +39 -0
- package/skill/skill.json +4 -4
- package/types/index.d.ts +1 -1
- package/types/modules/share/copy-link.d.ts +16 -0
- package/types/modules/share/extra.d.ts +3 -0
- package/types/modules/share/index.d.ts +8 -2
- package/types/modules/share/types.d.ts +11 -0
- package/types/protocol/capabilities.d.ts +1 -1
- package/types/protocol.d.ts +2 -2
package/dist/index.cjs.js
CHANGED
|
@@ -568,6 +568,7 @@ const AUTH_LOGIN_METHOD = 'auth.login';
|
|
|
568
568
|
const USER_GET_INFO_METHOD = 'user.getInfo';
|
|
569
569
|
const USER_REVOKE_AUTHORIZATION_METHOD = 'user.revokeAuthorization';
|
|
570
570
|
const USER_GET_STEAM_GAME_LIST_METHOD = 'user.getSteamGameList';
|
|
571
|
+
const SHARE_COPY_LINK_METHOD = 'share.copyLink';
|
|
571
572
|
const SHARE_SHOW_SHARE_MENU_METHOD = 'share.showShareMenu';
|
|
572
573
|
const SHARE_SCREENSHOT_METHOD = 'share.screenshot';
|
|
573
574
|
const VIEWPORT_GET_WINDOW_INFO_METHOD = 'viewport.getWindowInfo';
|
|
@@ -671,7 +672,7 @@ function createMessageId() {
|
|
|
671
672
|
/** 构建时替换为当前发布包的实际版本。 */
|
|
672
673
|
const HB_SDK_VERSION = typeof undefined === 'string'
|
|
673
674
|
? undefined
|
|
674
|
-
: '0.7.4-alpha.
|
|
675
|
+
: '0.7.4-alpha.5';
|
|
675
676
|
|
|
676
677
|
const DEFAULT_TIMEOUT = 10000;
|
|
677
678
|
const HANDSHAKE_RETRY_INTERVAL = 250;
|
|
@@ -1048,6 +1049,1184 @@ function createCloudModule(requester) {
|
|
|
1048
1049
|
};
|
|
1049
1050
|
}
|
|
1050
1051
|
|
|
1052
|
+
/**
|
|
1053
|
+
* 复制当前小程序的通用分享链接。
|
|
1054
|
+
*
|
|
1055
|
+
* @param requester 底层 bridge 请求能力。
|
|
1056
|
+
* @param options 分享扩展数据;不传时复制默认首页链接。
|
|
1057
|
+
* @returns 已写入系统剪贴板的完整分享链接。
|
|
1058
|
+
* @throws {HbMiniProgramSDKError} 当参数、bridge、父容器或剪贴板能力调用失败时抛出。
|
|
1059
|
+
*/
|
|
1060
|
+
function copyLink(requester, options) {
|
|
1061
|
+
return requester.request(SHARE_COPY_LINK_METHOD, options);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
// TextEncoder and TextDecoder are standardized in whatwg encoding:
|
|
1065
|
+
// https://encoding.spec.whatwg.org/
|
|
1066
|
+
// and available in all the modern browsers:
|
|
1067
|
+
// https://caniuse.com/textencoder
|
|
1068
|
+
// They are available in Node.js since v12 LTS as well:
|
|
1069
|
+
// https://nodejs.org/api/globals.html#textencoder
|
|
1070
|
+
new TextEncoder();
|
|
1071
|
+
const CHUNK_SIZE = 4096;
|
|
1072
|
+
function utf8DecodeJs(bytes, inputOffset, byteLength) {
|
|
1073
|
+
let offset = inputOffset;
|
|
1074
|
+
const end = offset + byteLength;
|
|
1075
|
+
const units = [];
|
|
1076
|
+
let result = "";
|
|
1077
|
+
while (offset < end) {
|
|
1078
|
+
const byte1 = bytes[offset++];
|
|
1079
|
+
if ((byte1 & 0x80) === 0) {
|
|
1080
|
+
// 1 byte
|
|
1081
|
+
units.push(byte1);
|
|
1082
|
+
}
|
|
1083
|
+
else if ((byte1 & 0xe0) === 0xc0) {
|
|
1084
|
+
// 2 bytes
|
|
1085
|
+
const byte2 = bytes[offset++] & 0x3f;
|
|
1086
|
+
units.push(((byte1 & 0x1f) << 6) | byte2);
|
|
1087
|
+
}
|
|
1088
|
+
else if ((byte1 & 0xf0) === 0xe0) {
|
|
1089
|
+
// 3 bytes
|
|
1090
|
+
const byte2 = bytes[offset++] & 0x3f;
|
|
1091
|
+
const byte3 = bytes[offset++] & 0x3f;
|
|
1092
|
+
units.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3);
|
|
1093
|
+
}
|
|
1094
|
+
else if ((byte1 & 0xf8) === 0xf0) {
|
|
1095
|
+
// 4 bytes
|
|
1096
|
+
const byte2 = bytes[offset++] & 0x3f;
|
|
1097
|
+
const byte3 = bytes[offset++] & 0x3f;
|
|
1098
|
+
const byte4 = bytes[offset++] & 0x3f;
|
|
1099
|
+
let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4;
|
|
1100
|
+
if (unit > 0xffff) {
|
|
1101
|
+
unit -= 0x10000;
|
|
1102
|
+
units.push(((unit >>> 10) & 0x3ff) | 0xd800);
|
|
1103
|
+
unit = 0xdc00 | (unit & 0x3ff);
|
|
1104
|
+
}
|
|
1105
|
+
units.push(unit);
|
|
1106
|
+
}
|
|
1107
|
+
else {
|
|
1108
|
+
units.push(byte1);
|
|
1109
|
+
}
|
|
1110
|
+
if (units.length >= CHUNK_SIZE) {
|
|
1111
|
+
result += String.fromCharCode(...units);
|
|
1112
|
+
units.length = 0;
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
if (units.length > 0) {
|
|
1116
|
+
result += String.fromCharCode(...units);
|
|
1117
|
+
}
|
|
1118
|
+
return result;
|
|
1119
|
+
}
|
|
1120
|
+
const sharedTextDecoder = new TextDecoder();
|
|
1121
|
+
// This threshold should be determined by benchmarking, which might vary in engines and input data.
|
|
1122
|
+
// Run `npx ts-node benchmark/decode-string.ts` for details.
|
|
1123
|
+
const TEXT_DECODER_THRESHOLD = 200;
|
|
1124
|
+
function utf8DecodeTD(bytes, inputOffset, byteLength) {
|
|
1125
|
+
const stringBytes = bytes.subarray(inputOffset, inputOffset + byteLength);
|
|
1126
|
+
return sharedTextDecoder.decode(stringBytes);
|
|
1127
|
+
}
|
|
1128
|
+
function utf8Decode(bytes, inputOffset, byteLength) {
|
|
1129
|
+
if (byteLength > TEXT_DECODER_THRESHOLD) {
|
|
1130
|
+
return utf8DecodeTD(bytes, inputOffset, byteLength);
|
|
1131
|
+
}
|
|
1132
|
+
else {
|
|
1133
|
+
return utf8DecodeJs(bytes, inputOffset, byteLength);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
/**
|
|
1138
|
+
* ExtData is used to handle Extension Types that are not registered to ExtensionCodec.
|
|
1139
|
+
*/
|
|
1140
|
+
class ExtData {
|
|
1141
|
+
type;
|
|
1142
|
+
data;
|
|
1143
|
+
constructor(type, data) {
|
|
1144
|
+
this.type = type;
|
|
1145
|
+
this.data = data;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
class DecodeError extends Error {
|
|
1150
|
+
constructor(message) {
|
|
1151
|
+
super(message);
|
|
1152
|
+
// fix the prototype chain in a cross-platform way
|
|
1153
|
+
const proto = Object.create(DecodeError.prototype);
|
|
1154
|
+
Object.setPrototypeOf(this, proto);
|
|
1155
|
+
Object.defineProperty(this, "name", {
|
|
1156
|
+
configurable: true,
|
|
1157
|
+
enumerable: false,
|
|
1158
|
+
value: DecodeError.name,
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
// Integer Utility
|
|
1164
|
+
const UINT32_MAX = 4294967295;
|
|
1165
|
+
function setInt64(view, offset, value) {
|
|
1166
|
+
const high = Math.floor(value / 4294967296);
|
|
1167
|
+
const low = value; // high bits are truncated by DataView
|
|
1168
|
+
view.setUint32(offset, high);
|
|
1169
|
+
view.setUint32(offset + 4, low);
|
|
1170
|
+
}
|
|
1171
|
+
function getInt64(view, offset) {
|
|
1172
|
+
const high = view.getInt32(offset);
|
|
1173
|
+
const low = view.getUint32(offset + 4);
|
|
1174
|
+
return high * 4294967296 + low;
|
|
1175
|
+
}
|
|
1176
|
+
function getUint64(view, offset) {
|
|
1177
|
+
const high = view.getUint32(offset);
|
|
1178
|
+
const low = view.getUint32(offset + 4);
|
|
1179
|
+
return high * 4294967296 + low;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type
|
|
1183
|
+
const EXT_TIMESTAMP = -1;
|
|
1184
|
+
const TIMESTAMP32_MAX_SEC = 0x100000000 - 1; // 32-bit unsigned int
|
|
1185
|
+
const TIMESTAMP64_MAX_SEC = 0x400000000 - 1; // 34-bit unsigned int
|
|
1186
|
+
function encodeTimeSpecToTimestamp({ sec, nsec }) {
|
|
1187
|
+
if (sec >= 0 && nsec >= 0 && sec <= TIMESTAMP64_MAX_SEC) {
|
|
1188
|
+
// Here sec >= 0 && nsec >= 0
|
|
1189
|
+
if (nsec === 0 && sec <= TIMESTAMP32_MAX_SEC) {
|
|
1190
|
+
// timestamp 32 = { sec32 (unsigned) }
|
|
1191
|
+
const rv = new Uint8Array(4);
|
|
1192
|
+
const view = new DataView(rv.buffer);
|
|
1193
|
+
view.setUint32(0, sec);
|
|
1194
|
+
return rv;
|
|
1195
|
+
}
|
|
1196
|
+
else {
|
|
1197
|
+
// timestamp 64 = { nsec30 (unsigned), sec34 (unsigned) }
|
|
1198
|
+
const secHigh = sec / 0x100000000;
|
|
1199
|
+
const secLow = sec & 0xffffffff;
|
|
1200
|
+
const rv = new Uint8Array(8);
|
|
1201
|
+
const view = new DataView(rv.buffer);
|
|
1202
|
+
// nsec30 | secHigh2
|
|
1203
|
+
view.setUint32(0, (nsec << 2) | (secHigh & 0x3));
|
|
1204
|
+
// secLow32
|
|
1205
|
+
view.setUint32(4, secLow);
|
|
1206
|
+
return rv;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
else {
|
|
1210
|
+
// timestamp 96 = { nsec32 (unsigned), sec64 (signed) }
|
|
1211
|
+
const rv = new Uint8Array(12);
|
|
1212
|
+
const view = new DataView(rv.buffer);
|
|
1213
|
+
view.setUint32(0, nsec);
|
|
1214
|
+
setInt64(view, 4, sec);
|
|
1215
|
+
return rv;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
function encodeDateToTimeSpec(date) {
|
|
1219
|
+
const msec = date.getTime();
|
|
1220
|
+
const sec = Math.floor(msec / 1e3);
|
|
1221
|
+
const nsec = (msec - sec * 1e3) * 1e6;
|
|
1222
|
+
// Normalizes { sec, nsec } to ensure nsec is unsigned.
|
|
1223
|
+
const nsecInSec = Math.floor(nsec / 1e9);
|
|
1224
|
+
return {
|
|
1225
|
+
sec: sec + nsecInSec,
|
|
1226
|
+
nsec: nsec - nsecInSec * 1e9,
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
function encodeTimestampExtension(object) {
|
|
1230
|
+
if (object instanceof Date) {
|
|
1231
|
+
const timeSpec = encodeDateToTimeSpec(object);
|
|
1232
|
+
return encodeTimeSpecToTimestamp(timeSpec);
|
|
1233
|
+
}
|
|
1234
|
+
else {
|
|
1235
|
+
return null;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
function decodeTimestampToTimeSpec(data) {
|
|
1239
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
1240
|
+
// data may be 32, 64, or 96 bits
|
|
1241
|
+
switch (data.byteLength) {
|
|
1242
|
+
case 4: {
|
|
1243
|
+
// timestamp 32 = { sec32 }
|
|
1244
|
+
const sec = view.getUint32(0);
|
|
1245
|
+
const nsec = 0;
|
|
1246
|
+
return { sec, nsec };
|
|
1247
|
+
}
|
|
1248
|
+
case 8: {
|
|
1249
|
+
// timestamp 64 = { nsec30, sec34 }
|
|
1250
|
+
const nsec30AndSecHigh2 = view.getUint32(0);
|
|
1251
|
+
const secLow32 = view.getUint32(4);
|
|
1252
|
+
const sec = (nsec30AndSecHigh2 & 0x3) * 0x100000000 + secLow32;
|
|
1253
|
+
const nsec = nsec30AndSecHigh2 >>> 2;
|
|
1254
|
+
return { sec, nsec };
|
|
1255
|
+
}
|
|
1256
|
+
case 12: {
|
|
1257
|
+
// timestamp 96 = { nsec32 (unsigned), sec64 (signed) }
|
|
1258
|
+
const sec = getInt64(view, 4);
|
|
1259
|
+
const nsec = view.getUint32(0);
|
|
1260
|
+
return { sec, nsec };
|
|
1261
|
+
}
|
|
1262
|
+
default:
|
|
1263
|
+
throw new DecodeError(`Unrecognized data size for timestamp (expected 4, 8, or 12): ${data.length}`);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
function decodeTimestampExtension(data) {
|
|
1267
|
+
const timeSpec = decodeTimestampToTimeSpec(data);
|
|
1268
|
+
return new Date(timeSpec.sec * 1e3 + timeSpec.nsec / 1e6);
|
|
1269
|
+
}
|
|
1270
|
+
const timestampExtension = {
|
|
1271
|
+
type: EXT_TIMESTAMP,
|
|
1272
|
+
encode: encodeTimestampExtension,
|
|
1273
|
+
decode: decodeTimestampExtension,
|
|
1274
|
+
};
|
|
1275
|
+
|
|
1276
|
+
// ExtensionCodec to handle MessagePack extensions
|
|
1277
|
+
class ExtensionCodec {
|
|
1278
|
+
static defaultCodec = new ExtensionCodec();
|
|
1279
|
+
// ensures ExtensionCodecType<X> matches ExtensionCodec<X>
|
|
1280
|
+
// this will make type errors a lot more clear
|
|
1281
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1282
|
+
__brand;
|
|
1283
|
+
// built-in extensions
|
|
1284
|
+
builtInEncoders = [];
|
|
1285
|
+
builtInDecoders = [];
|
|
1286
|
+
// custom extensions
|
|
1287
|
+
encoders = [];
|
|
1288
|
+
decoders = [];
|
|
1289
|
+
constructor() {
|
|
1290
|
+
this.register(timestampExtension);
|
|
1291
|
+
}
|
|
1292
|
+
register({ type, encode, decode, }) {
|
|
1293
|
+
if (type >= 0) {
|
|
1294
|
+
// custom extensions
|
|
1295
|
+
this.encoders[type] = encode;
|
|
1296
|
+
this.decoders[type] = decode;
|
|
1297
|
+
}
|
|
1298
|
+
else {
|
|
1299
|
+
// built-in extensions
|
|
1300
|
+
const index = -1 - type;
|
|
1301
|
+
this.builtInEncoders[index] = encode;
|
|
1302
|
+
this.builtInDecoders[index] = decode;
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
tryToEncode(object, context) {
|
|
1306
|
+
// built-in extensions
|
|
1307
|
+
for (let i = 0; i < this.builtInEncoders.length; i++) {
|
|
1308
|
+
const encodeExt = this.builtInEncoders[i];
|
|
1309
|
+
if (encodeExt != null) {
|
|
1310
|
+
const data = encodeExt(object, context);
|
|
1311
|
+
if (data != null) {
|
|
1312
|
+
const type = -1 - i;
|
|
1313
|
+
return new ExtData(type, data);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
// custom extensions
|
|
1318
|
+
for (let i = 0; i < this.encoders.length; i++) {
|
|
1319
|
+
const encodeExt = this.encoders[i];
|
|
1320
|
+
if (encodeExt != null) {
|
|
1321
|
+
const data = encodeExt(object, context);
|
|
1322
|
+
if (data != null) {
|
|
1323
|
+
const type = i;
|
|
1324
|
+
return new ExtData(type, data);
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
if (object instanceof ExtData) {
|
|
1329
|
+
// to keep ExtData as is
|
|
1330
|
+
return object;
|
|
1331
|
+
}
|
|
1332
|
+
return null;
|
|
1333
|
+
}
|
|
1334
|
+
decode(data, type, context) {
|
|
1335
|
+
const decodeExt = type < 0 ? this.builtInDecoders[-1 - type] : this.decoders[type];
|
|
1336
|
+
if (decodeExt) {
|
|
1337
|
+
return decodeExt(data, type, context);
|
|
1338
|
+
}
|
|
1339
|
+
else {
|
|
1340
|
+
// decode() does not fail, returns ExtData instead.
|
|
1341
|
+
return new ExtData(type, data);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
function isArrayBufferLike(buffer) {
|
|
1347
|
+
return (buffer instanceof ArrayBuffer || (typeof SharedArrayBuffer !== "undefined" && buffer instanceof SharedArrayBuffer));
|
|
1348
|
+
}
|
|
1349
|
+
function ensureUint8Array(buffer) {
|
|
1350
|
+
if (buffer instanceof Uint8Array) {
|
|
1351
|
+
return buffer;
|
|
1352
|
+
}
|
|
1353
|
+
else if (ArrayBuffer.isView(buffer)) {
|
|
1354
|
+
return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
1355
|
+
}
|
|
1356
|
+
else if (isArrayBufferLike(buffer)) {
|
|
1357
|
+
return new Uint8Array(buffer);
|
|
1358
|
+
}
|
|
1359
|
+
else {
|
|
1360
|
+
// ArrayLike<number>
|
|
1361
|
+
return Uint8Array.from(buffer);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
function prettyByte(byte) {
|
|
1366
|
+
return `${byte < 0 ? "-" : ""}0x${Math.abs(byte).toString(16).padStart(2, "0")}`;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
const DEFAULT_MAX_KEY_LENGTH = 16;
|
|
1370
|
+
const DEFAULT_MAX_LENGTH_PER_KEY = 16;
|
|
1371
|
+
class CachedKeyDecoder {
|
|
1372
|
+
hit = 0;
|
|
1373
|
+
miss = 0;
|
|
1374
|
+
caches;
|
|
1375
|
+
maxKeyLength;
|
|
1376
|
+
maxLengthPerKey;
|
|
1377
|
+
constructor(maxKeyLength = DEFAULT_MAX_KEY_LENGTH, maxLengthPerKey = DEFAULT_MAX_LENGTH_PER_KEY) {
|
|
1378
|
+
this.maxKeyLength = maxKeyLength;
|
|
1379
|
+
this.maxLengthPerKey = maxLengthPerKey;
|
|
1380
|
+
// avoid `new Array(N)`, which makes a sparse array,
|
|
1381
|
+
// because a sparse array is typically slower than a non-sparse array.
|
|
1382
|
+
this.caches = [];
|
|
1383
|
+
for (let i = 0; i < this.maxKeyLength; i++) {
|
|
1384
|
+
this.caches.push([]);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
canBeCached(byteLength) {
|
|
1388
|
+
return byteLength > 0 && byteLength <= this.maxKeyLength;
|
|
1389
|
+
}
|
|
1390
|
+
find(bytes, inputOffset, byteLength) {
|
|
1391
|
+
const records = this.caches[byteLength - 1];
|
|
1392
|
+
FIND_CHUNK: for (const record of records) {
|
|
1393
|
+
const recordBytes = record.bytes;
|
|
1394
|
+
for (let j = 0; j < byteLength; j++) {
|
|
1395
|
+
if (recordBytes[j] !== bytes[inputOffset + j]) {
|
|
1396
|
+
continue FIND_CHUNK;
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
return record.str;
|
|
1400
|
+
}
|
|
1401
|
+
return null;
|
|
1402
|
+
}
|
|
1403
|
+
store(bytes, value) {
|
|
1404
|
+
const records = this.caches[bytes.length - 1];
|
|
1405
|
+
const record = { bytes, str: value };
|
|
1406
|
+
if (records.length >= this.maxLengthPerKey) {
|
|
1407
|
+
// `records` are full!
|
|
1408
|
+
// Set `record` to an arbitrary position.
|
|
1409
|
+
records[(Math.random() * records.length) | 0] = record;
|
|
1410
|
+
}
|
|
1411
|
+
else {
|
|
1412
|
+
records.push(record);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
decode(bytes, inputOffset, byteLength) {
|
|
1416
|
+
const cachedValue = this.find(bytes, inputOffset, byteLength);
|
|
1417
|
+
if (cachedValue != null) {
|
|
1418
|
+
this.hit++;
|
|
1419
|
+
return cachedValue;
|
|
1420
|
+
}
|
|
1421
|
+
this.miss++;
|
|
1422
|
+
const str = utf8DecodeJs(bytes, inputOffset, byteLength);
|
|
1423
|
+
// Ensure to copy a slice of bytes because the bytes may be a NodeJS Buffer and Buffer#slice() returns a reference to its internal ArrayBuffer.
|
|
1424
|
+
const slicedCopyOfBytes = Uint8Array.prototype.slice.call(bytes, inputOffset, inputOffset + byteLength);
|
|
1425
|
+
this.store(slicedCopyOfBytes, str);
|
|
1426
|
+
return str;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
const STATE_ARRAY = "array";
|
|
1431
|
+
const STATE_MAP_KEY = "map_key";
|
|
1432
|
+
const STATE_MAP_VALUE = "map_value";
|
|
1433
|
+
const mapKeyConverter = (key) => {
|
|
1434
|
+
if (typeof key === "string" || typeof key === "number") {
|
|
1435
|
+
return key;
|
|
1436
|
+
}
|
|
1437
|
+
throw new DecodeError("The type of key must be string or number but " + typeof key);
|
|
1438
|
+
};
|
|
1439
|
+
class StackPool {
|
|
1440
|
+
stack = [];
|
|
1441
|
+
stackHeadPosition = -1;
|
|
1442
|
+
get length() {
|
|
1443
|
+
return this.stackHeadPosition + 1;
|
|
1444
|
+
}
|
|
1445
|
+
top() {
|
|
1446
|
+
return this.stack[this.stackHeadPosition];
|
|
1447
|
+
}
|
|
1448
|
+
pushArrayState(size) {
|
|
1449
|
+
const state = this.getUninitializedStateFromPool();
|
|
1450
|
+
state.type = STATE_ARRAY;
|
|
1451
|
+
state.position = 0;
|
|
1452
|
+
state.size = size;
|
|
1453
|
+
state.array = new Array(size);
|
|
1454
|
+
}
|
|
1455
|
+
pushMapState(size) {
|
|
1456
|
+
const state = this.getUninitializedStateFromPool();
|
|
1457
|
+
state.type = STATE_MAP_KEY;
|
|
1458
|
+
state.readCount = 0;
|
|
1459
|
+
state.size = size;
|
|
1460
|
+
state.map = {};
|
|
1461
|
+
}
|
|
1462
|
+
getUninitializedStateFromPool() {
|
|
1463
|
+
this.stackHeadPosition++;
|
|
1464
|
+
if (this.stackHeadPosition === this.stack.length) {
|
|
1465
|
+
const partialState = {
|
|
1466
|
+
type: undefined,
|
|
1467
|
+
size: 0,
|
|
1468
|
+
array: undefined,
|
|
1469
|
+
position: 0,
|
|
1470
|
+
readCount: 0,
|
|
1471
|
+
map: undefined,
|
|
1472
|
+
key: null,
|
|
1473
|
+
};
|
|
1474
|
+
this.stack.push(partialState);
|
|
1475
|
+
}
|
|
1476
|
+
return this.stack[this.stackHeadPosition];
|
|
1477
|
+
}
|
|
1478
|
+
release(state) {
|
|
1479
|
+
const topStackState = this.stack[this.stackHeadPosition];
|
|
1480
|
+
if (topStackState !== state) {
|
|
1481
|
+
throw new Error("Invalid stack state. Released state is not on top of the stack.");
|
|
1482
|
+
}
|
|
1483
|
+
if (state.type === STATE_ARRAY) {
|
|
1484
|
+
const partialState = state;
|
|
1485
|
+
partialState.size = 0;
|
|
1486
|
+
partialState.array = undefined;
|
|
1487
|
+
partialState.position = 0;
|
|
1488
|
+
partialState.type = undefined;
|
|
1489
|
+
}
|
|
1490
|
+
if (state.type === STATE_MAP_KEY || state.type === STATE_MAP_VALUE) {
|
|
1491
|
+
const partialState = state;
|
|
1492
|
+
partialState.size = 0;
|
|
1493
|
+
partialState.map = undefined;
|
|
1494
|
+
partialState.readCount = 0;
|
|
1495
|
+
partialState.type = undefined;
|
|
1496
|
+
}
|
|
1497
|
+
this.stackHeadPosition--;
|
|
1498
|
+
}
|
|
1499
|
+
reset() {
|
|
1500
|
+
this.stack.length = 0;
|
|
1501
|
+
this.stackHeadPosition = -1;
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
const HEAD_BYTE_REQUIRED = -1;
|
|
1505
|
+
const EMPTY_VIEW = new DataView(new ArrayBuffer(0));
|
|
1506
|
+
const EMPTY_BYTES = new Uint8Array(EMPTY_VIEW.buffer);
|
|
1507
|
+
try {
|
|
1508
|
+
// IE11: The spec says it should throw RangeError,
|
|
1509
|
+
// IE11: but in IE11 it throws TypeError.
|
|
1510
|
+
EMPTY_VIEW.getInt8(0);
|
|
1511
|
+
}
|
|
1512
|
+
catch (e) {
|
|
1513
|
+
if (!(e instanceof RangeError)) {
|
|
1514
|
+
throw new Error("This module is not supported in the current JavaScript engine because DataView does not throw RangeError on out-of-bounds access");
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
const MORE_DATA = new RangeError("Insufficient data");
|
|
1518
|
+
const sharedCachedKeyDecoder = new CachedKeyDecoder();
|
|
1519
|
+
class Decoder {
|
|
1520
|
+
extensionCodec;
|
|
1521
|
+
context;
|
|
1522
|
+
useBigInt64;
|
|
1523
|
+
rawStrings;
|
|
1524
|
+
maxStrLength;
|
|
1525
|
+
maxBinLength;
|
|
1526
|
+
maxArrayLength;
|
|
1527
|
+
maxMapLength;
|
|
1528
|
+
maxExtLength;
|
|
1529
|
+
keyDecoder;
|
|
1530
|
+
mapKeyConverter;
|
|
1531
|
+
totalPos = 0;
|
|
1532
|
+
pos = 0;
|
|
1533
|
+
view = EMPTY_VIEW;
|
|
1534
|
+
bytes = EMPTY_BYTES;
|
|
1535
|
+
headByte = HEAD_BYTE_REQUIRED;
|
|
1536
|
+
stack = new StackPool();
|
|
1537
|
+
entered = false;
|
|
1538
|
+
constructor(options) {
|
|
1539
|
+
this.extensionCodec = options?.extensionCodec ?? ExtensionCodec.defaultCodec;
|
|
1540
|
+
this.context = options?.context; // needs a type assertion because EncoderOptions has no context property when ContextType is undefined
|
|
1541
|
+
this.useBigInt64 = options?.useBigInt64 ?? false;
|
|
1542
|
+
this.rawStrings = options?.rawStrings ?? false;
|
|
1543
|
+
this.maxStrLength = options?.maxStrLength ?? UINT32_MAX;
|
|
1544
|
+
this.maxBinLength = options?.maxBinLength ?? UINT32_MAX;
|
|
1545
|
+
this.maxArrayLength = options?.maxArrayLength ?? UINT32_MAX;
|
|
1546
|
+
this.maxMapLength = options?.maxMapLength ?? UINT32_MAX;
|
|
1547
|
+
this.maxExtLength = options?.maxExtLength ?? UINT32_MAX;
|
|
1548
|
+
this.keyDecoder = options?.keyDecoder !== undefined ? options.keyDecoder : sharedCachedKeyDecoder;
|
|
1549
|
+
this.mapKeyConverter = options?.mapKeyConverter ?? mapKeyConverter;
|
|
1550
|
+
}
|
|
1551
|
+
clone() {
|
|
1552
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
1553
|
+
return new Decoder({
|
|
1554
|
+
extensionCodec: this.extensionCodec,
|
|
1555
|
+
context: this.context,
|
|
1556
|
+
useBigInt64: this.useBigInt64,
|
|
1557
|
+
rawStrings: this.rawStrings,
|
|
1558
|
+
maxStrLength: this.maxStrLength,
|
|
1559
|
+
maxBinLength: this.maxBinLength,
|
|
1560
|
+
maxArrayLength: this.maxArrayLength,
|
|
1561
|
+
maxMapLength: this.maxMapLength,
|
|
1562
|
+
maxExtLength: this.maxExtLength,
|
|
1563
|
+
keyDecoder: this.keyDecoder,
|
|
1564
|
+
});
|
|
1565
|
+
}
|
|
1566
|
+
reinitializeState() {
|
|
1567
|
+
this.totalPos = 0;
|
|
1568
|
+
this.headByte = HEAD_BYTE_REQUIRED;
|
|
1569
|
+
this.stack.reset();
|
|
1570
|
+
// view, bytes, and pos will be re-initialized in setBuffer()
|
|
1571
|
+
}
|
|
1572
|
+
setBuffer(buffer) {
|
|
1573
|
+
const bytes = ensureUint8Array(buffer);
|
|
1574
|
+
this.bytes = bytes;
|
|
1575
|
+
this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
1576
|
+
this.pos = 0;
|
|
1577
|
+
}
|
|
1578
|
+
appendBuffer(buffer) {
|
|
1579
|
+
if (this.headByte === HEAD_BYTE_REQUIRED && !this.hasRemaining(1)) {
|
|
1580
|
+
this.setBuffer(buffer);
|
|
1581
|
+
}
|
|
1582
|
+
else {
|
|
1583
|
+
const remainingData = this.bytes.subarray(this.pos);
|
|
1584
|
+
const newData = ensureUint8Array(buffer);
|
|
1585
|
+
// concat remainingData + newData
|
|
1586
|
+
const newBuffer = new Uint8Array(remainingData.length + newData.length);
|
|
1587
|
+
newBuffer.set(remainingData);
|
|
1588
|
+
newBuffer.set(newData, remainingData.length);
|
|
1589
|
+
this.setBuffer(newBuffer);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
hasRemaining(size) {
|
|
1593
|
+
return this.view.byteLength - this.pos >= size;
|
|
1594
|
+
}
|
|
1595
|
+
createExtraByteError(posToShow) {
|
|
1596
|
+
const { view, pos } = this;
|
|
1597
|
+
return new RangeError(`Extra ${view.byteLength - pos} of ${view.byteLength} byte(s) found at buffer[${posToShow}]`);
|
|
1598
|
+
}
|
|
1599
|
+
/**
|
|
1600
|
+
* @throws {@link DecodeError}
|
|
1601
|
+
* @throws {@link RangeError}
|
|
1602
|
+
*/
|
|
1603
|
+
decode(buffer) {
|
|
1604
|
+
if (this.entered) {
|
|
1605
|
+
const instance = this.clone();
|
|
1606
|
+
return instance.decode(buffer);
|
|
1607
|
+
}
|
|
1608
|
+
try {
|
|
1609
|
+
this.entered = true;
|
|
1610
|
+
this.reinitializeState();
|
|
1611
|
+
this.setBuffer(buffer);
|
|
1612
|
+
const object = this.doDecodeSync();
|
|
1613
|
+
if (this.hasRemaining(1)) {
|
|
1614
|
+
throw this.createExtraByteError(this.pos);
|
|
1615
|
+
}
|
|
1616
|
+
return object;
|
|
1617
|
+
}
|
|
1618
|
+
finally {
|
|
1619
|
+
this.entered = false;
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
*decodeMulti(buffer) {
|
|
1623
|
+
if (this.entered) {
|
|
1624
|
+
const instance = this.clone();
|
|
1625
|
+
yield* instance.decodeMulti(buffer);
|
|
1626
|
+
return;
|
|
1627
|
+
}
|
|
1628
|
+
try {
|
|
1629
|
+
this.entered = true;
|
|
1630
|
+
this.reinitializeState();
|
|
1631
|
+
this.setBuffer(buffer);
|
|
1632
|
+
while (this.hasRemaining(1)) {
|
|
1633
|
+
yield this.doDecodeSync();
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
finally {
|
|
1637
|
+
this.entered = false;
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
async decodeAsync(stream) {
|
|
1641
|
+
if (this.entered) {
|
|
1642
|
+
const instance = this.clone();
|
|
1643
|
+
return instance.decodeAsync(stream);
|
|
1644
|
+
}
|
|
1645
|
+
try {
|
|
1646
|
+
this.entered = true;
|
|
1647
|
+
let decoded = false;
|
|
1648
|
+
let object;
|
|
1649
|
+
for await (const buffer of stream) {
|
|
1650
|
+
if (decoded) {
|
|
1651
|
+
this.entered = false;
|
|
1652
|
+
throw this.createExtraByteError(this.totalPos);
|
|
1653
|
+
}
|
|
1654
|
+
this.appendBuffer(buffer);
|
|
1655
|
+
try {
|
|
1656
|
+
object = this.doDecodeSync();
|
|
1657
|
+
decoded = true;
|
|
1658
|
+
}
|
|
1659
|
+
catch (e) {
|
|
1660
|
+
if (!(e instanceof RangeError)) {
|
|
1661
|
+
throw e; // rethrow
|
|
1662
|
+
}
|
|
1663
|
+
// fallthrough
|
|
1664
|
+
}
|
|
1665
|
+
this.totalPos += this.pos;
|
|
1666
|
+
}
|
|
1667
|
+
if (decoded) {
|
|
1668
|
+
if (this.hasRemaining(1)) {
|
|
1669
|
+
throw this.createExtraByteError(this.totalPos);
|
|
1670
|
+
}
|
|
1671
|
+
return object;
|
|
1672
|
+
}
|
|
1673
|
+
const { headByte, pos, totalPos } = this;
|
|
1674
|
+
throw new RangeError(`Insufficient data in parsing ${prettyByte(headByte)} at ${totalPos} (${pos} in the current buffer)`);
|
|
1675
|
+
}
|
|
1676
|
+
finally {
|
|
1677
|
+
this.entered = false;
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
decodeArrayStream(stream) {
|
|
1681
|
+
return this.decodeMultiAsync(stream, true);
|
|
1682
|
+
}
|
|
1683
|
+
decodeStream(stream) {
|
|
1684
|
+
return this.decodeMultiAsync(stream, false);
|
|
1685
|
+
}
|
|
1686
|
+
async *decodeMultiAsync(stream, isArray) {
|
|
1687
|
+
if (this.entered) {
|
|
1688
|
+
const instance = this.clone();
|
|
1689
|
+
yield* instance.decodeMultiAsync(stream, isArray);
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
try {
|
|
1693
|
+
this.entered = true;
|
|
1694
|
+
let isArrayHeaderRequired = isArray;
|
|
1695
|
+
let arrayItemsLeft = -1;
|
|
1696
|
+
for await (const buffer of stream) {
|
|
1697
|
+
if (isArray && arrayItemsLeft === 0) {
|
|
1698
|
+
throw this.createExtraByteError(this.totalPos);
|
|
1699
|
+
}
|
|
1700
|
+
this.appendBuffer(buffer);
|
|
1701
|
+
if (isArrayHeaderRequired) {
|
|
1702
|
+
arrayItemsLeft = this.readArraySize();
|
|
1703
|
+
isArrayHeaderRequired = false;
|
|
1704
|
+
this.complete();
|
|
1705
|
+
}
|
|
1706
|
+
try {
|
|
1707
|
+
while (true) {
|
|
1708
|
+
yield this.doDecodeSync();
|
|
1709
|
+
if (--arrayItemsLeft === 0) {
|
|
1710
|
+
break;
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
catch (e) {
|
|
1715
|
+
if (!(e instanceof RangeError)) {
|
|
1716
|
+
throw e; // rethrow
|
|
1717
|
+
}
|
|
1718
|
+
// fallthrough
|
|
1719
|
+
}
|
|
1720
|
+
this.totalPos += this.pos;
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
finally {
|
|
1724
|
+
this.entered = false;
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
doDecodeSync() {
|
|
1728
|
+
DECODE: while (true) {
|
|
1729
|
+
const headByte = this.readHeadByte();
|
|
1730
|
+
let object;
|
|
1731
|
+
if (headByte >= 0xe0) {
|
|
1732
|
+
// negative fixint (111x xxxx) 0xe0 - 0xff
|
|
1733
|
+
object = headByte - 0x100;
|
|
1734
|
+
}
|
|
1735
|
+
else if (headByte < 0xc0) {
|
|
1736
|
+
if (headByte < 0x80) {
|
|
1737
|
+
// positive fixint (0xxx xxxx) 0x00 - 0x7f
|
|
1738
|
+
object = headByte;
|
|
1739
|
+
}
|
|
1740
|
+
else if (headByte < 0x90) {
|
|
1741
|
+
// fixmap (1000 xxxx) 0x80 - 0x8f
|
|
1742
|
+
const size = headByte - 0x80;
|
|
1743
|
+
if (size !== 0) {
|
|
1744
|
+
this.pushMapState(size);
|
|
1745
|
+
this.complete();
|
|
1746
|
+
continue DECODE;
|
|
1747
|
+
}
|
|
1748
|
+
else {
|
|
1749
|
+
object = {};
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
else if (headByte < 0xa0) {
|
|
1753
|
+
// fixarray (1001 xxxx) 0x90 - 0x9f
|
|
1754
|
+
const size = headByte - 0x90;
|
|
1755
|
+
if (size !== 0) {
|
|
1756
|
+
this.pushArrayState(size);
|
|
1757
|
+
this.complete();
|
|
1758
|
+
continue DECODE;
|
|
1759
|
+
}
|
|
1760
|
+
else {
|
|
1761
|
+
object = [];
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
else {
|
|
1765
|
+
// fixstr (101x xxxx) 0xa0 - 0xbf
|
|
1766
|
+
const byteLength = headByte - 0xa0;
|
|
1767
|
+
object = this.decodeString(byteLength, 0);
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
else if (headByte === 0xc0) {
|
|
1771
|
+
// nil
|
|
1772
|
+
object = null;
|
|
1773
|
+
}
|
|
1774
|
+
else if (headByte === 0xc2) {
|
|
1775
|
+
// false
|
|
1776
|
+
object = false;
|
|
1777
|
+
}
|
|
1778
|
+
else if (headByte === 0xc3) {
|
|
1779
|
+
// true
|
|
1780
|
+
object = true;
|
|
1781
|
+
}
|
|
1782
|
+
else if (headByte === 0xca) {
|
|
1783
|
+
// float 32
|
|
1784
|
+
object = this.readF32();
|
|
1785
|
+
}
|
|
1786
|
+
else if (headByte === 0xcb) {
|
|
1787
|
+
// float 64
|
|
1788
|
+
object = this.readF64();
|
|
1789
|
+
}
|
|
1790
|
+
else if (headByte === 0xcc) {
|
|
1791
|
+
// uint 8
|
|
1792
|
+
object = this.readU8();
|
|
1793
|
+
}
|
|
1794
|
+
else if (headByte === 0xcd) {
|
|
1795
|
+
// uint 16
|
|
1796
|
+
object = this.readU16();
|
|
1797
|
+
}
|
|
1798
|
+
else if (headByte === 0xce) {
|
|
1799
|
+
// uint 32
|
|
1800
|
+
object = this.readU32();
|
|
1801
|
+
}
|
|
1802
|
+
else if (headByte === 0xcf) {
|
|
1803
|
+
// uint 64
|
|
1804
|
+
if (this.useBigInt64) {
|
|
1805
|
+
object = this.readU64AsBigInt();
|
|
1806
|
+
}
|
|
1807
|
+
else {
|
|
1808
|
+
object = this.readU64();
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
else if (headByte === 0xd0) {
|
|
1812
|
+
// int 8
|
|
1813
|
+
object = this.readI8();
|
|
1814
|
+
}
|
|
1815
|
+
else if (headByte === 0xd1) {
|
|
1816
|
+
// int 16
|
|
1817
|
+
object = this.readI16();
|
|
1818
|
+
}
|
|
1819
|
+
else if (headByte === 0xd2) {
|
|
1820
|
+
// int 32
|
|
1821
|
+
object = this.readI32();
|
|
1822
|
+
}
|
|
1823
|
+
else if (headByte === 0xd3) {
|
|
1824
|
+
// int 64
|
|
1825
|
+
if (this.useBigInt64) {
|
|
1826
|
+
object = this.readI64AsBigInt();
|
|
1827
|
+
}
|
|
1828
|
+
else {
|
|
1829
|
+
object = this.readI64();
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
else if (headByte === 0xd9) {
|
|
1833
|
+
// str 8
|
|
1834
|
+
const byteLength = this.lookU8();
|
|
1835
|
+
object = this.decodeString(byteLength, 1);
|
|
1836
|
+
}
|
|
1837
|
+
else if (headByte === 0xda) {
|
|
1838
|
+
// str 16
|
|
1839
|
+
const byteLength = this.lookU16();
|
|
1840
|
+
object = this.decodeString(byteLength, 2);
|
|
1841
|
+
}
|
|
1842
|
+
else if (headByte === 0xdb) {
|
|
1843
|
+
// str 32
|
|
1844
|
+
const byteLength = this.lookU32();
|
|
1845
|
+
object = this.decodeString(byteLength, 4);
|
|
1846
|
+
}
|
|
1847
|
+
else if (headByte === 0xdc) {
|
|
1848
|
+
// array 16
|
|
1849
|
+
const size = this.readU16();
|
|
1850
|
+
if (size !== 0) {
|
|
1851
|
+
this.pushArrayState(size);
|
|
1852
|
+
this.complete();
|
|
1853
|
+
continue DECODE;
|
|
1854
|
+
}
|
|
1855
|
+
else {
|
|
1856
|
+
object = [];
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
else if (headByte === 0xdd) {
|
|
1860
|
+
// array 32
|
|
1861
|
+
const size = this.readU32();
|
|
1862
|
+
if (size !== 0) {
|
|
1863
|
+
this.pushArrayState(size);
|
|
1864
|
+
this.complete();
|
|
1865
|
+
continue DECODE;
|
|
1866
|
+
}
|
|
1867
|
+
else {
|
|
1868
|
+
object = [];
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
else if (headByte === 0xde) {
|
|
1872
|
+
// map 16
|
|
1873
|
+
const size = this.readU16();
|
|
1874
|
+
if (size !== 0) {
|
|
1875
|
+
this.pushMapState(size);
|
|
1876
|
+
this.complete();
|
|
1877
|
+
continue DECODE;
|
|
1878
|
+
}
|
|
1879
|
+
else {
|
|
1880
|
+
object = {};
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
else if (headByte === 0xdf) {
|
|
1884
|
+
// map 32
|
|
1885
|
+
const size = this.readU32();
|
|
1886
|
+
if (size !== 0) {
|
|
1887
|
+
this.pushMapState(size);
|
|
1888
|
+
this.complete();
|
|
1889
|
+
continue DECODE;
|
|
1890
|
+
}
|
|
1891
|
+
else {
|
|
1892
|
+
object = {};
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
else if (headByte === 0xc4) {
|
|
1896
|
+
// bin 8
|
|
1897
|
+
const size = this.lookU8();
|
|
1898
|
+
object = this.decodeBinary(size, 1);
|
|
1899
|
+
}
|
|
1900
|
+
else if (headByte === 0xc5) {
|
|
1901
|
+
// bin 16
|
|
1902
|
+
const size = this.lookU16();
|
|
1903
|
+
object = this.decodeBinary(size, 2);
|
|
1904
|
+
}
|
|
1905
|
+
else if (headByte === 0xc6) {
|
|
1906
|
+
// bin 32
|
|
1907
|
+
const size = this.lookU32();
|
|
1908
|
+
object = this.decodeBinary(size, 4);
|
|
1909
|
+
}
|
|
1910
|
+
else if (headByte === 0xd4) {
|
|
1911
|
+
// fixext 1
|
|
1912
|
+
object = this.decodeExtension(1, 0);
|
|
1913
|
+
}
|
|
1914
|
+
else if (headByte === 0xd5) {
|
|
1915
|
+
// fixext 2
|
|
1916
|
+
object = this.decodeExtension(2, 0);
|
|
1917
|
+
}
|
|
1918
|
+
else if (headByte === 0xd6) {
|
|
1919
|
+
// fixext 4
|
|
1920
|
+
object = this.decodeExtension(4, 0);
|
|
1921
|
+
}
|
|
1922
|
+
else if (headByte === 0xd7) {
|
|
1923
|
+
// fixext 8
|
|
1924
|
+
object = this.decodeExtension(8, 0);
|
|
1925
|
+
}
|
|
1926
|
+
else if (headByte === 0xd8) {
|
|
1927
|
+
// fixext 16
|
|
1928
|
+
object = this.decodeExtension(16, 0);
|
|
1929
|
+
}
|
|
1930
|
+
else if (headByte === 0xc7) {
|
|
1931
|
+
// ext 8
|
|
1932
|
+
const size = this.lookU8();
|
|
1933
|
+
object = this.decodeExtension(size, 1);
|
|
1934
|
+
}
|
|
1935
|
+
else if (headByte === 0xc8) {
|
|
1936
|
+
// ext 16
|
|
1937
|
+
const size = this.lookU16();
|
|
1938
|
+
object = this.decodeExtension(size, 2);
|
|
1939
|
+
}
|
|
1940
|
+
else if (headByte === 0xc9) {
|
|
1941
|
+
// ext 32
|
|
1942
|
+
const size = this.lookU32();
|
|
1943
|
+
object = this.decodeExtension(size, 4);
|
|
1944
|
+
}
|
|
1945
|
+
else {
|
|
1946
|
+
throw new DecodeError(`Unrecognized type byte: ${prettyByte(headByte)}`);
|
|
1947
|
+
}
|
|
1948
|
+
this.complete();
|
|
1949
|
+
const stack = this.stack;
|
|
1950
|
+
while (stack.length > 0) {
|
|
1951
|
+
// arrays and maps
|
|
1952
|
+
const state = stack.top();
|
|
1953
|
+
if (state.type === STATE_ARRAY) {
|
|
1954
|
+
state.array[state.position] = object;
|
|
1955
|
+
state.position++;
|
|
1956
|
+
if (state.position === state.size) {
|
|
1957
|
+
object = state.array;
|
|
1958
|
+
stack.release(state);
|
|
1959
|
+
}
|
|
1960
|
+
else {
|
|
1961
|
+
continue DECODE;
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
else if (state.type === STATE_MAP_KEY) {
|
|
1965
|
+
if (object === "__proto__") {
|
|
1966
|
+
throw new DecodeError("The key __proto__ is not allowed");
|
|
1967
|
+
}
|
|
1968
|
+
state.key = this.mapKeyConverter(object);
|
|
1969
|
+
state.type = STATE_MAP_VALUE;
|
|
1970
|
+
continue DECODE;
|
|
1971
|
+
}
|
|
1972
|
+
else {
|
|
1973
|
+
// it must be `state.type === State.MAP_VALUE` here
|
|
1974
|
+
state.map[state.key] = object;
|
|
1975
|
+
state.readCount++;
|
|
1976
|
+
if (state.readCount === state.size) {
|
|
1977
|
+
object = state.map;
|
|
1978
|
+
stack.release(state);
|
|
1979
|
+
}
|
|
1980
|
+
else {
|
|
1981
|
+
state.key = null;
|
|
1982
|
+
state.type = STATE_MAP_KEY;
|
|
1983
|
+
continue DECODE;
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
return object;
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
readHeadByte() {
|
|
1991
|
+
if (this.headByte === HEAD_BYTE_REQUIRED) {
|
|
1992
|
+
this.headByte = this.readU8();
|
|
1993
|
+
// console.log("headByte", prettyByte(this.headByte));
|
|
1994
|
+
}
|
|
1995
|
+
return this.headByte;
|
|
1996
|
+
}
|
|
1997
|
+
complete() {
|
|
1998
|
+
this.headByte = HEAD_BYTE_REQUIRED;
|
|
1999
|
+
}
|
|
2000
|
+
readArraySize() {
|
|
2001
|
+
const headByte = this.readHeadByte();
|
|
2002
|
+
switch (headByte) {
|
|
2003
|
+
case 0xdc:
|
|
2004
|
+
return this.readU16();
|
|
2005
|
+
case 0xdd:
|
|
2006
|
+
return this.readU32();
|
|
2007
|
+
default: {
|
|
2008
|
+
if (headByte < 0xa0) {
|
|
2009
|
+
return headByte - 0x90;
|
|
2010
|
+
}
|
|
2011
|
+
else {
|
|
2012
|
+
throw new DecodeError(`Unrecognized array type byte: ${prettyByte(headByte)}`);
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
pushMapState(size) {
|
|
2018
|
+
if (size > this.maxMapLength) {
|
|
2019
|
+
throw new DecodeError(`Max length exceeded: map length (${size}) > maxMapLengthLength (${this.maxMapLength})`);
|
|
2020
|
+
}
|
|
2021
|
+
this.stack.pushMapState(size);
|
|
2022
|
+
}
|
|
2023
|
+
pushArrayState(size) {
|
|
2024
|
+
if (size > this.maxArrayLength) {
|
|
2025
|
+
throw new DecodeError(`Max length exceeded: array length (${size}) > maxArrayLength (${this.maxArrayLength})`);
|
|
2026
|
+
}
|
|
2027
|
+
this.stack.pushArrayState(size);
|
|
2028
|
+
}
|
|
2029
|
+
decodeString(byteLength, headerOffset) {
|
|
2030
|
+
if (!this.rawStrings || this.stateIsMapKey()) {
|
|
2031
|
+
return this.decodeUtf8String(byteLength, headerOffset);
|
|
2032
|
+
}
|
|
2033
|
+
return this.decodeBinary(byteLength, headerOffset);
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* @throws {@link RangeError}
|
|
2037
|
+
*/
|
|
2038
|
+
decodeUtf8String(byteLength, headerOffset) {
|
|
2039
|
+
if (byteLength > this.maxStrLength) {
|
|
2040
|
+
throw new DecodeError(`Max length exceeded: UTF-8 byte length (${byteLength}) > maxStrLength (${this.maxStrLength})`);
|
|
2041
|
+
}
|
|
2042
|
+
if (this.bytes.byteLength < this.pos + headerOffset + byteLength) {
|
|
2043
|
+
throw MORE_DATA;
|
|
2044
|
+
}
|
|
2045
|
+
const offset = this.pos + headerOffset;
|
|
2046
|
+
let object;
|
|
2047
|
+
if (this.stateIsMapKey() && this.keyDecoder?.canBeCached(byteLength)) {
|
|
2048
|
+
object = this.keyDecoder.decode(this.bytes, offset, byteLength);
|
|
2049
|
+
}
|
|
2050
|
+
else {
|
|
2051
|
+
object = utf8Decode(this.bytes, offset, byteLength);
|
|
2052
|
+
}
|
|
2053
|
+
this.pos += headerOffset + byteLength;
|
|
2054
|
+
return object;
|
|
2055
|
+
}
|
|
2056
|
+
stateIsMapKey() {
|
|
2057
|
+
if (this.stack.length > 0) {
|
|
2058
|
+
const state = this.stack.top();
|
|
2059
|
+
return state.type === STATE_MAP_KEY;
|
|
2060
|
+
}
|
|
2061
|
+
return false;
|
|
2062
|
+
}
|
|
2063
|
+
/**
|
|
2064
|
+
* @throws {@link RangeError}
|
|
2065
|
+
*/
|
|
2066
|
+
decodeBinary(byteLength, headOffset) {
|
|
2067
|
+
if (byteLength > this.maxBinLength) {
|
|
2068
|
+
throw new DecodeError(`Max length exceeded: bin length (${byteLength}) > maxBinLength (${this.maxBinLength})`);
|
|
2069
|
+
}
|
|
2070
|
+
if (!this.hasRemaining(byteLength + headOffset)) {
|
|
2071
|
+
throw MORE_DATA;
|
|
2072
|
+
}
|
|
2073
|
+
const offset = this.pos + headOffset;
|
|
2074
|
+
const object = this.bytes.subarray(offset, offset + byteLength);
|
|
2075
|
+
this.pos += headOffset + byteLength;
|
|
2076
|
+
return object;
|
|
2077
|
+
}
|
|
2078
|
+
decodeExtension(size, headOffset) {
|
|
2079
|
+
if (size > this.maxExtLength) {
|
|
2080
|
+
throw new DecodeError(`Max length exceeded: ext length (${size}) > maxExtLength (${this.maxExtLength})`);
|
|
2081
|
+
}
|
|
2082
|
+
const extType = this.view.getInt8(this.pos + headOffset);
|
|
2083
|
+
const data = this.decodeBinary(size, headOffset + 1 /* extType */);
|
|
2084
|
+
return this.extensionCodec.decode(data, extType, this.context);
|
|
2085
|
+
}
|
|
2086
|
+
lookU8() {
|
|
2087
|
+
return this.view.getUint8(this.pos);
|
|
2088
|
+
}
|
|
2089
|
+
lookU16() {
|
|
2090
|
+
return this.view.getUint16(this.pos);
|
|
2091
|
+
}
|
|
2092
|
+
lookU32() {
|
|
2093
|
+
return this.view.getUint32(this.pos);
|
|
2094
|
+
}
|
|
2095
|
+
readU8() {
|
|
2096
|
+
const value = this.view.getUint8(this.pos);
|
|
2097
|
+
this.pos++;
|
|
2098
|
+
return value;
|
|
2099
|
+
}
|
|
2100
|
+
readI8() {
|
|
2101
|
+
const value = this.view.getInt8(this.pos);
|
|
2102
|
+
this.pos++;
|
|
2103
|
+
return value;
|
|
2104
|
+
}
|
|
2105
|
+
readU16() {
|
|
2106
|
+
const value = this.view.getUint16(this.pos);
|
|
2107
|
+
this.pos += 2;
|
|
2108
|
+
return value;
|
|
2109
|
+
}
|
|
2110
|
+
readI16() {
|
|
2111
|
+
const value = this.view.getInt16(this.pos);
|
|
2112
|
+
this.pos += 2;
|
|
2113
|
+
return value;
|
|
2114
|
+
}
|
|
2115
|
+
readU32() {
|
|
2116
|
+
const value = this.view.getUint32(this.pos);
|
|
2117
|
+
this.pos += 4;
|
|
2118
|
+
return value;
|
|
2119
|
+
}
|
|
2120
|
+
readI32() {
|
|
2121
|
+
const value = this.view.getInt32(this.pos);
|
|
2122
|
+
this.pos += 4;
|
|
2123
|
+
return value;
|
|
2124
|
+
}
|
|
2125
|
+
readU64() {
|
|
2126
|
+
const value = getUint64(this.view, this.pos);
|
|
2127
|
+
this.pos += 8;
|
|
2128
|
+
return value;
|
|
2129
|
+
}
|
|
2130
|
+
readI64() {
|
|
2131
|
+
const value = getInt64(this.view, this.pos);
|
|
2132
|
+
this.pos += 8;
|
|
2133
|
+
return value;
|
|
2134
|
+
}
|
|
2135
|
+
readU64AsBigInt() {
|
|
2136
|
+
const value = this.view.getBigUint64(this.pos);
|
|
2137
|
+
this.pos += 8;
|
|
2138
|
+
return value;
|
|
2139
|
+
}
|
|
2140
|
+
readI64AsBigInt() {
|
|
2141
|
+
const value = this.view.getBigInt64(this.pos);
|
|
2142
|
+
this.pos += 8;
|
|
2143
|
+
return value;
|
|
2144
|
+
}
|
|
2145
|
+
readF32() {
|
|
2146
|
+
const value = this.view.getFloat32(this.pos);
|
|
2147
|
+
this.pos += 4;
|
|
2148
|
+
return value;
|
|
2149
|
+
}
|
|
2150
|
+
readF64() {
|
|
2151
|
+
const value = this.view.getFloat64(this.pos);
|
|
2152
|
+
this.pos += 8;
|
|
2153
|
+
return value;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
/**
|
|
2158
|
+
* It decodes a single MessagePack object in a buffer.
|
|
2159
|
+
*
|
|
2160
|
+
* This is a synchronous decoding function.
|
|
2161
|
+
* See other variants for asynchronous decoding: {@link decodeAsync}, {@link decodeMultiStream}, or {@link decodeArrayStream}.
|
|
2162
|
+
*
|
|
2163
|
+
* @throws {@link RangeError} if the buffer is incomplete, including the case where the buffer is empty.
|
|
2164
|
+
* @throws {@link DecodeError} if the buffer contains invalid data.
|
|
2165
|
+
*/
|
|
2166
|
+
function decode(buffer, options) {
|
|
2167
|
+
const decoder = new Decoder(options);
|
|
2168
|
+
return decoder.decode(buffer);
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
/** 读取小程序启动时携带的分享数据。 */
|
|
2172
|
+
function readMiniProgramShareExtra(launchHref) {
|
|
2173
|
+
if (!launchHref)
|
|
2174
|
+
return undefined;
|
|
2175
|
+
try {
|
|
2176
|
+
const value = new URL(launchHref).searchParams.get('extra');
|
|
2177
|
+
if (!value || value.length > 256 || value.length % 4 === 1 || !/^[A-Za-z0-9_-]+$/.test(value)) {
|
|
2178
|
+
return undefined;
|
|
2179
|
+
}
|
|
2180
|
+
const bytes = decodeBase64Url(value);
|
|
2181
|
+
if (bytes.byteLength > 128)
|
|
2182
|
+
return undefined;
|
|
2183
|
+
const decoded = decode(bytes);
|
|
2184
|
+
assertExtraValue(decoded);
|
|
2185
|
+
return decoded;
|
|
2186
|
+
}
|
|
2187
|
+
catch {
|
|
2188
|
+
return undefined;
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
function assertExtraValue(value, depth = 0, seen = new WeakSet()) {
|
|
2192
|
+
if (depth > 8)
|
|
2193
|
+
throw new Error('extra nesting depth exceeded');
|
|
2194
|
+
if (value === null || typeof value === 'string' || typeof value === 'boolean')
|
|
2195
|
+
return;
|
|
2196
|
+
if (typeof value === 'number') {
|
|
2197
|
+
if (Number.isFinite(value))
|
|
2198
|
+
return;
|
|
2199
|
+
throw new Error('extra number must be finite');
|
|
2200
|
+
}
|
|
2201
|
+
if (typeof value !== 'object')
|
|
2202
|
+
throw new Error('extra value must be JSON-compatible');
|
|
2203
|
+
if (seen.has(value))
|
|
2204
|
+
throw new Error('extra value must not contain cycles');
|
|
2205
|
+
seen.add(value);
|
|
2206
|
+
if (Array.isArray(value)) {
|
|
2207
|
+
if (value.length > 64)
|
|
2208
|
+
throw new Error('extra array is too large');
|
|
2209
|
+
for (const item of value)
|
|
2210
|
+
assertExtraValue(item, depth + 1, seen);
|
|
2211
|
+
seen.delete(value);
|
|
2212
|
+
return;
|
|
2213
|
+
}
|
|
2214
|
+
const prototype = Object.getPrototypeOf(value);
|
|
2215
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
2216
|
+
throw new Error('extra object must be a plain object');
|
|
2217
|
+
const values = Object.values(value);
|
|
2218
|
+
if (values.length > 64)
|
|
2219
|
+
throw new Error('extra object has too many fields');
|
|
2220
|
+
for (const item of values)
|
|
2221
|
+
assertExtraValue(item, depth + 1, seen);
|
|
2222
|
+
seen.delete(value);
|
|
2223
|
+
}
|
|
2224
|
+
function decodeBase64Url(value) {
|
|
2225
|
+
const normalized = value.replaceAll('-', '+').replaceAll('_', '/');
|
|
2226
|
+
const padded = normalized.padEnd(normalized.length + ((4 - (normalized.length % 4)) % 4), '=');
|
|
2227
|
+
return Uint8Array.from(atob(padded), (character) => character.charCodeAt(0));
|
|
2228
|
+
}
|
|
2229
|
+
|
|
1051
2230
|
/**
|
|
1052
2231
|
* 截图并唤起分享。
|
|
1053
2232
|
*
|
|
@@ -1078,8 +2257,10 @@ function showShareMenu(requester, options) {
|
|
|
1078
2257
|
* @param requester 底层 bridge 请求能力。
|
|
1079
2258
|
* @returns 面向业务层的分享模块对象。
|
|
1080
2259
|
*/
|
|
1081
|
-
function createShareModule(requester) {
|
|
2260
|
+
function createShareModule(requester, launchHref) {
|
|
1082
2261
|
return {
|
|
2262
|
+
copyLink: options => copyLink(requester, options),
|
|
2263
|
+
getExtra: () => readMiniProgramShareExtra(launchHref),
|
|
1083
2264
|
showShareMenu: options => showShareMenu(requester, options),
|
|
1084
2265
|
screenshot: options => screenshot(requester, options),
|
|
1085
2266
|
};
|
|
@@ -1589,10 +2770,11 @@ class MiniProgramSDK {
|
|
|
1589
2770
|
/** 云端数据相关开放能力。 */
|
|
1590
2771
|
cloud;
|
|
1591
2772
|
constructor(options) {
|
|
2773
|
+
const launchHref = (options?.selfWindow ?? getGlobalWindow())?.location.href;
|
|
1592
2774
|
this.client = new MiniProgramBridgeClient(options);
|
|
1593
2775
|
this.auth = createAuthModule(this.client);
|
|
1594
2776
|
this.user = createUserModule(this.client);
|
|
1595
|
-
this.share = createShareModule(this.client);
|
|
2777
|
+
this.share = createShareModule(this.client, launchHref);
|
|
1596
2778
|
this.viewport = createViewportModule(this.client);
|
|
1597
2779
|
this.storage = createStorageModule(this.client);
|
|
1598
2780
|
this.network = createNetworkModule(this.client);
|
|
@@ -1708,6 +2890,8 @@ const user = {
|
|
|
1708
2890
|
};
|
|
1709
2891
|
/** 默认 SDK 实例的分享模块。 */
|
|
1710
2892
|
const share = {
|
|
2893
|
+
copyLink: (options) => getDefaultSDK().share.copyLink(options),
|
|
2894
|
+
getExtra: () => getDefaultSDK().share.getExtra(),
|
|
1711
2895
|
showShareMenu: (options) => getDefaultSDK().share.showShareMenu(options),
|
|
1712
2896
|
screenshot: (options) => getDefaultSDK().share.screenshot(options),
|
|
1713
2897
|
};
|