@gscdump/lakehouse 1.0.2 → 1.0.3

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
@@ -15,6 +15,9 @@ Node.js 22 or newer is required.
15
15
 
16
16
  - `@gscdump/lakehouse` — connect to a catalog, define datasets, derive table
17
17
  specifications, resolve data files, and use bigint-safe serialization.
18
+ - `@gscdump/lakehouse/bigint`: bigint-safe JSON helpers without catalog or
19
+ Node dependencies.
20
+ - `@gscdump/lakehouse/schema`: lightweight shared schema constants.
18
21
  - `@gscdump/lakehouse/maintenance` — stable commit classification and orphan
19
22
  cleanup workflows.
20
23
  - `@gscdump/lakehouse/provisioning` — adopt, allocate, or provision R2 Data
@@ -25,6 +28,7 @@ Node.js 22 or newer is required.
25
28
 
26
29
  ```ts
27
30
  import { connectIcebergCatalog, listIcebergTables } from '@gscdump/lakehouse'
31
+ import { encodeJsonBigintSafe } from '@gscdump/lakehouse/bigint'
28
32
  import { isCommitRateLimited } from '@gscdump/lakehouse/maintenance'
29
33
 
30
34
  const connection = await connectIcebergCatalog(config)
@@ -1,16 +1,5 @@
1
+ import { stringifyBigintSafe } from "../bigint.mjs";
1
2
  import { cachingResolver, icebergAppend, icebergDropTable, icebergManifests, restCatalogConnect, restCatalogCreateNamespace, restCatalogListTables, restCatalogLoadTable, s3SignedResolver } from "./libs/icebird.mjs";
2
- function bigintJsonReplacer(_key, value) {
3
- return typeof value === "bigint" ? value.toString() : value;
4
- }
5
- function stringifyBigintSafe(value, space) {
6
- return JSON.stringify(value, bigintJsonReplacer, space);
7
- }
8
- function encodeJsonBigintSafe(value) {
9
- return new TextEncoder().encode(stringifyBigintSafe(value));
10
- }
11
- function coerceBigIntToNumber(value) {
12
- return typeof value === "bigint" ? Number(value) : value;
13
- }
14
3
  function reportCatalogCacheError(cache, operation, key, error) {
15
4
  try {
16
5
  if (cache.onError) cache.onError(operation, key, error);
@@ -410,4 +399,4 @@ async function resolveIcebergDataFiles(conn, opts) {
410
399
  }
411
400
  return out;
412
401
  }
413
- export { ICEBERG_TYPE_MAP, bigintJsonReplacer, buildManifestPartitionFilter, cacheGet, cachePut, catalogCacheScope, coerceBigIntToNumber, connectIcebergCatalog, dropIcebergTables, encodeJsonBigintSafe, ensureIcebergNamespace, icebergAppendRetrying, invalidateSnapshotRef, isCommitRateLimited, listIcebergTables, resolveIcebergDataFiles, stringifyBigintSafe };
402
+ export { ICEBERG_TYPE_MAP, buildManifestPartitionFilter, cacheGet, cachePut, catalogCacheScope, connectIcebergCatalog, dropIcebergTables, ensureIcebergNamespace, icebergAppendRetrying, invalidateSnapshotRef, isCommitRateLimited, listIcebergTables, resolveIcebergDataFiles };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * BigInt at JSON boundaries — the single place this policy lives.
3
+ *
4
+ * int64 reaches serialization from two origins:
5
+ * 1. DuckDB `SUM`/`COUNT` aggregates — already coerced to `number` at the
6
+ * source-factory boundary (`@gscdump/engine` `coerceRows`), so rows are
7
+ * BigInt-free by the time they cross the query boundary.
8
+ * 2. icebird / REST-catalog metadata (`current-snapshot-id`, `sequence-number`,
9
+ * `snapshot-id`) and other identity ids — these never pass through a source,
10
+ * so they arrive at envelope / cache / log serializers still as BigInt.
11
+ *
12
+ * A plain `JSON.stringify` throws `Do not know how to serialize a BigInt`, which
13
+ * is how a stray identity int64 turns into a request 500. Any boundary that can
14
+ * see origin (2) must serialize through here.
15
+ *
16
+ * TWO policies, because the correct target type depends on what the value is:
17
+ *
18
+ * - Identity / precision values (snapshot ids, large row ids) can exceed 2^53
19
+ * and must round-trip losslessly → serialize as a decimal STRING. Use
20
+ * {@link stringifyBigintSafe} / {@link bigintJsonReplacer} / {@link encodeJsonBigintSafe}
21
+ * for storage / transport / log serialization. Where values are already
22
+ * number-coerced (origin 1), the replacer is a no-op backstop.
23
+ *
24
+ * - Analytics aggregates that you want as real numbers downstream → coerce with
25
+ * {@link coerceBigIntToNumber}. Lossy above 2^53 by design; click / impression
26
+ * columns never reach that range. This is the scalar behind engine `coerceRows`.
27
+ */
28
+ /** `JSON.stringify` replacer: BigInt → decimal string (lossless). Pass-through otherwise. */
29
+ declare function bigintJsonReplacer(_key: string, value: unknown): unknown;
30
+ /** `JSON.stringify` that never throws on BigInt; identity ids stay lossless as strings. */
31
+ declare function stringifyBigintSafe(value: unknown, space?: string | number): string;
32
+ declare function encodeJsonBigintSafe(value: unknown): Uint8Array;
33
+ /**
34
+ * BigInt → number for analytics aggregates (< 2^53). Lossy above; acceptable for
35
+ * click / impression sums. Non-BigInt values pass through untouched.
36
+ */
37
+ declare function coerceBigIntToNumber<T>(value: T): T | number;
38
+ export { bigintJsonReplacer, coerceBigIntToNumber, encodeJsonBigintSafe, stringifyBigintSafe };
@@ -0,0 +1,15 @@
1
+ function bigintJsonReplacer(_key, value) {
2
+ return typeof value === "bigint" ? value.toString() : value;
3
+ }
4
+ function stringifyBigintSafe(value, space) {
5
+ return JSON.stringify(value, bigintJsonReplacer, space);
6
+ }
7
+ let jsonEncoder;
8
+ function encodeJsonBigintSafe(value) {
9
+ jsonEncoder ??= new TextEncoder();
10
+ return jsonEncoder.encode(stringifyBigintSafe(value));
11
+ }
12
+ function coerceBigIntToNumber(value) {
13
+ return typeof value === "bigint" ? Number(value) : value;
14
+ }
15
+ export { bigintJsonReplacer, coerceBigIntToNumber, encodeJsonBigintSafe, stringifyBigintSafe };
package/dist/index.d.mts CHANGED
@@ -1,43 +1,6 @@
1
+ import { bigintJsonReplacer, coerceBigIntToNumber, encodeJsonBigintSafe, stringifyBigintSafe } from "./bigint.mjs";
1
2
  import { CatalogCache, CommitRetryOptions, ConnectIcebergOptions, ICEBERG_TYPE_MAP, IcebergCatalogConfig, IcebergConnection, IcebergFieldSummary, IcebergListedDataFile, IcebergPartitionSpec, IcebergPartitionSpecField, IcebergPrimitiveType, IcebergSchema, IcebergSchemaField, IcebergSortOrder, IcebergSortOrderField, IcebergTableOpResult, ManifestPartitionFilter, PartitionValueMatch, QueryProfiler, ResolveIcebergDataFilesOptions, buildManifestPartitionFilter, cacheGet, cachePut, catalogCacheScope, connectIcebergCatalog, dropIcebergTables, ensureIcebergNamespace, invalidateSnapshotRef, listIcebergTables, resolveIcebergDataFiles } from "./_chunks/catalog.mjs";
2
3
  import { DEFAULT_PARTITION_KEY_ENCODING, IcebergColumn, IcebergColumnType, IcebergPartitionField, IcebergPartitionTransform, IcebergS3Config, IcebergTableSpec, PartitionKeyEncoding } from "./_chunks/schema.mjs";
3
- /**
4
- * BigInt at JSON boundaries — the single place this policy lives.
5
- *
6
- * int64 reaches serialization from two origins:
7
- * 1. DuckDB `SUM`/`COUNT` aggregates — already coerced to `number` at the
8
- * source-factory boundary (`@gscdump/engine` `coerceRows`), so rows are
9
- * BigInt-free by the time they cross the query boundary.
10
- * 2. icebird / REST-catalog metadata (`current-snapshot-id`, `sequence-number`,
11
- * `snapshot-id`) and other identity ids — these never pass through a source,
12
- * so they arrive at envelope / cache / log serializers still as BigInt.
13
- *
14
- * A plain `JSON.stringify` throws `Do not know how to serialize a BigInt`, which
15
- * is how a stray identity int64 turns into a request 500. Any boundary that can
16
- * see origin (2) must serialize through here.
17
- *
18
- * TWO policies, because the correct target type depends on what the value is:
19
- *
20
- * - Identity / precision values (snapshot ids, large row ids) can exceed 2^53
21
- * and must round-trip losslessly → serialize as a decimal STRING. Use
22
- * {@link stringifyBigintSafe} / {@link bigintJsonReplacer} / {@link encodeJsonBigintSafe}
23
- * for storage / transport / log serialization. Where values are already
24
- * number-coerced (origin 1), the replacer is a no-op backstop.
25
- *
26
- * - Analytics aggregates that you want as real numbers downstream → coerce with
27
- * {@link coerceBigIntToNumber}. Lossy above 2^53 by design; click / impression
28
- * columns never reach that range. This is the scalar behind engine `coerceRows`.
29
- */
30
- /** `JSON.stringify` replacer: BigInt → decimal string (lossless). Pass-through otherwise. */
31
- declare function bigintJsonReplacer(_key: string, value: unknown): unknown;
32
- /** `JSON.stringify` that never throws on BigInt; identity ids stay lossless as strings. */
33
- declare function stringifyBigintSafe(value: unknown, space?: string | number): string;
34
- /** UTF-8 JSON bytes, BigInt-safe — the payload shape for `DataSource.write`. */
35
- declare function encodeJsonBigintSafe(value: unknown): Uint8Array;
36
- /**
37
- * BigInt → number for analytics aggregates (< 2^53). Lossy above; acceptable for
38
- * click / impression sums. Non-BigInt values pass through untouched.
39
- */
40
- declare function coerceBigIntToNumber<T>(value: T): T | number;
41
4
  /**
42
5
  * Closed identity shapes (ADR-0021 amendments 2 + 4). `'site-int'` is the
43
6
  * team-scoped numeric Catalog Site Id (nuxtseo ADR-0091) stored under the
package/dist/index.mjs CHANGED
@@ -1,5 +1,7 @@
1
- import { ICEBERG_TYPE_MAP, bigintJsonReplacer, buildManifestPartitionFilter, cacheGet, cachePut, catalogCacheScope, coerceBigIntToNumber, connectIcebergCatalog, dropIcebergTables, encodeJsonBigintSafe, ensureIcebergNamespace, icebergAppendRetrying, invalidateSnapshotRef, listIcebergTables, resolveIcebergDataFiles, stringifyBigintSafe } from "./_chunks/catalog.mjs";
1
+ import { bigintJsonReplacer, coerceBigIntToNumber, encodeJsonBigintSafe, stringifyBigintSafe } from "./bigint.mjs";
2
2
  import { icebergCreateTable } from "./_chunks/libs/icebird.mjs";
3
+ import { ICEBERG_TYPE_MAP, buildManifestPartitionFilter, cacheGet, cachePut, catalogCacheScope, connectIcebergCatalog, dropIcebergTables, ensureIcebergNamespace, icebergAppendRetrying, invalidateSnapshotRef, listIcebergTables, resolveIcebergDataFiles } from "./_chunks/catalog.mjs";
4
+ import { DEFAULT_PARTITION_KEY_ENCODING } from "./schema.mjs";
3
5
  const INT32_MIN = -2147483648;
4
6
  const INT32_MAX = 2147483647;
5
7
  const DAY_MILLIS = 864e5;
@@ -325,5 +327,4 @@ function defineIcebergDataset(def) {
325
327
  resolveDataFiles
326
328
  };
327
329
  }
328
- const DEFAULT_PARTITION_KEY_ENCODING = "int";
329
330
  export { DEFAULT_PARTITION_KEY_ENCODING, ICEBERG_TYPE_MAP, bigintJsonReplacer, buildManifestPartitionFilter, cacheGet, cachePut, catalogCacheScope, coerceBigIntToNumber, connectIcebergCatalog, defineIcebergDataset, deriveTableSpec, dropIcebergTables, encodeJsonBigintSafe, ensureIcebergNamespace, invalidateSnapshotRef, listIcebergTables, resolveIcebergDataFiles, stringifyBigintSafe, toIcebergDayCount };
@@ -1,5 +1,5 @@
1
- import { isCommitRateLimited } from "./_chunks/catalog.mjs";
2
1
  import { icebergManifests, restCatalogListTables, restCatalogLoadTable } from "./_chunks/libs/icebird.mjs";
2
+ import { isCommitRateLimited } from "./_chunks/catalog.mjs";
3
3
  const DEFAULT_GRACE_HOURS = 48;
4
4
  const DEFAULT_MAX_DELETES = 500;
5
5
  const DEFAULT_IO_CONCURRENCY = 4;
@@ -0,0 +1,2 @@
1
+ import { DEFAULT_PARTITION_KEY_ENCODING, IcebergColumn, IcebergColumnType, IcebergPartitionField, IcebergPartitionTransform, IcebergS3Config, IcebergTableSpec, PartitionKeyEncoding } from "./_chunks/schema.mjs";
2
+ export { DEFAULT_PARTITION_KEY_ENCODING, IcebergColumn, IcebergColumnType, IcebergPartitionField, IcebergPartitionTransform, IcebergS3Config, IcebergTableSpec, PartitionKeyEncoding };
@@ -0,0 +1,2 @@
1
+ const DEFAULT_PARTITION_KEY_ENCODING = "int";
2
+ export { DEFAULT_PARTITION_KEY_ENCODING };
@@ -1,3 +1,3 @@
1
- import { icebergAppendRetrying } from "./_chunks/catalog.mjs";
2
1
  import { icebergAppend, icebergCreateTable, icebergDropTable, icebergManifests, restCatalogConnect, restCatalogCreateNamespace, restCatalogListTables, restCatalogLoadTable, s3SignedResolver } from "./_chunks/libs/icebird.mjs";
2
+ import { icebergAppendRetrying } from "./_chunks/catalog.mjs";
3
3
  export { icebergAppend, icebergAppendRetrying, icebergCreateTable, icebergDropTable, icebergManifests, restCatalogConnect, restCatalogCreateNamespace, restCatalogListTables, restCatalogLoadTable, s3SignedResolver };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gscdump/lakehouse",
3
3
  "type": "module",
4
- "version": "1.0.2",
4
+ "version": "1.0.3",
5
5
  "description": "Dataset-agnostic Iceberg lakehouse layer + dataset registry for R2 Data Catalog producers (ADR-0021).",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",
@@ -26,6 +26,16 @@
26
26
  "import": "./dist/index.mjs",
27
27
  "default": "./dist/index.mjs"
28
28
  },
29
+ "./bigint": {
30
+ "types": "./dist/bigint.d.mts",
31
+ "import": "./dist/bigint.mjs",
32
+ "default": "./dist/bigint.mjs"
33
+ },
34
+ "./schema": {
35
+ "types": "./dist/schema.d.mts",
36
+ "import": "./dist/schema.mjs",
37
+ "default": "./dist/schema.mjs"
38
+ },
29
39
  "./maintenance": {
30
40
  "types": "./dist/maintenance.d.mts",
31
41
  "import": "./dist/maintenance.mjs",