@syncular/core 0.0.6-205 → 0.0.6-210

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.
@@ -0,0 +1,4 @@
1
+ export declare function bytesToReadableStream(bytes: Uint8Array): ReadableStream<Uint8Array>;
2
+ export declare function concatByteChunks(chunks: readonly Uint8Array[]): Uint8Array;
3
+ export declare function readAllBytesFromStream(stream: ReadableStream<Uint8Array>): Promise<Uint8Array>;
4
+ //# sourceMappingURL=bytes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytes.d.ts","sourceRoot":"","sources":["../../src/utils/bytes.ts"],"names":[],"mappings":"AAEA,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,UAAU,GAChB,cAAc,CAAC,UAAU,CAAC,CAO5B;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,UAAU,CAoB1E;AAED,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,GACjC,OAAO,CAAC,UAAU,CAAC,CAqCrB"}
@@ -0,0 +1,66 @@
1
+ import { getBunRuntime } from './internal-runtime.js';
2
+ export function bytesToReadableStream(bytes) {
3
+ return new ReadableStream({
4
+ start(controller) {
5
+ controller.enqueue(bytes);
6
+ controller.close();
7
+ },
8
+ });
9
+ }
10
+ export function concatByteChunks(chunks) {
11
+ if (chunks.length === 0) {
12
+ return new Uint8Array();
13
+ }
14
+ if (chunks.length === 1) {
15
+ return chunks[0] ?? new Uint8Array();
16
+ }
17
+ let total = 0;
18
+ for (const chunk of chunks) {
19
+ total += chunk.length;
20
+ }
21
+ const merged = new Uint8Array(total);
22
+ let offset = 0;
23
+ for (const chunk of chunks) {
24
+ merged.set(chunk, offset);
25
+ offset += chunk.length;
26
+ }
27
+ return merged;
28
+ }
29
+ export async function readAllBytesFromStream(stream) {
30
+ const bun = getBunRuntime();
31
+ if (bun?.readableStreamToBytes) {
32
+ const bytes = await bun.readableStreamToBytes(stream);
33
+ return bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
34
+ }
35
+ const reader = stream.getReader();
36
+ const chunks = [];
37
+ let total = 0;
38
+ try {
39
+ while (true) {
40
+ const { done, value } = await reader.read();
41
+ if (done)
42
+ break;
43
+ if (!value)
44
+ continue;
45
+ chunks.push(value);
46
+ total += value.length;
47
+ }
48
+ }
49
+ finally {
50
+ reader.releaseLock();
51
+ }
52
+ if (chunks.length === 0) {
53
+ return new Uint8Array();
54
+ }
55
+ if (chunks.length === 1) {
56
+ return chunks[0] ?? new Uint8Array();
57
+ }
58
+ const merged = new Uint8Array(total);
59
+ let offset = 0;
60
+ for (const chunk of chunks) {
61
+ merged.set(chunk, offset);
62
+ offset += chunk.length;
63
+ }
64
+ return merged;
65
+ }
66
+ //# sourceMappingURL=bytes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytes.js","sourceRoot":"","sources":["../../src/utils/bytes.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Gzip-compress a byte array using CompressionStream when available,
3
- * with node:zlib fallback for Node/Bun runtimes.
2
+ * Gzip-compress a byte array using the fastest native implementation available
3
+ * in the current runtime.
4
4
  */
5
5
  export declare function gzipBytes(payload: Uint8Array): Promise<Uint8Array>;
6
6
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"compression.d.ts","sourceRoot":"","sources":["../../src/utils/compression.ts"],"names":[],"mappings":"AAwCA;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAqBxE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;IACpE,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC,CAgBD"}
1
+ {"version":3,"file":"compression.d.ts","sourceRoot":"","sources":["../../src/utils/compression.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CA6BxE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;IACpE,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC,CAoBD"}
@@ -1,67 +1,50 @@
1
- function bytesToReadableStream(bytes) {
2
- return new ReadableStream({
3
- start(controller) {
4
- controller.enqueue(bytes);
5
- controller.close();
6
- },
7
- });
8
- }
9
- async function streamToBytes(stream) {
10
- const reader = stream.getReader();
11
- const chunks = [];
12
- let total = 0;
13
- try {
14
- while (true) {
15
- const { done, value } = await reader.read();
16
- if (done)
17
- break;
18
- if (!value)
19
- continue;
20
- chunks.push(value);
21
- total += value.length;
22
- }
23
- }
24
- finally {
25
- reader.releaseLock();
1
+ import { bytesToReadableStream, readAllBytesFromStream } from './bytes.js';
2
+ import { getBunRuntime, usesNodeRuntimeModules } from './internal-runtime.js';
3
+ let nodeZlibModulePromise = null;
4
+ async function getNodeZlibModule() {
5
+ if (!usesNodeRuntimeModules()) {
6
+ return null;
26
7
  }
27
- if (chunks.length === 0)
28
- return new Uint8Array();
29
- if (chunks.length === 1)
30
- return chunks[0] ?? new Uint8Array();
31
- const merged = new Uint8Array(total);
32
- let offset = 0;
33
- for (const chunk of chunks) {
34
- merged.set(chunk, offset);
35
- offset += chunk.length;
8
+ if (!nodeZlibModulePromise) {
9
+ nodeZlibModulePromise = import('node:zlib').catch(() => null);
36
10
  }
37
- return merged;
11
+ return nodeZlibModulePromise;
38
12
  }
39
13
  /**
40
- * Gzip-compress a byte array using CompressionStream when available,
41
- * with node:zlib fallback for Node/Bun runtimes.
14
+ * Gzip-compress a byte array using the fastest native implementation available
15
+ * in the current runtime.
42
16
  */
43
17
  export async function gzipBytes(payload) {
18
+ const bun = getBunRuntime();
19
+ if (bun?.gzipSync) {
20
+ return bun.gzipSync(payload);
21
+ }
22
+ const nodeZlib = await getNodeZlibModule();
23
+ if (nodeZlib?.gzip) {
24
+ return await new Promise((resolve, reject) => {
25
+ nodeZlib.gzip(payload, (error, compressed) => {
26
+ if (error) {
27
+ reject(error);
28
+ return;
29
+ }
30
+ resolve(new Uint8Array(compressed));
31
+ });
32
+ });
33
+ }
44
34
  if (typeof CompressionStream !== 'undefined') {
45
35
  const stream = bytesToReadableStream(payload).pipeThrough(new CompressionStream('gzip'));
46
- return streamToBytes(stream);
36
+ return readAllBytesFromStream(stream);
47
37
  }
48
- const nodeZlib = await import('node:zlib');
49
- return await new Promise((resolve, reject) => {
50
- nodeZlib.gzip(payload, (error, compressed) => {
51
- if (error) {
52
- reject(error);
53
- return;
54
- }
55
- resolve(new Uint8Array(compressed));
56
- });
57
- });
38
+ throw new Error('Failed to gzip bytes, no compression implementation available');
58
39
  }
59
40
  /**
60
41
  * Gzip-compress bytes and return a stream. When streaming compression is not
61
42
  * available, falls back to eager compression and includes byteLength metadata.
62
43
  */
63
44
  export async function gzipBytesToStream(payload) {
64
- if (typeof CompressionStream !== 'undefined') {
45
+ const bun = getBunRuntime();
46
+ const nodeZlib = await getNodeZlibModule();
47
+ if (!bun?.gzipSync && !nodeZlib && typeof CompressionStream !== 'undefined') {
65
48
  const source = bytesToReadableStream(payload);
66
49
  const gzipStream = new CompressionStream('gzip');
67
50
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"compression.js","sourceRoot":"","sources":["../../src/utils/compression.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compression.js","sourceRoot":"","sources":["../../src/utils/compression.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE3E,IAAI,qBAAqB,GACvB,IAAI,CAAC;AAEP,KAAK,UAAU,iBAAiB,GAA+C;IAC7E,IAAI,CAAC,sBAAsB,EAAE,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC3B,qBAAqB,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,qBAAqB,CAAC;AAAA,CAC9B;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAmB,EAAuB;IACxE,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,IAAI,GAAG,EAAE,QAAQ,EAAE,CAAC;QAClB,OAAO,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAC3C,IAAI,QAAQ,EAAE,IAAI,EAAE,CAAC;QACnB,OAAO,MAAM,IAAI,OAAO,CAAa,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;YACxD,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC;gBAC5C,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,CAAC,KAAK,CAAC,CAAC;oBACd,OAAO;gBACT,CAAC;gBACD,OAAO,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;YAAA,CACrC,CAAC,CAAC;QAAA,CACJ,CAAC,CAAC;IACL,CAAC;IAED,IAAI,OAAO,iBAAiB,KAAK,WAAW,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC,WAAW,CACvD,IAAI,iBAAiB,CAAC,MAAM,CAA4C,CACzE,CAAC;QACF,OAAO,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,IAAI,KAAK,CACb,+DAA+D,CAChE,CAAC;AAAA,CACH;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAmB,EAGxD;IACD,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAE3C,IAAI,CAAC,GAAG,EAAE,QAAQ,IAAI,CAAC,QAAQ,IAAI,OAAO,iBAAiB,KAAK,WAAW,EAAE,CAAC;QAC5E,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,UAAU,GAAG,IAAI,iBAAiB,CAAC,MAAM,CAG9C,CAAC;QACF,OAAO;YACL,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC;SACvC,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO;QACL,MAAM,EAAE,qBAAqB,CAAC,UAAU,CAAC;QACzC,UAAU,EAAE,UAAU,CAAC,MAAM;KAC9B,CAAC;AAAA,CACH"}
@@ -1,7 +1,13 @@
1
+ export interface IncrementalSha256 {
2
+ update(chunk: Uint8Array): void;
3
+ digestHex(): Promise<string>;
4
+ }
5
+ export declare function createIncrementalSha256(): Promise<IncrementalSha256>;
1
6
  /**
2
7
  * Cross-runtime SHA-256 digest helper.
3
8
  *
4
- * Uses Web Crypto when available, with Node crypto fallback.
9
+ * Uses native Bun/Node implementations on server runtimes, with Web Crypto
10
+ * fallback for browser and worker environments.
5
11
  */
6
12
  export declare function sha256Hex(input: string | Uint8Array): Promise<string>;
7
13
  //# sourceMappingURL=crypto.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAmB3E"}
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"AAyCA,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9B;AAED,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAqC1E;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA0B3E"}
@@ -1,25 +1,88 @@
1
+ import { concatByteChunks } from './bytes.js';
2
+ import { getBunRuntime, usesNodeRuntimeModules } from './internal-runtime.js';
1
3
  const textEncoder = new TextEncoder();
2
4
  function toHex(bytes) {
3
5
  return Array.from(bytes)
4
6
  .map((byte) => byte.toString(16).padStart(2, '0'))
5
7
  .join('');
6
8
  }
9
+ function toDigestBufferSource(payload) {
10
+ if (payload.buffer instanceof ArrayBuffer) {
11
+ return new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength);
12
+ }
13
+ const owned = new Uint8Array(payload.byteLength);
14
+ owned.set(payload);
15
+ return owned;
16
+ }
17
+ let nodeCryptoModulePromise = null;
18
+ async function getNodeCryptoModule() {
19
+ if (!usesNodeRuntimeModules()) {
20
+ return null;
21
+ }
22
+ if (!nodeCryptoModulePromise) {
23
+ nodeCryptoModulePromise = import('node:crypto').catch(() => null);
24
+ }
25
+ return nodeCryptoModulePromise;
26
+ }
27
+ export async function createIncrementalSha256() {
28
+ const bun = getBunRuntime();
29
+ if (bun?.CryptoHasher) {
30
+ const hasher = new bun.CryptoHasher('sha256');
31
+ return {
32
+ update(chunk) {
33
+ hasher.update(chunk);
34
+ },
35
+ async digestHex() {
36
+ return hasher.digest('hex');
37
+ },
38
+ };
39
+ }
40
+ const nodeCrypto = await getNodeCryptoModule();
41
+ if (nodeCrypto?.createHash) {
42
+ const hasher = nodeCrypto.createHash('sha256');
43
+ return {
44
+ update(chunk) {
45
+ hasher.update(chunk);
46
+ },
47
+ async digestHex() {
48
+ return hasher.digest('hex');
49
+ },
50
+ };
51
+ }
52
+ const chunks = [];
53
+ return {
54
+ update(chunk) {
55
+ if (chunk.length === 0)
56
+ return;
57
+ chunks.push(chunk.slice());
58
+ },
59
+ async digestHex() {
60
+ return sha256Hex(concatByteChunks(chunks));
61
+ },
62
+ };
63
+ }
7
64
  /**
8
65
  * Cross-runtime SHA-256 digest helper.
9
66
  *
10
- * Uses Web Crypto when available, with Node crypto fallback.
67
+ * Uses native Bun/Node implementations on server runtimes, with Web Crypto
68
+ * fallback for browser and worker environments.
11
69
  */
12
70
  export async function sha256Hex(input) {
13
71
  const payload = typeof input === 'string' ? textEncoder.encode(input) : input;
14
- if (typeof crypto !== 'undefined' && crypto.subtle) {
15
- const digestBuffer = await crypto.subtle.digest('SHA-256', payload.slice().buffer);
16
- return toHex(new Uint8Array(digestBuffer));
72
+ const bun = getBunRuntime();
73
+ if (bun?.CryptoHasher) {
74
+ const hasher = new bun.CryptoHasher('sha256');
75
+ hasher.update(payload);
76
+ return hasher.digest('hex');
17
77
  }
18
- try {
19
- const nodeCrypto = await import('node:crypto');
78
+ const nodeCrypto = await getNodeCryptoModule();
79
+ if (nodeCrypto?.createHash) {
20
80
  return nodeCrypto.createHash('sha256').update(payload).digest('hex');
21
81
  }
22
- catch { }
82
+ if (typeof crypto !== 'undefined' && crypto.subtle) {
83
+ const digestBuffer = await crypto.subtle.digest('SHA-256', toDigestBufferSource(payload));
84
+ return toHex(new Uint8Array(digestBuffer));
85
+ }
23
86
  throw new Error('Failed to create SHA-256 hash, no crypto implementation available');
24
87
  }
25
88
  //# sourceMappingURL=crypto.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;AAEtC,SAAS,KAAK,CAAC,KAAiB,EAAU;IACxC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;SACrB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SACjD,IAAI,CAAC,EAAE,CAAC,CAAC;AAAA,CACb;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAA0B,EAAmB;IAC3E,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAE9E,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QACnD,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAC7C,SAAS,EACT,OAAO,CAAC,KAAK,EAAE,CAAC,MAAM,CACvB,CAAC;QACF,OAAO,KAAK,CAAC,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QAC/C,OAAO,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,MAAM,IAAI,KAAK,CACb,mEAAmE,CACpE,CAAC;AAAA,CACH"}
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ export * from './bytes';
1
2
  export * from './compression';
2
3
  export * from './crypto';
3
4
  export * from './id';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,MAAM,CAAC;AACrB,cAAc,UAAU,CAAC;AACzB,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kBAAkB,CAAC;AACjC,cAAc,OAAO,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,MAAM,CAAC;AACrB,cAAc,UAAU,CAAC;AACzB,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kBAAkB,CAAC;AACjC,cAAc,OAAO,CAAC"}
@@ -1,3 +1,4 @@
1
+ export * from './bytes.js';
1
2
  export * from './compression.js';
2
3
  export * from './crypto.js';
3
4
  export * from './id.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,MAAM,CAAC;AACrB,cAAc,UAAU,CAAC;AACzB,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kBAAkB,CAAC;AACjC,cAAc,OAAO,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,MAAM,CAAC;AACrB,cAAc,UAAU,CAAC;AACzB,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kBAAkB,CAAC;AACjC,cAAc,OAAO,CAAC"}
@@ -0,0 +1,13 @@
1
+ interface BunCryptoHasher {
2
+ update(data: string | Uint8Array): void;
3
+ digest(encoding: 'hex'): string;
4
+ }
5
+ interface BunRuntime {
6
+ CryptoHasher?: new (algorithm: string) => BunCryptoHasher;
7
+ gzipSync?: (data: Uint8Array) => Uint8Array;
8
+ readableStreamToBytes?: (stream: ReadableStream<Uint8Array>) => Promise<Uint8Array | ArrayBuffer>;
9
+ }
10
+ export declare function getBunRuntime(): BunRuntime | null;
11
+ export declare function usesNodeRuntimeModules(): boolean;
12
+ export {};
13
+ //# sourceMappingURL=internal-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal-runtime.d.ts","sourceRoot":"","sources":["../../src/utils/internal-runtime.ts"],"names":[],"mappings":"AAAA,UAAU,eAAe;IACvB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IACxC,MAAM,CAAC,QAAQ,EAAE,KAAK,GAAG,MAAM,CAAC;CACjC;AAED,UAAU,UAAU;IAClB,YAAY,CAAC,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,eAAe,CAAC;IAC1D,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,UAAU,CAAC;IAC5C,qBAAqB,CAAC,EAAE,CACtB,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,KAC/B,OAAO,CAAC,UAAU,GAAG,WAAW,CAAC,CAAC;CACxC;AAgBD,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD;AAED,wBAAgB,sBAAsB,IAAI,OAAO,CAMhD"}
@@ -0,0 +1,14 @@
1
+ function getRuntimeGlobals() {
2
+ return globalThis;
3
+ }
4
+ export function getBunRuntime() {
5
+ return getRuntimeGlobals().Bun ?? null;
6
+ }
7
+ export function usesNodeRuntimeModules() {
8
+ const globals = getRuntimeGlobals();
9
+ if (globals.Deno !== undefined) {
10
+ return true;
11
+ }
12
+ return typeof globals.process?.versions?.node === 'string';
13
+ }
14
+ //# sourceMappingURL=internal-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal-runtime.js","sourceRoot":"","sources":["../../src/utils/internal-runtime.ts"],"names":[],"mappings":"AAuBA,SAAS,iBAAiB,GAAmB;IAC3C,OAAO,UAA4B,CAAC;AAAA,CACrC;AAED,MAAM,UAAU,aAAa,GAAsB;IACjD,OAAO,iBAAiB,EAAE,CAAC,GAAG,IAAI,IAAI,CAAC;AAAA,CACxC;AAED,MAAM,UAAU,sBAAsB,GAAY;IAChD,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;IACpC,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,OAAO,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,KAAK,QAAQ,CAAC;AAAA,CAC5D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncular/core",
3
- "version": "0.0.6-205",
3
+ "version": "0.0.6-210",
4
4
  "description": "Core protocol types and shared utilities for the Syncular sync framework",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Benjamin Kniffler",
@@ -0,0 +1,75 @@
1
+ import { getBunRuntime } from './internal-runtime';
2
+
3
+ export function bytesToReadableStream(
4
+ bytes: Uint8Array
5
+ ): ReadableStream<Uint8Array> {
6
+ return new ReadableStream<Uint8Array>({
7
+ start(controller) {
8
+ controller.enqueue(bytes);
9
+ controller.close();
10
+ },
11
+ });
12
+ }
13
+
14
+ export function concatByteChunks(chunks: readonly Uint8Array[]): Uint8Array {
15
+ if (chunks.length === 0) {
16
+ return new Uint8Array();
17
+ }
18
+ if (chunks.length === 1) {
19
+ return chunks[0] ?? new Uint8Array();
20
+ }
21
+
22
+ let total = 0;
23
+ for (const chunk of chunks) {
24
+ total += chunk.length;
25
+ }
26
+
27
+ const merged = new Uint8Array(total);
28
+ let offset = 0;
29
+ for (const chunk of chunks) {
30
+ merged.set(chunk, offset);
31
+ offset += chunk.length;
32
+ }
33
+ return merged;
34
+ }
35
+
36
+ export async function readAllBytesFromStream(
37
+ stream: ReadableStream<Uint8Array>
38
+ ): Promise<Uint8Array> {
39
+ const bun = getBunRuntime();
40
+ if (bun?.readableStreamToBytes) {
41
+ const bytes = await bun.readableStreamToBytes(stream);
42
+ return bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
43
+ }
44
+
45
+ const reader = stream.getReader();
46
+ const chunks: Uint8Array[] = [];
47
+ let total = 0;
48
+
49
+ try {
50
+ while (true) {
51
+ const { done, value } = await reader.read();
52
+ if (done) break;
53
+ if (!value) continue;
54
+ chunks.push(value);
55
+ total += value.length;
56
+ }
57
+ } finally {
58
+ reader.releaseLock();
59
+ }
60
+
61
+ if (chunks.length === 0) {
62
+ return new Uint8Array();
63
+ }
64
+ if (chunks.length === 1) {
65
+ return chunks[0] ?? new Uint8Array();
66
+ }
67
+
68
+ const merged = new Uint8Array(total);
69
+ let offset = 0;
70
+ for (const chunk of chunks) {
71
+ merged.set(chunk, offset);
72
+ offset += chunk.length;
73
+ }
74
+ return merged;
75
+ }
@@ -1,68 +1,52 @@
1
- function bytesToReadableStream(bytes: Uint8Array): ReadableStream<Uint8Array> {
2
- return new ReadableStream<Uint8Array>({
3
- start(controller) {
4
- controller.enqueue(bytes);
5
- controller.close();
6
- },
7
- });
8
- }
1
+ import { bytesToReadableStream, readAllBytesFromStream } from './bytes';
2
+ import { getBunRuntime, usesNodeRuntimeModules } from './internal-runtime';
9
3
 
10
- async function streamToBytes(
11
- stream: ReadableStream<Uint8Array>
12
- ): Promise<Uint8Array> {
13
- const reader = stream.getReader();
14
- const chunks: Uint8Array[] = [];
15
- let total = 0;
4
+ let nodeZlibModulePromise: Promise<typeof import('node:zlib') | null> | null =
5
+ null;
16
6
 
17
- try {
18
- while (true) {
19
- const { done, value } = await reader.read();
20
- if (done) break;
21
- if (!value) continue;
22
- chunks.push(value);
23
- total += value.length;
24
- }
25
- } finally {
26
- reader.releaseLock();
7
+ async function getNodeZlibModule(): Promise<typeof import('node:zlib') | null> {
8
+ if (!usesNodeRuntimeModules()) {
9
+ return null;
27
10
  }
28
-
29
- if (chunks.length === 0) return new Uint8Array();
30
- if (chunks.length === 1) return chunks[0] ?? new Uint8Array();
31
-
32
- const merged = new Uint8Array(total);
33
- let offset = 0;
34
- for (const chunk of chunks) {
35
- merged.set(chunk, offset);
36
- offset += chunk.length;
11
+ if (!nodeZlibModulePromise) {
12
+ nodeZlibModulePromise = import('node:zlib').catch(() => null);
37
13
  }
38
- return merged;
14
+ return nodeZlibModulePromise;
39
15
  }
40
16
 
41
17
  /**
42
- * Gzip-compress a byte array using CompressionStream when available,
43
- * with node:zlib fallback for Node/Bun runtimes.
18
+ * Gzip-compress a byte array using the fastest native implementation available
19
+ * in the current runtime.
44
20
  */
45
21
  export async function gzipBytes(payload: Uint8Array): Promise<Uint8Array> {
22
+ const bun = getBunRuntime();
23
+ if (bun?.gzipSync) {
24
+ return bun.gzipSync(payload);
25
+ }
26
+
27
+ const nodeZlib = await getNodeZlibModule();
28
+ if (nodeZlib?.gzip) {
29
+ return await new Promise<Uint8Array>((resolve, reject) => {
30
+ nodeZlib.gzip(payload, (error, compressed) => {
31
+ if (error) {
32
+ reject(error);
33
+ return;
34
+ }
35
+ resolve(new Uint8Array(compressed));
36
+ });
37
+ });
38
+ }
39
+
46
40
  if (typeof CompressionStream !== 'undefined') {
47
41
  const stream = bytesToReadableStream(payload).pipeThrough(
48
- new CompressionStream('gzip') as unknown as TransformStream<
49
- Uint8Array,
50
- Uint8Array
51
- >
42
+ new CompressionStream('gzip') as TransformStream<Uint8Array, Uint8Array>
52
43
  );
53
- return streamToBytes(stream);
44
+ return readAllBytesFromStream(stream);
54
45
  }
55
46
 
56
- const nodeZlib = await import('node:zlib');
57
- return await new Promise<Uint8Array>((resolve, reject) => {
58
- nodeZlib.gzip(payload, (error, compressed) => {
59
- if (error) {
60
- reject(error);
61
- return;
62
- }
63
- resolve(new Uint8Array(compressed));
64
- });
65
- });
47
+ throw new Error(
48
+ 'Failed to gzip bytes, no compression implementation available'
49
+ );
66
50
  }
67
51
 
68
52
  /**
@@ -73,11 +57,15 @@ export async function gzipBytesToStream(payload: Uint8Array): Promise<{
73
57
  stream: ReadableStream<Uint8Array>;
74
58
  byteLength?: number;
75
59
  }> {
76
- if (typeof CompressionStream !== 'undefined') {
60
+ const bun = getBunRuntime();
61
+ const nodeZlib = await getNodeZlibModule();
62
+
63
+ if (!bun?.gzipSync && !nodeZlib && typeof CompressionStream !== 'undefined') {
77
64
  const source = bytesToReadableStream(payload);
78
- const gzipStream = new CompressionStream(
79
- 'gzip'
80
- ) as unknown as TransformStream<Uint8Array, Uint8Array>;
65
+ const gzipStream = new CompressionStream('gzip') as TransformStream<
66
+ Uint8Array,
67
+ Uint8Array
68
+ >;
81
69
  return {
82
70
  stream: source.pipeThrough(gzipStream),
83
71
  };
@@ -1,3 +1,6 @@
1
+ import { concatByteChunks } from './bytes';
2
+ import { getBunRuntime, usesNodeRuntimeModules } from './internal-runtime';
3
+
1
4
  const textEncoder = new TextEncoder();
2
5
 
3
6
  function toHex(bytes: Uint8Array): string {
@@ -6,27 +9,109 @@ function toHex(bytes: Uint8Array): string {
6
9
  .join('');
7
10
  }
8
11
 
12
+ function toDigestBufferSource(payload: Uint8Array): Uint8Array<ArrayBuffer> {
13
+ if (payload.buffer instanceof ArrayBuffer) {
14
+ return new Uint8Array(
15
+ payload.buffer,
16
+ payload.byteOffset,
17
+ payload.byteLength
18
+ );
19
+ }
20
+
21
+ const owned = new Uint8Array(payload.byteLength);
22
+ owned.set(payload);
23
+ return owned;
24
+ }
25
+
26
+ let nodeCryptoModulePromise: Promise<
27
+ typeof import('node:crypto') | null
28
+ > | null = null;
29
+
30
+ async function getNodeCryptoModule(): Promise<
31
+ typeof import('node:crypto') | null
32
+ > {
33
+ if (!usesNodeRuntimeModules()) {
34
+ return null;
35
+ }
36
+ if (!nodeCryptoModulePromise) {
37
+ nodeCryptoModulePromise = import('node:crypto').catch(() => null);
38
+ }
39
+ return nodeCryptoModulePromise;
40
+ }
41
+
42
+ export interface IncrementalSha256 {
43
+ update(chunk: Uint8Array): void;
44
+ digestHex(): Promise<string>;
45
+ }
46
+
47
+ export async function createIncrementalSha256(): Promise<IncrementalSha256> {
48
+ const bun = getBunRuntime();
49
+ if (bun?.CryptoHasher) {
50
+ const hasher = new bun.CryptoHasher('sha256');
51
+ return {
52
+ update(chunk) {
53
+ hasher.update(chunk);
54
+ },
55
+ async digestHex() {
56
+ return hasher.digest('hex');
57
+ },
58
+ };
59
+ }
60
+
61
+ const nodeCrypto = await getNodeCryptoModule();
62
+ if (nodeCrypto?.createHash) {
63
+ const hasher = nodeCrypto.createHash('sha256');
64
+ return {
65
+ update(chunk) {
66
+ hasher.update(chunk);
67
+ },
68
+ async digestHex() {
69
+ return hasher.digest('hex');
70
+ },
71
+ };
72
+ }
73
+
74
+ const chunks: Uint8Array[] = [];
75
+ return {
76
+ update(chunk) {
77
+ if (chunk.length === 0) return;
78
+ chunks.push(chunk.slice());
79
+ },
80
+ async digestHex() {
81
+ return sha256Hex(concatByteChunks(chunks));
82
+ },
83
+ };
84
+ }
85
+
9
86
  /**
10
87
  * Cross-runtime SHA-256 digest helper.
11
88
  *
12
- * Uses Web Crypto when available, with Node crypto fallback.
89
+ * Uses native Bun/Node implementations on server runtimes, with Web Crypto
90
+ * fallback for browser and worker environments.
13
91
  */
14
92
  export async function sha256Hex(input: string | Uint8Array): Promise<string> {
15
93
  const payload = typeof input === 'string' ? textEncoder.encode(input) : input;
16
94
 
95
+ const bun = getBunRuntime();
96
+ if (bun?.CryptoHasher) {
97
+ const hasher = new bun.CryptoHasher('sha256');
98
+ hasher.update(payload);
99
+ return hasher.digest('hex');
100
+ }
101
+
102
+ const nodeCrypto = await getNodeCryptoModule();
103
+ if (nodeCrypto?.createHash) {
104
+ return nodeCrypto.createHash('sha256').update(payload).digest('hex');
105
+ }
106
+
17
107
  if (typeof crypto !== 'undefined' && crypto.subtle) {
18
108
  const digestBuffer = await crypto.subtle.digest(
19
109
  'SHA-256',
20
- payload.slice().buffer
110
+ toDigestBufferSource(payload)
21
111
  );
22
112
  return toHex(new Uint8Array(digestBuffer));
23
113
  }
24
114
 
25
- try {
26
- const nodeCrypto = await import('node:crypto');
27
- return nodeCrypto.createHash('sha256').update(payload).digest('hex');
28
- } catch {}
29
-
30
115
  throw new Error(
31
116
  'Failed to create SHA-256 hash, no crypto implementation available'
32
117
  );
@@ -1,3 +1,4 @@
1
+ export * from './bytes';
1
2
  export * from './compression';
2
3
  export * from './crypto';
3
4
  export * from './id';
@@ -0,0 +1,38 @@
1
+ interface BunCryptoHasher {
2
+ update(data: string | Uint8Array): void;
3
+ digest(encoding: 'hex'): string;
4
+ }
5
+
6
+ interface BunRuntime {
7
+ CryptoHasher?: new (algorithm: string) => BunCryptoHasher;
8
+ gzipSync?: (data: Uint8Array) => Uint8Array;
9
+ readableStreamToBytes?: (
10
+ stream: ReadableStream<Uint8Array>
11
+ ) => Promise<Uint8Array | ArrayBuffer>;
12
+ }
13
+
14
+ type RuntimeGlobals = typeof globalThis & {
15
+ Bun?: BunRuntime;
16
+ Deno?: object;
17
+ process?: {
18
+ versions?: {
19
+ node?: string;
20
+ };
21
+ };
22
+ };
23
+
24
+ function getRuntimeGlobals(): RuntimeGlobals {
25
+ return globalThis as RuntimeGlobals;
26
+ }
27
+
28
+ export function getBunRuntime(): BunRuntime | null {
29
+ return getRuntimeGlobals().Bun ?? null;
30
+ }
31
+
32
+ export function usesNodeRuntimeModules(): boolean {
33
+ const globals = getRuntimeGlobals();
34
+ if (globals.Deno !== undefined) {
35
+ return true;
36
+ }
37
+ return typeof globals.process?.versions?.node === 'string';
38
+ }