@nsky/sync 0.1.0

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,148 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/utils/hlc.ts
3
+ var HLCClock = class {
4
+ #nodeId;
5
+ #now;
6
+ #lastWallTime = 0;
7
+ #counter = 0;
8
+ constructor(nodeId, now = Date.now) {
9
+ if (nodeId.length === 0) throw new Error("HLC node id is required.");
10
+ this.#nodeId = nodeId;
11
+ this.#now = now;
12
+ }
13
+ now() {
14
+ const wallTime = this.#now();
15
+ if (wallTime > this.#lastWallTime) {
16
+ this.#lastWallTime = wallTime;
17
+ this.#counter = 0;
18
+ } else this.#counter += 1;
19
+ return formatHLC({
20
+ wallTime: this.#lastWallTime,
21
+ counter: this.#counter,
22
+ nodeId: this.#nodeId
23
+ });
24
+ }
25
+ merge(remoteTimestamp) {
26
+ const remote = parseHLC(remoteTimestamp);
27
+ const wallTime = this.#now();
28
+ const maxWallTime = Math.max(wallTime, this.#lastWallTime, remote.wallTime);
29
+ if (maxWallTime === this.#lastWallTime && maxWallTime === remote.wallTime) this.#counter = Math.max(this.#counter, remote.counter) + 1;
30
+ else if (maxWallTime === this.#lastWallTime) this.#counter += 1;
31
+ else if (maxWallTime === remote.wallTime) this.#counter = remote.counter + 1;
32
+ else this.#counter = 0;
33
+ this.#lastWallTime = maxWallTime;
34
+ return formatHLC({
35
+ wallTime: this.#lastWallTime,
36
+ counter: this.#counter,
37
+ nodeId: this.#nodeId
38
+ });
39
+ }
40
+ };
41
+ function compareHLC(left, right) {
42
+ const a = parseHLC(left);
43
+ const b = parseHLC(right);
44
+ if (a.wallTime !== b.wallTime) return a.wallTime - b.wallTime;
45
+ if (a.counter !== b.counter) return a.counter - b.counter;
46
+ return a.nodeId.localeCompare(b.nodeId);
47
+ }
48
+ function parseHLC(timestamp) {
49
+ const match = /^(?<wallTime>\d{13})-(?<counter>\d{4})-(?<nodeId>.+)$/.exec(timestamp);
50
+ const wallTime = match?.groups?.wallTime;
51
+ const counter = match?.groups?.counter;
52
+ const nodeId = match?.groups?.nodeId;
53
+ if (wallTime === void 0 || counter === void 0 || nodeId === void 0) throw new Error(`Invalid HLC timestamp: ${timestamp}`);
54
+ return {
55
+ wallTime: Number(wallTime),
56
+ counter: Number(counter),
57
+ nodeId
58
+ };
59
+ }
60
+ function formatHLC(timestamp) {
61
+ return `${timestamp.wallTime.toString().padStart(13, "0")}-${timestamp.counter.toString().padStart(4, "0")}-${timestamp.nodeId}`;
62
+ }
63
+ //#endregion
64
+ //#region src/utils/id.ts
65
+ function createDeviceId() {
66
+ return `device-${createUuid()}`;
67
+ }
68
+ function createChangeId() {
69
+ return `change-${createUuid()}`;
70
+ }
71
+ function createUuid() {
72
+ if (globalThis.crypto?.randomUUID !== void 0) return globalThis.crypto.randomUUID();
73
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replaceAll(/[xy]/g, (token) => {
74
+ const value = Math.trunc(Math.random() * 16);
75
+ return (token === "x" ? value : value & 3 | 8).toString(16);
76
+ });
77
+ }
78
+ //#endregion
79
+ //#region src/utils/retry.ts
80
+ var ExponentialBackoffPolicy = class {
81
+ #maxAttempts;
82
+ #baseDelayMs;
83
+ #maxDelayMs;
84
+ #retryableCodes;
85
+ constructor(options = {}) {
86
+ this.#maxAttempts = options.maxAttempts ?? 3;
87
+ this.#baseDelayMs = options.baseDelayMs ?? 1e3;
88
+ this.#maxDelayMs = options.maxDelayMs ?? 3e4;
89
+ this.#retryableCodes = options.retryableCodes ?? /* @__PURE__ */ new Set([
90
+ "NETWORK_UNAVAILABLE",
91
+ "TRANSPORT_ERROR",
92
+ "SERVER_ERROR",
93
+ "UNKNOWN"
94
+ ]);
95
+ }
96
+ decide(context) {
97
+ if (!this.#retryableCodes.has(context.lastError.code)) return { action: "abort" };
98
+ if (context.attempt >= this.#maxAttempts) return { action: "abort" };
99
+ if (context.attempt === 0) return {
100
+ action: "retry",
101
+ delayMs: 0
102
+ };
103
+ return {
104
+ action: "retry",
105
+ delayMs: Math.min(this.#baseDelayMs * 2 ** (context.attempt - 1), this.#maxDelayMs)
106
+ };
107
+ }
108
+ };
109
+ async function retryOperation(operation, options) {
110
+ let attempt = 0;
111
+ let firstFailedAt = 0;
112
+ while (true) try {
113
+ return await operation();
114
+ } catch (error) {
115
+ const normalized = options.normalizeError(error);
116
+ firstFailedAt = firstFailedAt === 0 ? normalized.occurredAt : firstFailedAt;
117
+ const decision = options.policy.decide({
118
+ attempt,
119
+ firstFailedAt,
120
+ lastError: normalized
121
+ });
122
+ if (decision.action === "abort") throw error;
123
+ attempt += 1;
124
+ await (options.sleep ?? defaultSleep)(decision.delayMs);
125
+ }
126
+ }
127
+ function defaultSleep(delayMs) {
128
+ if (delayMs <= 0) return Promise.resolve();
129
+ return new Promise((resolve) => {
130
+ setTimeout(resolve, delayMs);
131
+ });
132
+ }
133
+ //#endregion
134
+ //#region src/utils/sleep.ts
135
+ function sleep(delayMs) {
136
+ if (delayMs <= 0) return Promise.resolve();
137
+ return new Promise((resolve) => {
138
+ setTimeout(resolve, delayMs);
139
+ });
140
+ }
141
+ //#endregion
142
+ exports.ExponentialBackoffPolicy = ExponentialBackoffPolicy;
143
+ exports.HLCClock = HLCClock;
144
+ exports.compareHLC = compareHLC;
145
+ exports.createChangeId = createChangeId;
146
+ exports.createDeviceId = createDeviceId;
147
+ exports.retryOperation = retryOperation;
148
+ exports.sleep = sleep;
@@ -0,0 +1,2 @@
1
+ import { a as RetryDecision, c as retryOperation, d as HLCClock, f as HLCTimestamp, i as RetryContext, l as createChangeId, n as ExponentialBackoffOptions, o as RetryOperationOptions, p as compareHLC, r as ExponentialBackoffPolicy, s as RetryPolicy, t as sleep, u as createDeviceId } from "../index.cjs";
2
+ export { ExponentialBackoffOptions, ExponentialBackoffPolicy, HLCClock, HLCTimestamp, RetryContext, RetryDecision, RetryOperationOptions, RetryPolicy, compareHLC, createChangeId, createDeviceId, retryOperation, sleep };
@@ -0,0 +1,2 @@
1
+ import { a as RetryDecision, c as retryOperation, d as HLCClock, f as HLCTimestamp, i as RetryContext, l as createChangeId, n as ExponentialBackoffOptions, o as RetryOperationOptions, p as compareHLC, r as ExponentialBackoffPolicy, s as RetryPolicy, t as sleep, u as createDeviceId } from "../index.mjs";
2
+ export { ExponentialBackoffOptions, ExponentialBackoffPolicy, HLCClock, HLCTimestamp, RetryContext, RetryDecision, RetryOperationOptions, RetryPolicy, compareHLC, createChangeId, createDeviceId, retryOperation, sleep };
@@ -0,0 +1,143 @@
1
+ //#region src/utils/hlc.ts
2
+ var HLCClock = class {
3
+ #nodeId;
4
+ #now;
5
+ #lastWallTime = 0;
6
+ #counter = 0;
7
+ constructor(nodeId, now = Date.now) {
8
+ if (nodeId.length === 0) throw new Error("HLC node id is required.");
9
+ this.#nodeId = nodeId;
10
+ this.#now = now;
11
+ }
12
+ now() {
13
+ const wallTime = this.#now();
14
+ if (wallTime > this.#lastWallTime) {
15
+ this.#lastWallTime = wallTime;
16
+ this.#counter = 0;
17
+ } else this.#counter += 1;
18
+ return formatHLC({
19
+ wallTime: this.#lastWallTime,
20
+ counter: this.#counter,
21
+ nodeId: this.#nodeId
22
+ });
23
+ }
24
+ merge(remoteTimestamp) {
25
+ const remote = parseHLC(remoteTimestamp);
26
+ const wallTime = this.#now();
27
+ const maxWallTime = Math.max(wallTime, this.#lastWallTime, remote.wallTime);
28
+ if (maxWallTime === this.#lastWallTime && maxWallTime === remote.wallTime) this.#counter = Math.max(this.#counter, remote.counter) + 1;
29
+ else if (maxWallTime === this.#lastWallTime) this.#counter += 1;
30
+ else if (maxWallTime === remote.wallTime) this.#counter = remote.counter + 1;
31
+ else this.#counter = 0;
32
+ this.#lastWallTime = maxWallTime;
33
+ return formatHLC({
34
+ wallTime: this.#lastWallTime,
35
+ counter: this.#counter,
36
+ nodeId: this.#nodeId
37
+ });
38
+ }
39
+ };
40
+ function compareHLC(left, right) {
41
+ const a = parseHLC(left);
42
+ const b = parseHLC(right);
43
+ if (a.wallTime !== b.wallTime) return a.wallTime - b.wallTime;
44
+ if (a.counter !== b.counter) return a.counter - b.counter;
45
+ return a.nodeId.localeCompare(b.nodeId);
46
+ }
47
+ function parseHLC(timestamp) {
48
+ const match = /^(?<wallTime>\d{13})-(?<counter>\d{4})-(?<nodeId>.+)$/.exec(timestamp);
49
+ const wallTime = match?.groups?.wallTime;
50
+ const counter = match?.groups?.counter;
51
+ const nodeId = match?.groups?.nodeId;
52
+ if (wallTime === void 0 || counter === void 0 || nodeId === void 0) throw new Error(`Invalid HLC timestamp: ${timestamp}`);
53
+ return {
54
+ wallTime: Number(wallTime),
55
+ counter: Number(counter),
56
+ nodeId
57
+ };
58
+ }
59
+ function formatHLC(timestamp) {
60
+ return `${timestamp.wallTime.toString().padStart(13, "0")}-${timestamp.counter.toString().padStart(4, "0")}-${timestamp.nodeId}`;
61
+ }
62
+ //#endregion
63
+ //#region src/utils/id.ts
64
+ function createDeviceId() {
65
+ return `device-${createUuid()}`;
66
+ }
67
+ function createChangeId() {
68
+ return `change-${createUuid()}`;
69
+ }
70
+ function createUuid() {
71
+ if (globalThis.crypto?.randomUUID !== void 0) return globalThis.crypto.randomUUID();
72
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replaceAll(/[xy]/g, (token) => {
73
+ const value = Math.trunc(Math.random() * 16);
74
+ return (token === "x" ? value : value & 3 | 8).toString(16);
75
+ });
76
+ }
77
+ //#endregion
78
+ //#region src/utils/retry.ts
79
+ var ExponentialBackoffPolicy = class {
80
+ #maxAttempts;
81
+ #baseDelayMs;
82
+ #maxDelayMs;
83
+ #retryableCodes;
84
+ constructor(options = {}) {
85
+ this.#maxAttempts = options.maxAttempts ?? 3;
86
+ this.#baseDelayMs = options.baseDelayMs ?? 1e3;
87
+ this.#maxDelayMs = options.maxDelayMs ?? 3e4;
88
+ this.#retryableCodes = options.retryableCodes ?? /* @__PURE__ */ new Set([
89
+ "NETWORK_UNAVAILABLE",
90
+ "TRANSPORT_ERROR",
91
+ "SERVER_ERROR",
92
+ "UNKNOWN"
93
+ ]);
94
+ }
95
+ decide(context) {
96
+ if (!this.#retryableCodes.has(context.lastError.code)) return { action: "abort" };
97
+ if (context.attempt >= this.#maxAttempts) return { action: "abort" };
98
+ if (context.attempt === 0) return {
99
+ action: "retry",
100
+ delayMs: 0
101
+ };
102
+ return {
103
+ action: "retry",
104
+ delayMs: Math.min(this.#baseDelayMs * 2 ** (context.attempt - 1), this.#maxDelayMs)
105
+ };
106
+ }
107
+ };
108
+ async function retryOperation(operation, options) {
109
+ let attempt = 0;
110
+ let firstFailedAt = 0;
111
+ while (true) try {
112
+ return await operation();
113
+ } catch (error) {
114
+ const normalized = options.normalizeError(error);
115
+ firstFailedAt = firstFailedAt === 0 ? normalized.occurredAt : firstFailedAt;
116
+ const decision = options.policy.decide({
117
+ attempt,
118
+ firstFailedAt,
119
+ lastError: normalized
120
+ });
121
+ if (decision.action === "abort") throw error;
122
+ attempt += 1;
123
+ await (options.sleep ?? defaultSleep)(decision.delayMs);
124
+ }
125
+ }
126
+ function defaultSleep(delayMs) {
127
+ if (delayMs <= 0) return Promise.resolve();
128
+ return new Promise((resolve) => {
129
+ setTimeout(resolve, delayMs);
130
+ });
131
+ }
132
+ //#endregion
133
+ //#region src/utils/sleep.ts
134
+ function sleep(delayMs) {
135
+ if (delayMs <= 0) return Promise.resolve();
136
+ return new Promise((resolve) => {
137
+ setTimeout(resolve, delayMs);
138
+ });
139
+ }
140
+ //#endregion
141
+ export { ExponentialBackoffPolicy, HLCClock, compareHLC, createChangeId, createDeviceId, retryOperation, sleep };
142
+
143
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["#nodeId","#now","#lastWallTime","#counter","#maxAttempts","#baseDelayMs","#maxDelayMs","#retryableCodes"],"sources":["../../src/utils/hlc.ts","../../src/utils/id.ts","../../src/utils/retry.ts","../../src/utils/sleep.ts"],"sourcesContent":["export type HLCTimestamp = string;\n\ninterface ParsedHLC {\n wallTime: number;\n counter: number;\n nodeId: string;\n}\n\nexport class HLCClock {\n readonly #nodeId: string;\n readonly #now: () => number;\n #lastWallTime = 0;\n #counter = 0;\n\n constructor(nodeId: string, now: () => number = Date.now) {\n if (nodeId.length === 0) {\n throw new Error(\"HLC node id is required.\");\n }\n\n this.#nodeId = nodeId;\n this.#now = now;\n }\n\n now(): HLCTimestamp {\n const wallTime = this.#now();\n\n if (wallTime > this.#lastWallTime) {\n this.#lastWallTime = wallTime;\n this.#counter = 0;\n } else {\n this.#counter += 1;\n }\n\n return formatHLC({\n wallTime: this.#lastWallTime,\n counter: this.#counter,\n nodeId: this.#nodeId,\n });\n }\n\n merge(remoteTimestamp: HLCTimestamp): HLCTimestamp {\n const remote = parseHLC(remoteTimestamp);\n const wallTime = this.#now();\n const maxWallTime = Math.max(wallTime, this.#lastWallTime, remote.wallTime);\n\n if (maxWallTime === this.#lastWallTime && maxWallTime === remote.wallTime) {\n this.#counter = Math.max(this.#counter, remote.counter) + 1;\n } else if (maxWallTime === this.#lastWallTime) {\n this.#counter += 1;\n } else if (maxWallTime === remote.wallTime) {\n this.#counter = remote.counter + 1;\n } else {\n this.#counter = 0;\n }\n\n this.#lastWallTime = maxWallTime;\n\n return formatHLC({\n wallTime: this.#lastWallTime,\n counter: this.#counter,\n nodeId: this.#nodeId,\n });\n }\n}\n\nexport function compareHLC(left: HLCTimestamp, right: HLCTimestamp): number {\n const a = parseHLC(left);\n const b = parseHLC(right);\n\n if (a.wallTime !== b.wallTime) {\n return a.wallTime - b.wallTime;\n }\n\n if (a.counter !== b.counter) {\n return a.counter - b.counter;\n }\n\n return a.nodeId.localeCompare(b.nodeId);\n}\n\nfunction parseHLC(timestamp: HLCTimestamp): ParsedHLC {\n const match = /^(?<wallTime>\\d{13})-(?<counter>\\d{4})-(?<nodeId>.+)$/.exec(timestamp);\n const wallTime = match?.groups?.wallTime;\n const counter = match?.groups?.counter;\n const nodeId = match?.groups?.nodeId;\n\n if (wallTime === undefined || counter === undefined || nodeId === undefined) {\n throw new Error(`Invalid HLC timestamp: ${timestamp}`);\n }\n\n return {\n wallTime: Number(wallTime),\n counter: Number(counter),\n nodeId,\n };\n}\n\nfunction formatHLC(timestamp: ParsedHLC): HLCTimestamp {\n return `${timestamp.wallTime.toString().padStart(13, \"0\")}-${timestamp.counter\n .toString()\n .padStart(4, \"0\")}-${timestamp.nodeId}`;\n}\n","export function createDeviceId(): string {\n return `device-${createUuid()}`;\n}\n\nexport function createChangeId(): string {\n return `change-${createUuid()}`;\n}\n\nfunction createUuid(): string {\n if (globalThis.crypto?.randomUUID !== undefined) {\n return globalThis.crypto.randomUUID();\n }\n\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replaceAll(/[xy]/g, (token) => {\n const value = Math.trunc(Math.random() * 16);\n const nibble = token === \"x\" ? value : (value & 0x3) | 0x8;\n return nibble.toString(16);\n });\n}\n","export interface RetryContext {\n readonly attempt: number;\n readonly lastError: {\n readonly code: string;\n readonly message: string;\n readonly occurredAt: number;\n };\n readonly firstFailedAt: number;\n}\n\nexport type RetryDecision =\n | { readonly action: \"retry\"; readonly delayMs: number }\n | { readonly action: \"abort\" };\n\nexport interface RetryPolicy {\n decide(context: RetryContext): RetryDecision;\n}\n\nexport interface RetryOperationOptions {\n readonly policy: RetryPolicy;\n readonly normalizeError: (error: unknown) => RetryContext[\"lastError\"];\n readonly sleep?: (delayMs: number) => Promise<void>;\n}\n\nexport interface ExponentialBackoffOptions {\n readonly maxAttempts?: number;\n readonly baseDelayMs?: number;\n readonly maxDelayMs?: number;\n readonly retryableCodes?: ReadonlySet<string>;\n}\n\nexport class ExponentialBackoffPolicy implements RetryPolicy {\n readonly #maxAttempts: number;\n readonly #baseDelayMs: number;\n readonly #maxDelayMs: number;\n readonly #retryableCodes: ReadonlySet<string>;\n\n constructor(options: ExponentialBackoffOptions = {}) {\n this.#maxAttempts = options.maxAttempts ?? 3;\n this.#baseDelayMs = options.baseDelayMs ?? 1_000;\n this.#maxDelayMs = options.maxDelayMs ?? 30_000;\n this.#retryableCodes =\n options.retryableCodes ??\n new Set([\"NETWORK_UNAVAILABLE\", \"TRANSPORT_ERROR\", \"SERVER_ERROR\", \"UNKNOWN\"]);\n }\n\n decide(context: RetryContext): RetryDecision {\n if (!this.#retryableCodes.has(context.lastError.code)) {\n return { action: \"abort\" };\n }\n\n if (context.attempt >= this.#maxAttempts) {\n return { action: \"abort\" };\n }\n\n if (context.attempt === 0) {\n return { action: \"retry\", delayMs: 0 };\n }\n\n const delayMs = Math.min(this.#baseDelayMs * 2 ** (context.attempt - 1), this.#maxDelayMs);\n return { action: \"retry\", delayMs };\n }\n}\n\nexport async function retryOperation<T>(\n operation: () => Promise<T>,\n options: RetryOperationOptions,\n): Promise<T> {\n let attempt = 0;\n let firstFailedAt = 0;\n\n while (true) {\n try {\n // Retry attempts are intentionally serial; each decision depends on the previous failure.\n // oxlint-disable-next-line no-await-in-loop\n return await operation();\n } catch (error) {\n const normalized = options.normalizeError(error);\n firstFailedAt = firstFailedAt === 0 ? normalized.occurredAt : firstFailedAt;\n const decision = options.policy.decide({\n attempt,\n firstFailedAt,\n lastError: normalized,\n });\n\n if (decision.action === \"abort\") {\n throw error;\n }\n\n attempt += 1;\n // oxlint-disable-next-line no-await-in-loop\n await (options.sleep ?? defaultSleep)(decision.delayMs);\n }\n }\n}\n\nfunction defaultSleep(delayMs: number): Promise<void> {\n if (delayMs <= 0) {\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n setTimeout(resolve, delayMs);\n });\n}\n","export function sleep(delayMs: number): Promise<void> {\n if (delayMs <= 0) {\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n setTimeout(resolve, delayMs);\n });\n}\n"],"mappings":";AAQA,IAAa,WAAb,MAAsB;CACpB;CACA;CACA,gBAAgB;CAChB,WAAW;CAEX,YAAY,QAAgB,MAAoB,KAAK,KAAK;EACxD,IAAI,OAAO,WAAW,GACpB,MAAM,IAAI,MAAM,0BAA0B;EAG5C,KAAKA,UAAU;EACf,KAAKC,OAAO;CACd;CAEA,MAAoB;EAClB,MAAM,WAAW,KAAKA,KAAK;EAE3B,IAAI,WAAW,KAAKC,eAAe;GACjC,KAAKA,gBAAgB;GACrB,KAAKC,WAAW;EAClB,OACE,KAAKA,YAAY;EAGnB,OAAO,UAAU;GACf,UAAU,KAAKD;GACf,SAAS,KAAKC;GACd,QAAQ,KAAKH;EACf,CAAC;CACH;CAEA,MAAM,iBAA6C;EACjD,MAAM,SAAS,SAAS,eAAe;EACvC,MAAM,WAAW,KAAKC,KAAK;EAC3B,MAAM,cAAc,KAAK,IAAI,UAAU,KAAKC,eAAe,OAAO,QAAQ;EAE1E,IAAI,gBAAgB,KAAKA,iBAAiB,gBAAgB,OAAO,UAC/D,KAAKC,WAAW,KAAK,IAAI,KAAKA,UAAU,OAAO,OAAO,IAAI;OACrD,IAAI,gBAAgB,KAAKD,eAC9B,KAAKC,YAAY;OACZ,IAAI,gBAAgB,OAAO,UAChC,KAAKA,WAAW,OAAO,UAAU;OAEjC,KAAKA,WAAW;EAGlB,KAAKD,gBAAgB;EAErB,OAAO,UAAU;GACf,UAAU,KAAKA;GACf,SAAS,KAAKC;GACd,QAAQ,KAAKH;EACf,CAAC;CACH;AACF;AAEA,SAAgB,WAAW,MAAoB,OAA6B;CAC1E,MAAM,IAAI,SAAS,IAAI;CACvB,MAAM,IAAI,SAAS,KAAK;CAExB,IAAI,EAAE,aAAa,EAAE,UACnB,OAAO,EAAE,WAAW,EAAE;CAGxB,IAAI,EAAE,YAAY,EAAE,SAClB,OAAO,EAAE,UAAU,EAAE;CAGvB,OAAO,EAAE,OAAO,cAAc,EAAE,MAAM;AACxC;AAEA,SAAS,SAAS,WAAoC;CACpD,MAAM,QAAQ,wDAAwD,KAAK,SAAS;CACpF,MAAM,WAAW,OAAO,QAAQ;CAChC,MAAM,UAAU,OAAO,QAAQ;CAC/B,MAAM,SAAS,OAAO,QAAQ;CAE9B,IAAI,aAAa,KAAA,KAAa,YAAY,KAAA,KAAa,WAAW,KAAA,GAChE,MAAM,IAAI,MAAM,0BAA0B,WAAW;CAGvD,OAAO;EACL,UAAU,OAAO,QAAQ;EACzB,SAAS,OAAO,OAAO;EACvB;CACF;AACF;AAEA,SAAS,UAAU,WAAoC;CACrD,OAAO,GAAG,UAAU,SAAS,SAAS,CAAC,CAAC,SAAS,IAAI,GAAG,EAAE,GAAG,UAAU,QACpE,SAAS,CAAC,CACV,SAAS,GAAG,GAAG,EAAE,GAAG,UAAU;AACnC;;;ACrGA,SAAgB,iBAAyB;CACvC,OAAO,UAAU,WAAW;AAC9B;AAEA,SAAgB,iBAAyB;CACvC,OAAO,UAAU,WAAW;AAC9B;AAEA,SAAS,aAAqB;CAC5B,IAAI,WAAW,QAAQ,eAAe,KAAA,GACpC,OAAO,WAAW,OAAO,WAAW;CAGtC,OAAO,uCAAuC,WAAW,UAAU,UAAU;EAC3E,MAAM,QAAQ,KAAK,MAAM,KAAK,OAAO,IAAI,EAAE;EAE3C,QADe,UAAU,MAAM,QAAS,QAAQ,IAAO,EAAA,CACzC,SAAS,EAAE;CAC3B,CAAC;AACH;;;ACaA,IAAa,2BAAb,MAA6D;CAC3D;CACA;CACA;CACA;CAEA,YAAY,UAAqC,CAAC,GAAG;EACnD,KAAKI,eAAe,QAAQ,eAAe;EAC3C,KAAKC,eAAe,QAAQ,eAAe;EAC3C,KAAKC,cAAc,QAAQ,cAAc;EACzC,KAAKC,kBACH,QAAQ,kCACR,IAAI,IAAI;GAAC;GAAuB;GAAmB;GAAgB;EAAS,CAAC;CACjF;CAEA,OAAO,SAAsC;EAC3C,IAAI,CAAC,KAAKA,gBAAgB,IAAI,QAAQ,UAAU,IAAI,GAClD,OAAO,EAAE,QAAQ,QAAQ;EAG3B,IAAI,QAAQ,WAAW,KAAKH,cAC1B,OAAO,EAAE,QAAQ,QAAQ;EAG3B,IAAI,QAAQ,YAAY,GACtB,OAAO;GAAE,QAAQ;GAAS,SAAS;EAAE;EAIvC,OAAO;GAAE,QAAQ;GAAS,SADV,KAAK,IAAI,KAAKC,eAAe,MAAM,QAAQ,UAAU,IAAI,KAAKC,WAC9C;EAAE;CACpC;AACF;AAEA,eAAsB,eACpB,WACA,SACY;CACZ,IAAI,UAAU;CACd,IAAI,gBAAgB;CAEpB,OAAO,MACL,IAAI;EAGF,OAAO,MAAM,UAAU;CACzB,SAAS,OAAO;EACd,MAAM,aAAa,QAAQ,eAAe,KAAK;EAC/C,gBAAgB,kBAAkB,IAAI,WAAW,aAAa;EAC9D,MAAM,WAAW,QAAQ,OAAO,OAAO;GACrC;GACA;GACA,WAAW;EACb,CAAC;EAED,IAAI,SAAS,WAAW,SACtB,MAAM;EAGR,WAAW;EAEX,OAAO,QAAQ,SAAS,aAAA,CAAc,SAAS,OAAO;CACxD;AAEJ;AAEA,SAAS,aAAa,SAAgC;CACpD,IAAI,WAAW,GACb,OAAO,QAAQ,QAAQ;CAGzB,OAAO,IAAI,SAAS,YAAY;EAC9B,WAAW,SAAS,OAAO;CAC7B,CAAC;AACH;;;ACxGA,SAAgB,MAAM,SAAgC;CACpD,IAAI,WAAW,GACb,OAAO,QAAQ,QAAQ;CAGzB,OAAO,IAAI,SAAS,YAAY;EAC9B,WAAW,SAAS,OAAO;CAC7B,CAAC;AACH"}
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "@nsky/sync",
3
+ "version": "0.1.0",
4
+ "description": "Headless local-first sync engine and adapters for @nsky packages.",
5
+ "files": [
6
+ "dist",
7
+ "README.md"
8
+ ],
9
+ "type": "module",
10
+ "sideEffects": false,
11
+ "main": "./dist/index.mjs",
12
+ "module": "./dist/index.mjs",
13
+ "types": "./dist/index.d.mts",
14
+ "exports": {
15
+ ".": {
16
+ "import": {
17
+ "types": "./dist/index.d.mts",
18
+ "default": "./dist/index.mjs"
19
+ },
20
+ "require": {
21
+ "types": "./dist/index.d.cts",
22
+ "default": "./dist/index.cjs"
23
+ },
24
+ "default": "./dist/index.mjs"
25
+ },
26
+ "./core": {
27
+ "import": {
28
+ "types": "./dist/core/index.d.mts",
29
+ "default": "./dist/core/index.mjs"
30
+ },
31
+ "require": {
32
+ "types": "./dist/core/index.d.cts",
33
+ "default": "./dist/core/index.cjs"
34
+ },
35
+ "default": "./dist/core/index.mjs"
36
+ },
37
+ "./utils": {
38
+ "import": {
39
+ "types": "./dist/utils/index.d.mts",
40
+ "default": "./dist/utils/index.mjs"
41
+ },
42
+ "require": {
43
+ "types": "./dist/utils/index.d.cts",
44
+ "default": "./dist/utils/index.cjs"
45
+ },
46
+ "default": "./dist/utils/index.mjs"
47
+ },
48
+ "./sql": {
49
+ "import": {
50
+ "types": "./dist/sql/index.d.mts",
51
+ "default": "./dist/sql/index.mjs"
52
+ },
53
+ "require": {
54
+ "types": "./dist/sql/index.d.cts",
55
+ "default": "./dist/sql/index.cjs"
56
+ },
57
+ "default": "./dist/sql/index.mjs"
58
+ },
59
+ "./http": {
60
+ "import": {
61
+ "types": "./dist/http/index.d.mts",
62
+ "default": "./dist/http/index.mjs"
63
+ },
64
+ "require": {
65
+ "types": "./dist/http/index.d.cts",
66
+ "default": "./dist/http/index.cjs"
67
+ },
68
+ "default": "./dist/http/index.mjs"
69
+ }
70
+ },
71
+ "publishConfig": {
72
+ "access": "public"
73
+ },
74
+ "dependencies": {
75
+ "dexie": "^4.2.2"
76
+ },
77
+ "devDependencies": {
78
+ "fake-indexeddb": "^6.2.5"
79
+ },
80
+ "engines": {
81
+ "node": "^22.18.0 || ^24.0.0"
82
+ },
83
+ "scripts": {
84
+ "build": "pnpm exec tsdown",
85
+ "dev": "pnpm exec tsdown --watch",
86
+ "publint": "publint",
87
+ "test": "vitest run",
88
+ "typecheck": "tsc --noEmit"
89
+ }
90
+ }