@tinycloud/sdk-services 3.1.0-beta.11 → 3.1.0-beta.14

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.
@@ -1073,6 +1073,16 @@ declare class KVService extends BaseService implements IKVService {
1073
1073
  private createResponseHeaders;
1074
1074
  private createBatchResponseHeaders;
1075
1075
  private parseBatchValue;
1076
+ /**
1077
+ * Validate a batch read response and return its items in the caller's
1078
+ * request order. The node flattens invocation abilities from a `BTreeMap`,
1079
+ * so results arrive sorted by UTF-8 byte order of the path, not in request
1080
+ * order. Items that carry their path in `key` are matched by path; if no
1081
+ * item carries a key, items are assumed to be in the node's byte-sorted
1082
+ * order and the request is aligned the same way. Any mix of keyed and
1083
+ * keyless items, a missing requested path, an unrequested path, or a
1084
+ * malformed item fails closed (returns undefined).
1085
+ */
1076
1086
  private normalizeBatchReadResponse;
1077
1087
  private batchRead;
1078
1088
  /**
@@ -1073,6 +1073,16 @@ declare class KVService extends BaseService implements IKVService {
1073
1073
  private createResponseHeaders;
1074
1074
  private createBatchResponseHeaders;
1075
1075
  private parseBatchValue;
1076
+ /**
1077
+ * Validate a batch read response and return its items in the caller's
1078
+ * request order. The node flattens invocation abilities from a `BTreeMap`,
1079
+ * so results arrive sorted by UTF-8 byte order of the path, not in request
1080
+ * order. Items that carry their path in `key` are matched by path; if no
1081
+ * item carries a key, items are assumed to be in the node's byte-sorted
1082
+ * order and the request is aligned the same way. Any mix of keyed and
1083
+ * keyless items, a missing requested path, an unrequested path, or a
1084
+ * malformed item fails closed (returns undefined).
1085
+ */
1076
1086
  private normalizeBatchReadResponse;
1077
1087
  private batchRead;
1078
1088
  /**
package/dist/kv/index.js CHANGED
@@ -801,6 +801,18 @@ var MAX_KV_BATCH_READ_ITEMS = 100;
801
801
  function isJsonObject(value) {
802
802
  return typeof value === "object" && value !== null && !Array.isArray(value);
803
803
  }
804
+ var pathByteEncoder = new TextEncoder();
805
+ function comparePathsByBytes(a, b) {
806
+ const left = pathByteEncoder.encode(a);
807
+ const right = pathByteEncoder.encode(b);
808
+ const length = Math.min(left.length, right.length);
809
+ for (let index = 0; index < length; index++) {
810
+ if (left[index] !== right[index]) {
811
+ return left[index] - right[index];
812
+ }
813
+ }
814
+ return left.length - right.length;
815
+ }
804
816
  var REVOKED_BODY = /^(?:Invalid invocation: )?delegation-(?:(revoked): [A-Za-z0-9]+|(ancestor-revoked): ancestor=[A-Za-z0-9]+ invoked=[A-Za-z0-9]+)$/;
805
817
  function revocationCodeOf(body) {
806
818
  const match = REVOKED_BODY.exec(body.trim());
@@ -1034,15 +1046,25 @@ var KVService = class extends BaseService {
1034
1046
  )?.[1];
1035
1047
  return contentType?.includes("application/json") ? JSON.parse(text) : text;
1036
1048
  }
1049
+ /**
1050
+ * Validate a batch read response and return its items in the caller's
1051
+ * request order. The node flattens invocation abilities from a `BTreeMap`,
1052
+ * so results arrive sorted by UTF-8 byte order of the path, not in request
1053
+ * order. Items that carry their path in `key` are matched by path; if no
1054
+ * item carries a key, items are assumed to be in the node's byte-sorted
1055
+ * order and the request is aligned the same way. Any mix of keyed and
1056
+ * keyless items, a missing requested path, an unrequested path, or a
1057
+ * malformed item fails closed (returns undefined).
1058
+ */
1037
1059
  normalizeBatchReadResponse(data, paths, requireData) {
1038
1060
  if (!data || typeof data !== "object") return void 0;
1039
1061
  const response = data;
1040
- if (!Array.isArray(response.results) || response.results.length !== paths.length) {
1062
+ const items = response.results;
1063
+ if (!Array.isArray(items) || items.length !== paths.length) {
1041
1064
  return void 0;
1042
1065
  }
1043
- for (let index = 0; index < response.results.length; index++) {
1044
- const item = response.results[index];
1045
- if (!item || typeof item !== "object" || item.key !== paths[index] || typeof item.ok !== "boolean") {
1066
+ for (const item of items) {
1067
+ if (!item || typeof item !== "object" || typeof item.ok !== "boolean") {
1046
1068
  return void 0;
1047
1069
  }
1048
1070
  if (item.ok && (!item.headers || typeof item.headers !== "object" || Object.values(item.headers).some((value) => typeof value !== "string") || requireData && typeof item.dataBase64 !== "string")) {
@@ -1052,7 +1074,24 @@ var KVService = class extends BaseService {
1052
1074
  return void 0;
1053
1075
  }
1054
1076
  }
1055
- return response;
1077
+ if (items.every((item) => typeof item.key === "string")) {
1078
+ const byPath = new Map(items.map((item) => [item.key, item]));
1079
+ if (byPath.size !== items.length) return void 0;
1080
+ const aligned2 = [];
1081
+ for (const path of paths) {
1082
+ const item = byPath.get(path);
1083
+ if (!item) return void 0;
1084
+ aligned2.push(item);
1085
+ }
1086
+ return aligned2;
1087
+ }
1088
+ if (items.some((item) => item.key !== void 0)) return void 0;
1089
+ const requestOrder = paths.map((_, index) => index).sort((a, b) => comparePathsByBytes(paths[a], paths[b]));
1090
+ const aligned = new Array(items.length);
1091
+ for (let position = 0; position < requestOrder.length; position++) {
1092
+ aligned[requestOrder[position]] = items[position];
1093
+ }
1094
+ return aligned;
1056
1095
  }
1057
1096
  async batchRead(keys, action, options) {
1058
1097
  if (!this.requireAuth()) return err(authRequiredError("kv"));
@@ -1145,19 +1184,19 @@ var KVService = class extends BaseService {
1145
1184
  { meta: { status: response.status, statusText: response.statusText } }
1146
1185
  ));
1147
1186
  }
1148
- const payload = this.normalizeBatchReadResponse(
1187
+ const items = this.normalizeBatchReadResponse(
1149
1188
  await response.json(),
1150
1189
  paths,
1151
1190
  action === KVAction.GET
1152
1191
  );
1153
- if (!payload) {
1192
+ if (!items) {
1154
1193
  return err(serviceError(
1155
1194
  ErrorCodes.NETWORK_ERROR,
1156
1195
  "KV batch read response did not match the requested keys",
1157
1196
  "kv"
1158
1197
  ));
1159
1198
  }
1160
- const results = payload.results.map((item, index) => {
1199
+ const results = items.map((item, index) => {
1161
1200
  if (!item.ok) {
1162
1201
  return {
1163
1202
  key: keys[index],