@oddington/sdk 0.1.9 → 0.1.10

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/README.md CHANGED
@@ -299,9 +299,37 @@ Each graph selection sends one request and returns only selected canonical
299
299
  values, expanded forward links and exact opaque public versions. Cursors
300
300
  continue the exact retained artifact and collection selection, even after
301
301
  replacement; repeat its options and links while omitting unrelated collections.
302
- There is no automatic retry or separate version fetch. History is not included.
302
+ There is no automatic retry or separate version fetch.
303
303
  Collection schemas omit Markdown storage hints.
304
304
 
305
+ Read published History through the same inert repository handle:
306
+
307
+ ```ts
308
+ const versions = await general.history.list({ limit: 50 });
309
+ const older = versions.length
310
+ ? await general.history.list({ before: versions.at(-1)!.version }) : [];
311
+ const close = await general.history.at('2026-10-09T16:30:00Z');
312
+ ```
313
+
314
+ List returns an entry array in descending published sequence, with an exclusive
315
+ visible `before` and a default limit of 50 (integer 1–100). Cutoff accepts a real
316
+ RFC 3339 instant with an explicit offset and returns the greatest visible sequence
317
+ published at or before it, or null. Entries contain exactly `version`, `publishedAt`,
318
+ `author`, `authoredAt`, `committer`, `committedAt`, `message`, `created`, `updated`,
319
+ and `deleted`. Git identities and complete messages are repository facts; changed
320
+ refs are lexical. Versions are opaque published identities, never Git expressions.
321
+ Each operation captures input before resolving authority and makes one request.
322
+ Incomplete selected metadata fails the whole result retryably with `unavailable`;
323
+ current Records remain independent. Hosted routines retain their captured ceiling
324
+ until their own authoritative publication advances it. History is served through
325
+ the member/run Data transport. Local apps and local routines use the same calls;
326
+ their OS parent may acquire one bounded page or cutoff result, retain it against
327
+ the exact repository target and published ceiling, and serve an identical warm
328
+ request without another hosted call. Authority loss, expiry, target replacement
329
+ or published-version replacement invalidates that retained result. Prepared local
330
+ changes do not appear in published History.
331
+ Historical Record selection and `history.changes` are not exposed by this slice.
332
+
305
333
  Use bounded plain-text lookup to find full Records and guards:
306
334
 
307
335
  ```ts
package/dist/browser.js CHANGED
@@ -717,31 +717,65 @@ var DataOperationError = class extends Error {
717
717
 
718
718
  var invalid = () => {
719
719
  throw new DataOperationError("invalid_query");
720
- }, scalarText = (value) => typeof value == "string" && !/[\u0000\uD800-\uDFFF]/u.test(value);
720
+ }, historyText = (value) => typeof value == "string" && !/[\u0000\uD800-\uDFFF]/u.test(value);
721
+ function historyVersion(value) {
722
+ return historyText(value) && value.length > 0 && new TextEncoder().encode(value).length <= 1024 && !/[\u0000-\u001f\u007f-\u009f]/.test(value) && !/^[0-9a-f]{40}$/i.test(value);
723
+ }
724
+ function historyProperties(value) {
725
+ if (!value || typeof value != "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return invalid();
726
+ let descriptors = Object.getOwnPropertyDescriptors(value);
727
+ return Reflect.ownKeys(value).some((key) => typeof key != "string" || !descriptors[key]?.enumerable || !Object.hasOwn(descriptors[key], "value")) ? invalid() : descriptors;
728
+ }
729
+ function captureHistoryListOptions(value) {
730
+ if (value === void 0) return {};
731
+ let descriptors = historyProperties(value), result2 = {};
732
+ if (Object.keys(descriptors).some((key) => !["limit", "before"].includes(key))) return invalid();
733
+ if (Object.hasOwn(descriptors, "limit")) {
734
+ let limit = descriptors.limit.value;
735
+ if (!Number.isInteger(limit) || limit < 1 || limit > 100) return invalid();
736
+ result2.limit = limit;
737
+ }
738
+ if (Object.hasOwn(descriptors, "before")) {
739
+ let before = descriptors.before.value;
740
+ if (!historyVersion(before)) return invalid();
741
+ result2.before = before;
742
+ }
743
+ return result2;
744
+ }
745
+ function captureHistoryInstant(value) {
746
+ if (!historyText(value) || value.length > 1024) return invalid();
747
+ let match = /^(\d{4})-(\d{2})-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(?:\.\d+)?([Zz]|([+-])(\d{2}):(\d{2}))$/.exec(value);
748
+ if (!match) return invalid();
749
+ let [year, month, day, hour, minute, second] = match.slice(1, 7).map(Number), days = new Date(Date.UTC(year, month, 0));
750
+ return days.setUTCFullYear(year), year < 1 || month < 1 || month > 12 || day < 1 || day > days.getUTCDate() || hour > 23 || minute > 59 || second > 59 || Number(match[9] ?? 0) > 23 || Number(match[10] ?? 0) > 59 ? invalid() : value;
751
+ }
752
+
753
+ var invalid2 = () => {
754
+ throw new DataOperationError("invalid_query");
755
+ };
721
756
  function captureRecordsSearchInput(query, options) {
722
- if (!scalarText(query)) return invalid();
757
+ if (!historyText(query)) return invalid2();
723
758
  let length = [...query.trim()].length;
724
- if (length < 1 || length > 256) return invalid();
759
+ if (length < 1 || length > 256) return invalid2();
725
760
  if (options === void 0) return { query };
726
- if (!options || typeof options != "object" || Array.isArray(options) || ![Object.prototype, null].includes(Object.getPrototypeOf(options))) return invalid();
727
- let descriptors = Object.getOwnPropertyDescriptors(options);
728
- if (Reflect.ownKeys(options).some((key) => typeof key != "string" || !["collections", "limit"].includes(key) || !descriptors[key]?.enumerable || !Object.hasOwn(descriptors[key], "value"))) return invalid();
761
+ let descriptors = historyProperties(options);
762
+ if (Object.keys(descriptors).some((key) => !["collections", "limit"].includes(key))) return invalid2();
729
763
  let captured = {};
730
764
  if (Object.hasOwn(descriptors, "collections")) {
731
765
  let supplied = descriptors.collections.value;
732
- if (!Array.isArray(supplied) || supplied.length < 1 || supplied.length > 16 || Reflect.ownKeys(supplied).length !== supplied.length + 1) return invalid();
766
+ if (!Array.isArray(supplied) || supplied.length < 1 || supplied.length > 16 || Reflect.ownKeys(supplied).length !== supplied.length + 1) return invalid2();
733
767
  let collections = [];
734
768
  for (let index = 0; index < supplied.length; index++) {
735
769
  let descriptor2 = Object.getOwnPropertyDescriptor(supplied, String(index));
736
- if (!descriptor2?.enumerable || !Object.hasOwn(descriptor2, "value") || !scalarText(descriptor2.value)) return invalid();
770
+ if (!descriptor2?.enumerable || !Object.hasOwn(descriptor2, "value") || !historyText(descriptor2.value)) return invalid2();
737
771
  collections.push(descriptor2.value);
738
772
  }
739
- if (new Set(collections).size !== collections.length) return invalid();
773
+ if (new Set(collections).size !== collections.length) return invalid2();
740
774
  captured.collections = collections;
741
775
  }
742
776
  if (Object.hasOwn(descriptors, "limit")) {
743
777
  let supplied = descriptors.limit.value;
744
- if (!Number.isInteger(supplied) || supplied < 1 || supplied > 100) return invalid();
778
+ if (!Number.isInteger(supplied) || supplied < 1 || supplied > 100) return invalid2();
745
779
  captured.limit = supplied;
746
780
  }
747
781
  return { query, options: captured };
@@ -842,42 +876,42 @@ var FileOperationError = class extends Error {
842
876
  retryable;
843
877
  }, FILE_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/, FILE_ORIGINAL_MAX_BYTES = 5 * 1024 ** 3;
844
878
  function parseFileDescriptor(value) {
845
- let invalid3 = () => {
879
+ let invalid4 = () => {
846
880
  throw new FileOperationError("unavailable", 503, !0);
847
881
  };
848
- if (!value || typeof value != "object" || Array.isArray(value)) return invalid3();
882
+ if (!value || typeof value != "object" || Array.isArray(value)) return invalid4();
849
883
  let f = value;
850
- if (Object.keys(f).sort().join(",") !== "details,enrichments,id,mediaType,name,path,sha256,size" || typeof f.id != "string" || !FILE_ID_PATTERN.test(f.id) || !safeFileName(f.name) || !safeFilePath(f.path) || !Number.isSafeInteger(f.size) || f.size < 0 || f.size > FILE_ORIGINAL_MAX_BYTES || typeof f.sha256 != "string" || !/^[0-9a-f]{64}$/.test(f.sha256) || !f.enrichments || typeof f.enrichments != "object" || Array.isArray(f.enrichments) || !f.details || typeof f.details != "object" || Array.isArray(f.details)) return invalid3();
884
+ if (Object.keys(f).sort().join(",") !== "details,enrichments,id,mediaType,name,path,sha256,size" || typeof f.id != "string" || !FILE_ID_PATTERN.test(f.id) || !safeFileName(f.name) || !safeFilePath(f.path) || !Number.isSafeInteger(f.size) || f.size < 0 || f.size > FILE_ORIGINAL_MAX_BYTES || typeof f.sha256 != "string" || !/^[0-9a-f]{64}$/.test(f.sha256) || !f.enrichments || typeof f.enrichments != "object" || Array.isArray(f.enrichments) || !f.details || typeof f.details != "object" || Array.isArray(f.details)) return invalid4();
851
885
  let d = f.details;
852
886
  if (d.kind === "other") {
853
- if (Object.keys(d).length !== 1 || f.mediaType !== "application/octet-stream") return invalid3();
887
+ if (Object.keys(d).length !== 1 || f.mediaType !== "application/octet-stream") return invalid4();
854
888
  } else if (d.kind === "csv") {
855
- if (Object.keys(d).sort().join(",") !== "dataRows,delimiter,encoding,headerRow,kind" || f.mediaType !== "text/csv" || !["utf-8", "windows-1252"].includes(d.encoding) || ![",", ";", " "].includes(d.delimiter) || !Number.isSafeInteger(d.headerRow) || d.headerRow < 1 || !Number.isSafeInteger(d.dataRows) || d.dataRows < 0) return invalid3();
856
- } else return invalid3();
889
+ if (Object.keys(d).sort().join(",") !== "dataRows,delimiter,encoding,headerRow,kind" || f.mediaType !== "text/csv" || !["utf-8", "windows-1252"].includes(d.encoding) || ![",", ";", " "].includes(d.delimiter) || !Number.isSafeInteger(d.headerRow) || d.headerRow < 1 || !Number.isSafeInteger(d.dataRows) || d.dataRows < 0) return invalid4();
890
+ } else return invalid4();
857
891
  for (let [name, descriptor2] of Object.entries(f.enrichments)) {
858
- if (!safeEnrichmentName(name)) return invalid3();
892
+ if (!safeEnrichmentName(name)) return invalid4();
859
893
  parseEnrichmentDescriptor(descriptor2);
860
894
  }
861
- return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ? invalid3() : f;
895
+ return new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024 ? invalid4() : f;
862
896
  }
863
897
  function parseEnrichmentDescriptor(value) {
864
- let invalid3 = () => {
898
+ let invalid4 = () => {
865
899
  throw new FileOperationError("unavailable", 503, !0);
866
900
  };
867
- if (!value || typeof value != "object" || Array.isArray(value)) return invalid3();
901
+ if (!value || typeof value != "object" || Array.isArray(value)) return invalid4();
868
902
  let d = value;
869
- return Object.keys(d).sort().join(",") !== "mediaType,sha256,size" || !["application/octet-stream", "text/plain", "text/markdown", "application/json"].includes(d.mediaType) || !Number.isSafeInteger(d.size) || d.size < 0 || d.size > 16 * 1024 * 1024 || typeof d.sha256 != "string" || !/^[0-9a-f]{64}$/.test(d.sha256) ? invalid3() : d;
903
+ return Object.keys(d).sort().join(",") !== "mediaType,sha256,size" || !["application/octet-stream", "text/plain", "text/markdown", "application/json"].includes(d.mediaType) || !Number.isSafeInteger(d.size) || d.size < 0 || d.size > 16 * 1024 * 1024 || typeof d.sha256 != "string" || !/^[0-9a-f]{64}$/.test(d.sha256) ? invalid4() : d;
870
904
  }
871
905
  function safeEnrichmentName(value) {
872
906
  return safeFileName(value) && !/^original(?:\.|$)/i.test(value);
873
907
  }
874
908
  function parseFileEnrichMetadata(value, maxBytes) {
875
- let invalid3 = () => {
909
+ let invalid4 = () => {
876
910
  throw new FileOperationError("invalid_input", 400);
877
911
  };
878
- if (!value || typeof value != "object" || Array.isArray(value)) return invalid3();
912
+ if (!value || typeof value != "object" || Array.isArray(value)) return invalid4();
879
913
  let d = value;
880
- if (Object.keys(d).some((key) => !["name", "size", "mediaType", "replace"].includes(key)) || !safeEnrichmentName(d.name) || !Number.isSafeInteger(d.size) || d.size < 0 || d.mediaType !== void 0 && (typeof d.mediaType != "string" || d.mediaType.length > 255 || /[\u0000-\u001f\u007f]/.test(d.mediaType)) || d.replace !== void 0 && (typeof d.replace != "string" || !/^[0-9a-f]{64}$/.test(d.replace))) return invalid3();
914
+ if (Object.keys(d).some((key) => !["name", "size", "mediaType", "replace"].includes(key)) || !safeEnrichmentName(d.name) || !Number.isSafeInteger(d.size) || d.size < 0 || d.mediaType !== void 0 && (typeof d.mediaType != "string" || d.mediaType.length > 255 || /[\u0000-\u001f\u007f]/.test(d.mediaType)) || d.replace !== void 0 && (typeof d.replace != "string" || !/^[0-9a-f]{64}$/.test(d.replace))) return invalid4();
881
915
  if (d.size > maxBytes) throw new FileOperationError("request_too_large", 413);
882
916
  return d;
883
917
  }
@@ -888,23 +922,23 @@ function safeFilePath(value) {
888
922
  return typeof value == "string" && value.length <= 1024 && value.split("/").every(safeFileName);
889
923
  }
890
924
  function parseFileCreateMetadata(value, maxBytes) {
891
- let invalid3 = () => {
925
+ let invalid4 = () => {
892
926
  throw new FileOperationError("invalid_input", 400);
893
927
  };
894
- if (!value || typeof value != "object" || Array.isArray(value)) return invalid3();
928
+ if (!value || typeof value != "object" || Array.isArray(value)) return invalid4();
895
929
  let input = value;
896
- if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "size", "requestKey"].includes(key))) return invalid3();
930
+ if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "size", "requestKey"].includes(key))) return invalid4();
897
931
  let path = input.path === void 0 ? "Files" : input.path;
898
- if (!safeFileName(input.name) || !safeFilePath(path) || input.storage !== void 0 && input.storage !== "remote" && input.storage !== "local" || !Number.isSafeInteger(input.size) || input.size < 0) return invalid3();
932
+ if (!safeFileName(input.name) || !safeFilePath(path) || input.storage !== void 0 && input.storage !== "remote" && input.storage !== "local" || !Number.isSafeInteger(input.size) || input.size < 0) return invalid4();
899
933
  if (input.size > maxBytes) throw new FileOperationError("request_too_large", 413);
900
- if (typeof input.requestKey != "string" || input.requestKey.length < 1 || input.requestKey.length > 256 || input.requestKey !== input.requestKey.trim() || /[\u0000-\u001f\u007f]/.test(input.requestKey)) return invalid3();
934
+ if (typeof input.requestKey != "string" || input.requestKey.length < 1 || input.requestKey.length > 256 || input.requestKey !== input.requestKey.trim() || /[\u0000-\u001f\u007f]/.test(input.requestKey)) return invalid4();
901
935
  let csv;
902
936
  if (input.csv !== void 0) {
903
- if (!input.csv || typeof input.csv != "object" || Array.isArray(input.csv)) return invalid3();
937
+ if (!input.csv || typeof input.csv != "object" || Array.isArray(input.csv)) return invalid4();
904
938
  let hints = input.csv;
905
- if (Object.keys(hints).some((key) => !["encoding", "delimiter", "headerRow"].includes(key))) return invalid3();
939
+ if (Object.keys(hints).some((key) => !["encoding", "delimiter", "headerRow"].includes(key))) return invalid4();
906
940
  let encoding = hints.encoding === void 0 ? "utf-8" : hints.encoding, delimiter = hints.delimiter === void 0 ? "," : hints.delimiter, headerRow = hints.headerRow === void 0 ? 1 : hints.headerRow;
907
- if (encoding !== "utf-8" && encoding !== "windows-1252" || ![",", ";", " "].includes(delimiter) || !Number.isSafeInteger(headerRow) || headerRow < 1 || headerRow > 1e5) return invalid3();
941
+ if (encoding !== "utf-8" && encoding !== "windows-1252" || ![",", ";", " "].includes(delimiter) || !Number.isSafeInteger(headerRow) || headerRow < 1 || headerRow > 1e5) return invalid4();
908
942
  csv = { encoding, delimiter, headerRow };
909
943
  }
910
944
  return {
@@ -992,13 +1026,14 @@ var data = {
992
1026
  async function send2(input) {
993
1027
  let context2 = await resolveDataContext();
994
1028
  try {
995
- if (checkDataRequestSize({ repository, ...input }), "local" in context2) return await context2.local("data/query", { repository, ...input });
1029
+ let envelope = { repository, ...input };
1030
+ if (checkDataRequestSize(envelope), "local" in context2) return await context2.local("data/query", envelope);
996
1031
  let response = await fetch(context2.url, {
997
1032
  method: "POST",
998
1033
  redirect: "error",
999
1034
  cache: "no-store",
1000
1035
  headers: { "content-type": "application/json", ...context2.headers },
1001
- body: JSON.stringify({ repository, ...input })
1036
+ body: JSON.stringify(envelope)
1002
1037
  }), result2 = await response.json();
1003
1038
  if (!response.ok)
1004
1039
  throw dataTransportError(response.status, result2);
@@ -1014,13 +1049,11 @@ var data = {
1014
1049
  },
1015
1050
  records: {
1016
1051
  select: (query) => send2({ operation: "records.select", query }),
1017
- search: (query, options) => {
1018
- try {
1019
- return send2({ operation: "records.search", ...captureRecordsSearchInput(query, options) });
1020
- } catch (error) {
1021
- return Promise.reject(error);
1022
- }
1023
- }
1052
+ search: async (query, options) => send2({ operation: "records.search", ...captureRecordsSearchInput(query, options) })
1053
+ },
1054
+ history: {
1055
+ list: async (options) => send2({ operation: "history.list", options: captureHistoryListOptions(options) }),
1056
+ at: async (instant) => send2({ operation: "history.at", instant: captureHistoryInstant(instant) })
1024
1057
  },
1025
1058
  changes() {
1026
1059
  let updates = [], creates = [], deletes = [], publicationId, pending, confirmed, snapshot = () => {
@@ -1104,7 +1137,7 @@ var data = {
1104
1137
  }
1105
1138
  };
1106
1139
 
1107
- var MAX_BYTES = 16 * 1024 * 1024, PART_BYTES = 8 * 1024 * 1024, METADATA_BYTES = 4096, RESULT_BYTES = 16 * 1024, CONTROL_RESULT_BYTES = 128 * 1024, TIMEOUT_MS = 3e4, MAX_ACTIVE = 4, ATTEMPTS = 2, active = 0, invalid2 = () => new FileOperationError("invalid_input", 400), unavailable = () => new FileOperationError("unavailable", 503, !0), failures = {
1140
+ var MAX_BYTES = 16 * 1024 * 1024, PART_BYTES = 8 * 1024 * 1024, METADATA_BYTES = 4096, RESULT_BYTES = 16 * 1024, CONTROL_RESULT_BYTES = 128 * 1024, TIMEOUT_MS = 3e4, MAX_ACTIVE = 4, ATTEMPTS = 2, active = 0, invalid3 = () => new FileOperationError("invalid_input", 400), unavailable = () => new FileOperationError("unavailable", 503, !0), failures = {
1108
1141
  400: ["invalid_input", "unsupported_context"],
1109
1142
  401: ["unauthenticated"],
1110
1143
  403: ["access_denied"],
@@ -1121,7 +1154,7 @@ async function boundedBytes(stream, limit) {
1121
1154
  for (; ; ) {
1122
1155
  let { done, value } = await reader.read();
1123
1156
  if (done) break;
1124
- if (!(value instanceof Uint8Array)) throw invalid2();
1157
+ if (!(value instanceof Uint8Array)) throw invalid3();
1125
1158
  if (size += value.byteLength, size > limit) throw new FileOperationError("request_too_large", 413);
1126
1159
  bytes.set(value, size - value.byteLength);
1127
1160
  }
@@ -1249,7 +1282,7 @@ async function send(suffix, init2, descriptor2, initial, parent) {
1249
1282
  throw unavailable();
1250
1283
  }
1251
1284
  function idPath(id2) {
1252
- if (typeof id2 != "string" || !FILE_ID_PATTERN.test(id2)) throw invalid2();
1285
+ if (typeof id2 != "string" || !FILE_ID_PATTERN.test(id2)) throw invalid3();
1253
1286
  return `/${id2}`;
1254
1287
  }
1255
1288
  async function multipartCreate(input, metadata, exchange, release = () => {
@@ -1292,18 +1325,18 @@ async function multipartCreate(input, metadata, exchange, release = () => {
1292
1325
  if (!chunk || offset === chunk.byteLength) {
1293
1326
  chunk = void 0, offset = 0;
1294
1327
  let value2 = await next();
1295
- if (value2.done || !(value2.value instanceof Uint8Array) || (chunk = value2.value, chunk.byteLength > metadata.size - sent - filled)) throw invalid2();
1328
+ if (value2.done || !(value2.value instanceof Uint8Array) || (chunk = value2.value, chunk.byteLength > metadata.size - sent - filled)) throw invalid3();
1296
1329
  }
1297
1330
  let take = Math.min(length - filled, chunk.byteLength - offset);
1298
1331
  part.set(chunk.subarray(offset, offset + take), filled), filled += take, offset += take, offset === chunk.byteLength && (chunk = void 0, offset = 0);
1299
1332
  }
1300
1333
  }
1301
- if (part.byteLength !== length) throw invalid2();
1334
+ if (part.byteLength !== length) throw invalid3();
1302
1335
  if (reader && sent + length === metadata.size)
1303
1336
  for (lastProgress = Date.now(); ; ) {
1304
1337
  let value2 = await next();
1305
1338
  if (value2.done) break;
1306
- if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw invalid2();
1339
+ if (!(value2.value instanceof Uint8Array) || value2.value.byteLength) throw invalid3();
1307
1340
  }
1308
1341
  let value = await request((signal) => exchange(`${route}/part`, {
1309
1342
  method: "POST",
@@ -1317,7 +1350,7 @@ async function multipartCreate(input, metadata, exchange, release = () => {
1317
1350
  }
1318
1351
  if (upload) for (let name of Object.keys(upload.file.enrichments)) {
1319
1352
  let bytes = await request(() => upload.enrichment(name));
1320
- if (bytes.byteLength !== upload.file.enrichments[name].size || bytes.byteLength > MAX_BYTES) throw invalid2();
1353
+ if (bytes.byteLength !== upload.file.enrichments[name].size || bytes.byteLength > MAX_BYTES) throw invalid3();
1321
1354
  await request((signal) => exchange(`${route}/enrichments/${encodeURIComponent(name)}`, {
1322
1355
  method: "POST",
1323
1356
  headers: { "content-type": "application/octet-stream", "x-oddington-transfer": ticket },
@@ -1361,7 +1394,7 @@ async function operation(work, initial, parent) {
1361
1394
  function contentPath(id2, name) {
1362
1395
  let path = idPath(id2);
1363
1396
  if (name === void 0) return `${path}/content`;
1364
- if (!safeEnrichmentName(name)) throw invalid2();
1397
+ if (!safeEnrichmentName(name)) throw invalid3();
1365
1398
  return `${path}/enrichments/${encodeURIComponent(name)}/content`;
1366
1399
  }
1367
1400
  async function read(id2, names) {
@@ -1370,12 +1403,12 @@ async function read(id2, names) {
1370
1403
  let path = contentPath(id2, names);
1371
1404
  return operation((context3, signal) => send(path, { method: "GET" }, !1, context3, signal), context2);
1372
1405
  }
1373
- if (!Array.isArray(names)) throw invalid2();
1406
+ if (!Array.isArray(names)) throw invalid3();
1374
1407
  let distinct = [], seen = /* @__PURE__ */ new Set();
1375
1408
  for (let name of names) {
1376
- if (typeof name != "string" || !safeEnrichmentName(name)) throw invalid2();
1409
+ if (typeof name != "string" || !safeEnrichmentName(name)) throw invalid3();
1377
1410
  if (!seen.has(name)) {
1378
- if (seen.size === 16) throw invalid2();
1411
+ if (seen.size === 16) throw invalid3();
1379
1412
  seen.add(name), distinct.push(name);
1380
1413
  }
1381
1414
  }
@@ -1407,11 +1440,11 @@ var files = {
1407
1440
  async create(input, options) {
1408
1441
  let context2 = await resolveFilesContext();
1409
1442
  if (!input || typeof input != "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "size", "path", "name", "storage", "csv"].includes(key)) || options !== void 0 && (!options || typeof options != "object" || Array.isArray(options) || Object.keys(options).some((key) => key !== "requestKey")))
1410
- throw invalid2();
1443
+ throw invalid3();
1411
1444
  let blob = input.file instanceof Blob, array2 = input.file instanceof Uint8Array, stream = input.file instanceof ReadableStream;
1412
- if (!blob && !array2 && !stream) throw invalid2();
1445
+ if (!blob && !array2 && !stream) throw invalid3();
1413
1446
  let intrinsic = blob ? input.file.size : array2 ? input.file.byteLength : void 0;
1414
- if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw invalid2();
1447
+ if (intrinsic !== void 0 && input.size !== void 0 && input.size !== intrinsic) throw invalid3();
1415
1448
  let name = input.name;
1416
1449
  name === void 0 && blob && "name" in input.file && typeof input.file.name == "string" && (name = typeof globalThis.File < "u" && input.file instanceof globalThis.File ? input.file.name : input.file.name.split(/[\\/]/).at(-1));
1417
1450
  let metadata = parseFileCreateMetadata({
@@ -1424,7 +1457,7 @@ var files = {
1424
1457
  }, FILE_ORIGINAL_MAX_BYTES);
1425
1458
  if (!context2.local && metadata.storage === "local") throw new FileOperationError("unsupported_context", 400);
1426
1459
  let header = encodeURIComponent(JSON.stringify(metadata));
1427
- if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid2();
1460
+ if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid3();
1428
1461
  if (active >= MAX_ACTIVE) throw new FileOperationError("capacity", 429, !0);
1429
1462
  if (active++, context2.localFiles && metadata.size > MAX_BYTES) {
1430
1463
  let controller = new AbortController(), file = input.file, offset = 0, body2 = file instanceof ReadableStream ? file : file instanceof Blob ? file.stream() : new ReadableStream({
@@ -1452,7 +1485,7 @@ var files = {
1452
1485
  blob ? input.file.stream() : input.file,
1453
1486
  metadata.size
1454
1487
  );
1455
- if (bytes.byteLength !== metadata.size) throw invalid2();
1488
+ if (bytes.byteLength !== metadata.size) throw invalid3();
1456
1489
  if (signal.aborted) throw unavailable();
1457
1490
  return await send("", {
1458
1491
  method: "POST",
@@ -1468,7 +1501,7 @@ var files = {
1468
1501
  },
1469
1502
  async enrich(input) {
1470
1503
  let context2 = await resolveFilesContext();
1471
- if (!input || typeof input != "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "name", "content", "mediaType", "replace"].includes(key)) || typeof input.content != "string" && !(input.content instanceof Uint8Array)) throw invalid2();
1504
+ if (!input || typeof input != "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "name", "content", "mediaType", "replace"].includes(key)) || typeof input.content != "string" && !(input.content instanceof Uint8Array)) throw invalid3();
1472
1505
  let path = `${idPath(input.file)}/enrichments`;
1473
1506
  if (typeof input.content == "string" ? input.content.length > MAX_BYTES : input.content.byteLength > MAX_BYTES)
1474
1507
  throw new FileOperationError("request_too_large", 413);
@@ -1485,7 +1518,7 @@ var files = {
1485
1518
  ...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
1486
1519
  ...input.replace === void 0 ? {} : { replace: input.replace }
1487
1520
  }, MAX_BYTES), header = encodeURIComponent(JSON.stringify(metadata));
1488
- if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid2();
1521
+ if (new TextEncoder().encode(header).byteLength > METADATA_BYTES) throw invalid3();
1489
1522
  let result2 = await send(path, { method: "POST", headers: {
1490
1523
  "content-type": "application/octet-stream",
1491
1524
  "x-oddington-enrichment": header
package/dist/index.js CHANGED
@@ -21709,44 +21709,91 @@ class DataOperationError extends Error {
21709
21709
  }
21710
21710
  }
21711
21711
 
21712
- // ../../shared/data-search-input.ts
21712
+ // ../../shared/data-history-input.ts
21713
21713
  var invalid = () => {
21714
21714
  throw new DataOperationError("invalid_query");
21715
21715
  };
21716
- var scalarText = (value) => typeof value === "string" && !/[\u0000\uD800-\uDFFF]/u.test(value);
21717
- function captureRecordsSearchInput(query, options) {
21718
- if (!scalarText(query))
21716
+ var historyText = (value) => typeof value === "string" && !/[\u0000\uD800-\uDFFF]/u.test(value);
21717
+ function historyVersion(value) {
21718
+ return historyText(value) && value.length > 0 && new TextEncoder().encode(value).length <= 1024 && !/[\u0000-\u001f\u007f-\u009f]/.test(value) && !/^[0-9a-f]{40}$/i.test(value);
21719
+ }
21720
+ function historyProperties(value) {
21721
+ if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value)))
21722
+ return invalid();
21723
+ const descriptors = Object.getOwnPropertyDescriptors(value);
21724
+ if (Reflect.ownKeys(value).some((key) => typeof key !== "string" || !descriptors[key]?.enumerable || !Object.hasOwn(descriptors[key], "value")))
21725
+ return invalid();
21726
+ return descriptors;
21727
+ }
21728
+ function captureHistoryListOptions(value) {
21729
+ if (value === undefined)
21730
+ return {};
21731
+ const descriptors = historyProperties(value), result = {};
21732
+ if (Object.keys(descriptors).some((key) => !["limit", "before"].includes(key)))
21733
+ return invalid();
21734
+ if (Object.hasOwn(descriptors, "limit")) {
21735
+ const limit = descriptors.limit.value;
21736
+ if (!Number.isInteger(limit) || limit < 1 || limit > 100)
21737
+ return invalid();
21738
+ result.limit = limit;
21739
+ }
21740
+ if (Object.hasOwn(descriptors, "before")) {
21741
+ const before = descriptors.before.value;
21742
+ if (!historyVersion(before))
21743
+ return invalid();
21744
+ result.before = before;
21745
+ }
21746
+ return result;
21747
+ }
21748
+ function captureHistoryInstant(value) {
21749
+ if (!historyText(value) || value.length > 1024)
21719
21750
  return invalid();
21751
+ const match = /^(\d{4})-(\d{2})-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(?:\.\d+)?([Zz]|([+-])(\d{2}):(\d{2}))$/.exec(value);
21752
+ if (!match)
21753
+ return invalid();
21754
+ const [year, month, day, hour, minute, second] = match.slice(1, 7).map(Number);
21755
+ const days = new Date(Date.UTC(year, month, 0));
21756
+ days.setUTCFullYear(year);
21757
+ if (year < 1 || month < 1 || month > 12 || day < 1 || day > days.getUTCDate() || hour > 23 || minute > 59 || second > 59 || Number(match[9] ?? 0) > 23 || Number(match[10] ?? 0) > 59)
21758
+ return invalid();
21759
+ return value;
21760
+ }
21761
+
21762
+ // ../../shared/data-search-input.ts
21763
+ var invalid2 = () => {
21764
+ throw new DataOperationError("invalid_query");
21765
+ };
21766
+ function captureRecordsSearchInput(query, options) {
21767
+ if (!historyText(query))
21768
+ return invalid2();
21720
21769
  const length = [...query.trim()].length;
21721
21770
  if (length < 1 || length > 256)
21722
- return invalid();
21771
+ return invalid2();
21723
21772
  if (options === undefined)
21724
21773
  return { query };
21725
- if (!options || typeof options !== "object" || Array.isArray(options) || ![Object.prototype, null].includes(Object.getPrototypeOf(options)))
21726
- return invalid();
21727
- const descriptors = Object.getOwnPropertyDescriptors(options);
21728
- if (Reflect.ownKeys(options).some((key) => typeof key !== "string" || !["collections", "limit"].includes(key) || !descriptors[key]?.enumerable || !Object.hasOwn(descriptors[key], "value")))
21729
- return invalid();
21774
+ const descriptors = historyProperties(options);
21775
+ if (Object.keys(descriptors).some((key) => !["collections", "limit"].includes(key)))
21776
+ return invalid2();
21730
21777
  const captured = {};
21731
21778
  if (Object.hasOwn(descriptors, "collections")) {
21732
21779
  const supplied = descriptors.collections.value;
21733
21780
  if (!Array.isArray(supplied) || supplied.length < 1 || supplied.length > 16 || Reflect.ownKeys(supplied).length !== supplied.length + 1)
21734
- return invalid();
21781
+ return invalid2();
21735
21782
  const collections = [];
21736
21783
  for (let index = 0;index < supplied.length; index++) {
21737
21784
  const descriptor = Object.getOwnPropertyDescriptor(supplied, String(index));
21738
- if (!descriptor?.enumerable || !Object.hasOwn(descriptor, "value") || !scalarText(descriptor.value))
21739
- return invalid();
21785
+ if (!descriptor?.enumerable || !Object.hasOwn(descriptor, "value") || !historyText(descriptor.value))
21786
+ return invalid2();
21740
21787
  collections.push(descriptor.value);
21741
21788
  }
21742
21789
  if (new Set(collections).size !== collections.length)
21743
- return invalid();
21790
+ return invalid2();
21744
21791
  captured.collections = collections;
21745
21792
  }
21746
21793
  if (Object.hasOwn(descriptors, "limit")) {
21747
21794
  const supplied = descriptors.limit.value;
21748
21795
  if (!Number.isInteger(supplied) || supplied < 1 || supplied > 100)
21749
- return invalid();
21796
+ return invalid2();
21750
21797
  captured.limit = supplied;
21751
21798
  }
21752
21799
  return { query, options: captured };
@@ -21886,55 +21933,55 @@ class FileOperationError extends Error {
21886
21933
  var FILE_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
21887
21934
  var FILE_ORIGINAL_MAX_BYTES = 5 * 1024 ** 3;
21888
21935
  function parseFileDescriptor(value) {
21889
- const invalid2 = () => {
21936
+ const invalid3 = () => {
21890
21937
  throw new FileOperationError("unavailable", 503, true);
21891
21938
  };
21892
21939
  if (!value || typeof value !== "object" || Array.isArray(value))
21893
- return invalid2();
21940
+ return invalid3();
21894
21941
  const f = value;
21895
21942
  if (Object.keys(f).sort().join(",") !== "details,enrichments,id,mediaType,name,path,sha256,size" || typeof f.id !== "string" || !FILE_ID_PATTERN.test(f.id) || !safeFileName(f.name) || !safeFilePath(f.path) || !Number.isSafeInteger(f.size) || f.size < 0 || f.size > FILE_ORIGINAL_MAX_BYTES || typeof f.sha256 !== "string" || !/^[0-9a-f]{64}$/.test(f.sha256) || !f.enrichments || typeof f.enrichments !== "object" || Array.isArray(f.enrichments) || !f.details || typeof f.details !== "object" || Array.isArray(f.details))
21896
- return invalid2();
21943
+ return invalid3();
21897
21944
  const d = f.details;
21898
21945
  if (d.kind === "other") {
21899
21946
  if (Object.keys(d).length !== 1 || f.mediaType !== "application/octet-stream")
21900
- return invalid2();
21947
+ return invalid3();
21901
21948
  } else if (d.kind === "csv") {
21902
21949
  if (Object.keys(d).sort().join(",") !== "dataRows,delimiter,encoding,headerRow,kind" || f.mediaType !== "text/csv" || !["utf-8", "windows-1252"].includes(d.encoding) || ![",", ";", "\t"].includes(d.delimiter) || !Number.isSafeInteger(d.headerRow) || d.headerRow < 1 || !Number.isSafeInteger(d.dataRows) || d.dataRows < 0)
21903
- return invalid2();
21950
+ return invalid3();
21904
21951
  } else
21905
- return invalid2();
21952
+ return invalid3();
21906
21953
  for (const [name, descriptor] of Object.entries(f.enrichments)) {
21907
21954
  if (!safeEnrichmentName(name))
21908
- return invalid2();
21955
+ return invalid3();
21909
21956
  parseEnrichmentDescriptor(descriptor);
21910
21957
  }
21911
21958
  if (new TextEncoder().encode(JSON.stringify(f)).byteLength > 16 * 1024)
21912
- return invalid2();
21959
+ return invalid3();
21913
21960
  return f;
21914
21961
  }
21915
21962
  function parseEnrichmentDescriptor(value) {
21916
- const invalid2 = () => {
21963
+ const invalid3 = () => {
21917
21964
  throw new FileOperationError("unavailable", 503, true);
21918
21965
  };
21919
21966
  if (!value || typeof value !== "object" || Array.isArray(value))
21920
- return invalid2();
21967
+ return invalid3();
21921
21968
  const d = value;
21922
21969
  if (Object.keys(d).sort().join(",") !== "mediaType,sha256,size" || !["application/octet-stream", "text/plain", "text/markdown", "application/json"].includes(d.mediaType) || !Number.isSafeInteger(d.size) || d.size < 0 || d.size > 16 * 1024 * 1024 || typeof d.sha256 !== "string" || !/^[0-9a-f]{64}$/.test(d.sha256))
21923
- return invalid2();
21970
+ return invalid3();
21924
21971
  return d;
21925
21972
  }
21926
21973
  function safeEnrichmentName(value) {
21927
21974
  return safeFileName(value) && !/^original(?:\.|$)/i.test(value);
21928
21975
  }
21929
21976
  function parseFileEnrichMetadata(value, maxBytes) {
21930
- const invalid2 = () => {
21977
+ const invalid3 = () => {
21931
21978
  throw new FileOperationError("invalid_input", 400);
21932
21979
  };
21933
21980
  if (!value || typeof value !== "object" || Array.isArray(value))
21934
- return invalid2();
21981
+ return invalid3();
21935
21982
  const d = value;
21936
21983
  if (Object.keys(d).some((key) => !["name", "size", "mediaType", "replace"].includes(key)) || !safeEnrichmentName(d.name) || !Number.isSafeInteger(d.size) || d.size < 0 || d.mediaType !== undefined && (typeof d.mediaType !== "string" || d.mediaType.length > 255 || /[\u0000-\u001f\u007f]/.test(d.mediaType)) || d.replace !== undefined && (typeof d.replace !== "string" || !/^[0-9a-f]{64}$/.test(d.replace)))
21937
- return invalid2();
21984
+ return invalid3();
21938
21985
  if (d.size > maxBytes)
21939
21986
  throw new FileOperationError("request_too_large", 413);
21940
21987
  return d;
@@ -21946,37 +21993,37 @@ function safeFilePath(value) {
21946
21993
  return typeof value === "string" && value.length <= 1024 && value.split("/").every(safeFileName);
21947
21994
  }
21948
21995
  function parseFileCreateMetadata(value, maxBytes) {
21949
- const invalid2 = () => {
21996
+ const invalid3 = () => {
21950
21997
  throw new FileOperationError("invalid_input", 400);
21951
21998
  };
21952
21999
  if (!value || typeof value !== "object" || Array.isArray(value))
21953
- return invalid2();
22000
+ return invalid3();
21954
22001
  const input = value;
21955
22002
  if (Object.keys(input).some((key) => !["name", "path", "storage", "csv", "size", "requestKey"].includes(key)))
21956
- return invalid2();
22003
+ return invalid3();
21957
22004
  const path = input.path === undefined ? "Files" : input.path;
21958
22005
  if (!safeFileName(input.name) || !safeFilePath(path))
21959
- return invalid2();
22006
+ return invalid3();
21960
22007
  if (input.storage !== undefined && input.storage !== "remote" && input.storage !== "local")
21961
- return invalid2();
22008
+ return invalid3();
21962
22009
  if (!Number.isSafeInteger(input.size) || input.size < 0)
21963
- return invalid2();
22010
+ return invalid3();
21964
22011
  if (input.size > maxBytes)
21965
22012
  throw new FileOperationError("request_too_large", 413);
21966
22013
  if (typeof input.requestKey !== "string" || input.requestKey.length < 1 || input.requestKey.length > 256 || input.requestKey !== input.requestKey.trim() || /[\u0000-\u001f\u007f]/.test(input.requestKey))
21967
- return invalid2();
22014
+ return invalid3();
21968
22015
  let csv;
21969
22016
  if (input.csv !== undefined) {
21970
22017
  if (!input.csv || typeof input.csv !== "object" || Array.isArray(input.csv))
21971
- return invalid2();
22018
+ return invalid3();
21972
22019
  const hints = input.csv;
21973
22020
  if (Object.keys(hints).some((key) => !["encoding", "delimiter", "headerRow"].includes(key)))
21974
- return invalid2();
22021
+ return invalid3();
21975
22022
  const encoding = hints.encoding === undefined ? "utf-8" : hints.encoding;
21976
22023
  const delimiter = hints.delimiter === undefined ? "," : hints.delimiter;
21977
22024
  const headerRow = hints.headerRow === undefined ? 1 : hints.headerRow;
21978
22025
  if (encoding !== "utf-8" && encoding !== "windows-1252" || ![",", ";", "\t"].includes(delimiter) || !Number.isSafeInteger(headerRow) || headerRow < 1 || headerRow > 1e5)
21979
- return invalid2();
22026
+ return invalid3();
21980
22027
  csv = { encoding, delimiter, headerRow };
21981
22028
  }
21982
22029
  return {
@@ -22432,15 +22479,16 @@ var data = {
22432
22479
  async function send(input) {
22433
22480
  const context = await resolveDataContext();
22434
22481
  try {
22435
- checkDataRequestSize({ repository, ...input });
22482
+ const envelope = { repository, ...input };
22483
+ checkDataRequestSize(envelope);
22436
22484
  if ("local" in context)
22437
- return await context.local("data/query", { repository, ...input });
22485
+ return await context.local("data/query", envelope);
22438
22486
  const response = await fetch(context.url, {
22439
22487
  method: "POST",
22440
22488
  redirect: "error",
22441
22489
  cache: "no-store",
22442
22490
  headers: { "content-type": "application/json", ...context.headers },
22443
- body: JSON.stringify({ repository, ...input })
22491
+ body: JSON.stringify(envelope)
22444
22492
  });
22445
22493
  const result = await response.json();
22446
22494
  if (!response.ok) {
@@ -22460,13 +22508,11 @@ var data = {
22460
22508
  },
22461
22509
  records: {
22462
22510
  select: (query) => send({ operation: "records.select", query }),
22463
- search: (query, options) => {
22464
- try {
22465
- return send({ operation: "records.search", ...captureRecordsSearchInput(query, options) });
22466
- } catch (error) {
22467
- return Promise.reject(error);
22468
- }
22469
- }
22511
+ search: async (query, options) => send({ operation: "records.search", ...captureRecordsSearchInput(query, options) })
22512
+ },
22513
+ history: {
22514
+ list: async (options) => send({ operation: "history.list", options: captureHistoryListOptions(options) }),
22515
+ at: async (instant) => send({ operation: "history.at", instant: captureHistoryInstant(instant) })
22470
22516
  },
22471
22517
  changes() {
22472
22518
  let updates = [], creates = [], deletes = [], publicationId;
@@ -22574,7 +22620,7 @@ var TIMEOUT_MS = 30000;
22574
22620
  var MAX_ACTIVE = 4;
22575
22621
  var ATTEMPTS = 2;
22576
22622
  var active = 0;
22577
- var invalid2 = () => new FileOperationError("invalid_input", 400);
22623
+ var invalid3 = () => new FileOperationError("invalid_input", 400);
22578
22624
  var unavailable = () => new FileOperationError("unavailable", 503, true);
22579
22625
  var failures = {
22580
22626
  400: ["invalid_input", "unsupported_context"],
@@ -22598,7 +22644,7 @@ async function boundedBytes(stream, limit) {
22598
22644
  if (done)
22599
22645
  break;
22600
22646
  if (!(value instanceof Uint8Array))
22601
- throw invalid2();
22647
+ throw invalid3();
22602
22648
  size += value.byteLength;
22603
22649
  if (size > limit)
22604
22650
  throw new FileOperationError("request_too_large", 413);
@@ -22780,7 +22826,7 @@ async function send(suffix, init, descriptor, initial, parent) {
22780
22826
  }
22781
22827
  function idPath(id2) {
22782
22828
  if (typeof id2 !== "string" || !FILE_ID_PATTERN.test(id2))
22783
- throw invalid2();
22829
+ throw invalid3();
22784
22830
  return `/${id2}`;
22785
22831
  }
22786
22832
  async function multipartCreate(input, metadata, exchange, release = () => {
@@ -22844,12 +22890,12 @@ async function multipartCreate(input, metadata, exchange, release = () => {
22844
22890
  offset = 0;
22845
22891
  const value2 = await next();
22846
22892
  if (value2.done)
22847
- throw invalid2();
22893
+ throw invalid3();
22848
22894
  if (!(value2.value instanceof Uint8Array))
22849
- throw invalid2();
22895
+ throw invalid3();
22850
22896
  chunk = value2.value;
22851
22897
  if (chunk.byteLength > metadata.size - sent - filled)
22852
- throw invalid2();
22898
+ throw invalid3();
22853
22899
  }
22854
22900
  const take = Math.min(length - filled, chunk.byteLength - offset);
22855
22901
  part.set(chunk.subarray(offset, offset + take), filled);
@@ -22862,7 +22908,7 @@ async function multipartCreate(input, metadata, exchange, release = () => {
22862
22908
  }
22863
22909
  }
22864
22910
  if (part.byteLength !== length)
22865
- throw invalid2();
22911
+ throw invalid3();
22866
22912
  if (reader && sent + length === metadata.size) {
22867
22913
  lastProgress = Date.now();
22868
22914
  for (;; ) {
@@ -22870,7 +22916,7 @@ async function multipartCreate(input, metadata, exchange, release = () => {
22870
22916
  if (value2.done)
22871
22917
  break;
22872
22918
  if (!(value2.value instanceof Uint8Array) || value2.value.byteLength)
22873
- throw invalid2();
22919
+ throw invalid3();
22874
22920
  }
22875
22921
  }
22876
22922
  const value = await request((signal) => exchange(`${route}/part`, {
@@ -22890,7 +22936,7 @@ async function multipartCreate(input, metadata, exchange, release = () => {
22890
22936
  for (const name of Object.keys(upload.file.enrichments)) {
22891
22937
  const bytes = await request(() => upload.enrichment(name));
22892
22938
  if (bytes.byteLength !== upload.file.enrichments[name].size || bytes.byteLength > MAX_BYTES)
22893
- throw invalid2();
22939
+ throw invalid3();
22894
22940
  await request((signal) => exchange(`${route}/enrichments/${encodeURIComponent(name)}`, {
22895
22941
  method: "POST",
22896
22942
  headers: { "content-type": "application/octet-stream", "x-oddington-transfer": ticket },
@@ -22944,7 +22990,7 @@ function contentPath(id2, name) {
22944
22990
  if (name === undefined)
22945
22991
  return `${path}/content`;
22946
22992
  if (!safeEnrichmentName(name))
22947
- throw invalid2();
22993
+ throw invalid3();
22948
22994
  return `${path}/enrichments/${encodeURIComponent(name)}/content`;
22949
22995
  }
22950
22996
  async function read(id2, names) {
@@ -22955,16 +23001,16 @@ async function read(id2, names) {
22955
23001
  return operation((context2, signal) => send(path, { method: "GET" }, false, context2, signal), context);
22956
23002
  }
22957
23003
  if (!Array.isArray(names))
22958
- throw invalid2();
23004
+ throw invalid3();
22959
23005
  const distinct = [];
22960
23006
  const seen = new Set;
22961
23007
  for (const name of names) {
22962
23008
  if (typeof name !== "string" || !safeEnrichmentName(name))
22963
- throw invalid2();
23009
+ throw invalid3();
22964
23010
  if (seen.has(name))
22965
23011
  continue;
22966
23012
  if (seen.size === 16)
22967
- throw invalid2();
23013
+ throw invalid3();
22968
23014
  seen.add(name);
22969
23015
  distinct.push(name);
22970
23016
  }
@@ -22998,15 +23044,15 @@ var files = {
22998
23044
  async create(input, options) {
22999
23045
  const context = await resolveFilesContext();
23000
23046
  if (!input || typeof input !== "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "size", "path", "name", "storage", "csv"].includes(key)) || options !== undefined && (!options || typeof options !== "object" || Array.isArray(options) || Object.keys(options).some((key) => key !== "requestKey")))
23001
- throw invalid2();
23047
+ throw invalid3();
23002
23048
  const blob = input.file instanceof Blob;
23003
23049
  const array2 = input.file instanceof Uint8Array;
23004
23050
  const stream = input.file instanceof ReadableStream;
23005
23051
  if (!blob && !array2 && !stream)
23006
- throw invalid2();
23052
+ throw invalid3();
23007
23053
  const intrinsic = blob ? input.file.size : array2 ? input.file.byteLength : undefined;
23008
23054
  if (intrinsic !== undefined && input.size !== undefined && input.size !== intrinsic)
23009
- throw invalid2();
23055
+ throw invalid3();
23010
23056
  let name = input.name;
23011
23057
  if (name === undefined && blob && "name" in input.file && typeof input.file.name === "string") {
23012
23058
  name = typeof globalThis.File !== "undefined" && input.file instanceof globalThis.File ? input.file.name : input.file.name.split(/[\\/]/).at(-1);
@@ -23023,7 +23069,7 @@ var files = {
23023
23069
  throw new FileOperationError("unsupported_context", 400);
23024
23070
  const header = encodeURIComponent(JSON.stringify(metadata));
23025
23071
  if (new TextEncoder().encode(header).byteLength > METADATA_BYTES)
23026
- throw invalid2();
23072
+ throw invalid3();
23027
23073
  if (active >= MAX_ACTIVE)
23028
23074
  throw new FileOperationError("capacity", 429, true);
23029
23075
  active++;
@@ -23057,7 +23103,7 @@ var files = {
23057
23103
  try {
23058
23104
  const bytes = array2 ? input.file.slice() : await boundedBytes(blob ? input.file.stream() : input.file, metadata.size);
23059
23105
  if (bytes.byteLength !== metadata.size)
23060
- throw invalid2();
23106
+ throw invalid3();
23061
23107
  if (signal.aborted)
23062
23108
  throw unavailable();
23063
23109
  return await send("", {
@@ -23075,7 +23121,7 @@ var files = {
23075
23121
  async enrich(input) {
23076
23122
  const context = await resolveFilesContext();
23077
23123
  if (!input || typeof input !== "object" || Array.isArray(input) || Object.keys(input).some((key) => !["file", "name", "content", "mediaType", "replace"].includes(key)) || typeof input.content !== "string" && !(input.content instanceof Uint8Array))
23078
- throw invalid2();
23124
+ throw invalid3();
23079
23125
  const path = `${idPath(input.file)}/enrichments`;
23080
23126
  if (typeof input.content === "string" ? input.content.length > MAX_BYTES : input.content.byteLength > MAX_BYTES)
23081
23127
  throw new FileOperationError("request_too_large", 413);
@@ -23097,7 +23143,7 @@ var files = {
23097
23143
  }, MAX_BYTES);
23098
23144
  const header = encodeURIComponent(JSON.stringify(metadata));
23099
23145
  if (new TextEncoder().encode(header).byteLength > METADATA_BYTES)
23100
- throw invalid2();
23146
+ throw invalid3();
23101
23147
  const result2 = await send(path, { method: "POST", headers: {
23102
23148
  "content-type": "application/octet-stream",
23103
23149
  "x-oddington-enrichment": header
@@ -13,7 +13,7 @@ export { AirtableOperationError } from '../../../shared/airtable-contract.js';
13
13
  export type { AirtableField, AirtableTable, AirtableRecord, AirtableListInput, AirtableGetInput, AirtableCreateInput, AirtableUpdateInput, AirtableDeleteInput, AirtableReceipt, AirtableWriteResult, AirtableClient, Connections } from '../../../shared/airtable-contract.js';
14
14
  export declare const connections: import('../../../shared/airtable-contract.js').Connections;
15
15
  export { DataOperationError } from '../../../shared/data-contract.js';
16
- export type { DataRepository, DataErrorCode, PublicValueDefinition, PublicField, CollectionSummary, CollectionSchema, QueryScalar, SelectionOptions, RecordSelection, RecordsQuery, DataValue, SelectedRecord, SelectionMetadata, RecordsResult, RecordsSearchOptions, RecordsSearchResult, RecordIdentity, RecordCreation, RecordUpdateSet, DataPublication, DataChangeSet, DataEffect } from '../../../shared/data-contract.js';
16
+ export type { DataRepository, DataErrorCode, PublicValueDefinition, PublicField, CollectionSummary, CollectionSchema, QueryScalar, SelectionOptions, RecordSelection, RecordsQuery, DataValue, SelectedRecord, SelectionMetadata, RecordsResult, RecordsSearchOptions, RecordsSearchResult, HistoryListOptions, HistoryEntry, RecordIdentity, RecordCreation, RecordUpdateSet, DataPublication, DataChangeSet, DataEffect } from '../../../shared/data-contract.js';
17
17
  export declare const data: {
18
18
  repository(name: string): import('../../../shared/data-contract.js').DataRepository;
19
19
  };
@@ -134,6 +134,28 @@ export type DataPublication = {
134
134
  updated: RecordIdentity[];
135
135
  deleted: RecordIdentity[];
136
136
  };
137
+ export type HistoryListOptions = {
138
+ limit?: number;
139
+ before?: string;
140
+ };
141
+ export type HistoryEntry = {
142
+ version: string;
143
+ publishedAt: string;
144
+ author: {
145
+ name: string;
146
+ email: string;
147
+ };
148
+ authoredAt: string;
149
+ committer: {
150
+ name: string;
151
+ email: string;
152
+ };
153
+ committedAt: string;
154
+ message: string;
155
+ created: string[];
156
+ updated: string[];
157
+ deleted: string[];
158
+ };
137
159
  export interface DataChangeSet {
138
160
  create(record: RecordCreation): void;
139
161
  update(record: RecordIdentity, set: RecordUpdateSet): void;
@@ -150,6 +172,10 @@ export interface DataRepository {
150
172
  select(query: RecordsQuery): Promise<RecordsResult>;
151
173
  search(query: string, options?: RecordsSearchOptions): Promise<RecordsSearchResult>;
152
174
  };
175
+ history: {
176
+ list(options?: HistoryListOptions): Promise<HistoryEntry[]>;
177
+ at(instant: string): Promise<HistoryEntry | null>;
178
+ };
153
179
  changes(): DataChangeSet;
154
180
  }
155
181
  export type DataErrorCode = 'context_unavailable' | 'unauthenticated' | 'access_denied' | 'invalid_query' | 'request_too_large' | 'capacity' | 'unavailable' | 'invalid_change' | 'conflict' | 'publication_pending';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oddington/sdk",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Oddington routine and response-handler SDK",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",