@byearlybird/starling 0.4.0 → 0.6.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.
package/dist/index.d.ts CHANGED
@@ -1,160 +1,73 @@
1
- import { t as __export } from "./chunk-Bp6m_JJh.js";
2
-
3
- //#region src/clock.d.ts
4
- declare namespace clock_d_exports {
5
- export { Clock, create$2 as create };
6
- }
7
- type Clock = {
8
- now: () => string;
9
- latest: () => string;
10
- forward: (eventstamp: string) => void;
11
- };
12
- declare const create$2: () => Clock;
13
- declare namespace value_d_exports {
14
- export { EncodedValue, decode$3 as decode, encode$3 as encode, isEncoded, merge$2 as merge };
15
- }
1
+ //#region src/value.d.ts
16
2
  type EncodedValue<T$1> = {
17
3
  "~value": T$1;
18
4
  "~eventstamp": string;
19
5
  };
20
- declare const encode$3: <T>(value: T, eventstamp: string) => EncodedValue<T>;
21
- declare const decode$3: <T>(value: EncodedValue<T>) => T;
22
- declare const merge$2: <T>(into: EncodedValue<T>, from: EncodedValue<T>) => EncodedValue<T>;
23
- declare const isEncoded: (value: unknown) => boolean;
24
- declare namespace record_d_exports {
25
- export { EncodedRecord, decode$2 as decode, encode$2 as encode, isObject, merge$1 as merge };
26
- }
6
+ //#endregion
7
+ //#region src/record.d.ts
27
8
  type EncodedRecord = {
28
9
  [key: string]: EncodedValue<unknown> | EncodedRecord;
29
10
  };
30
- declare const isObject: (value: unknown) => boolean;
31
- declare const encode$2: <T extends Record<string, unknown>>(obj: T, eventstamp: string) => EncodedRecord;
32
- declare const decode$2: <T extends Record<string, unknown>>(obj: EncodedRecord) => T;
33
- declare const merge$1: (into: EncodedRecord, from: EncodedRecord) => EncodedRecord;
34
- declare namespace document_d_exports {
35
- export { EncodedDocument, decode$1 as decode, del, encode$1 as encode, merge };
36
- }
11
+ //#endregion
12
+ //#region src/document.d.ts
37
13
  type EncodedDocument = {
38
14
  "~id": string;
39
15
  "~data": EncodedValue<unknown> | EncodedRecord;
40
16
  "~deletedAt": string | null;
41
17
  };
42
- declare const encode$1: <T>(id: string, obj: T, eventstamp: string, deletedAt?: string | null) => EncodedDocument;
43
- declare const decode$1: <T>(doc: EncodedDocument) => {
44
- "~id": string;
45
- "~data": T;
46
- "~deletedAt": string | null;
47
- };
48
- declare const merge: (into: EncodedDocument, from: EncodedDocument) => EncodedDocument;
49
- declare const del: (doc: EncodedDocument, eventstamp: string) => EncodedDocument;
50
- declare namespace eventstamp_d_exports {
51
- export { decode, encode };
52
- }
53
- declare const encode: (timestampMs: number, counter: number) => string;
54
- declare const decode: (eventstamp: string) => {
55
- timestampMs: number;
56
- counter: number;
18
+ //#endregion
19
+ //#region src/transaction.d.ts
20
+ type DeepPartial<T$1> = T$1 extends object ? { [P in keyof T$1]?: DeepPartial<T$1[P]> } : T$1;
21
+ type StorePutOptions = {
22
+ withId?: string;
57
23
  };
58
- declare namespace kv_d_exports {
59
- export { create$1 as create };
60
- }
61
- declare const create$1: (iterable?: Iterable<readonly [string, EncodedDocument]> | null) => {
62
- get(key: string): EncodedDocument | null;
63
- has(key: string): boolean;
64
- values(): MapIterator<EncodedDocument>;
65
- entries(): MapIterator<[string, EncodedDocument]>;
66
- readonly size: number;
67
- begin(): {
68
- get(key: string): EncodedDocument | null;
69
- put(key: string, value: EncodedDocument): void;
70
- patch(key: string, value: EncodedDocument): void;
71
- del(key: string, eventstamp: string): void;
72
- has(key: string): boolean;
73
- commit(): void;
74
- rollback(): void;
75
- };
24
+ type StoreSetTransaction<T$1> = {
25
+ add: (value: T$1, options?: StorePutOptions) => string;
26
+ update: (key: string, value: DeepPartial<T$1>) => void;
27
+ merge: (doc: EncodedDocument) => void;
28
+ del: (key: string) => void;
29
+ get: (key: string) => T$1 | null;
30
+ rollback: () => void;
76
31
  };
77
- declare namespace store_d_exports {
78
- export { Plugin, PluginHandle, PluginMethods, Store as StarlingStore, StoreHooks, StoreOnBeforeDelete, StoreOnBeforePatch, StoreOnBeforePut, StoreOnDelete, StoreOnPatch, StoreOnPut, StoreTransaction, create };
79
- }
80
- type DeepPartial<T$1> = T$1 extends object ? { [P in keyof T$1]?: DeepPartial<T$1[P]> } : T$1;
81
- /**
82
- * Called once per commit with all put operations accumulated as decoded entries.
83
- * Only fires if at least one put occurred.
84
- */
85
- type StoreOnPut<T$1> = (entries: ReadonlyArray<readonly [string, T$1]>) => void;
86
- /**
87
- * Called once per commit with all patch operations accumulated as decoded entries.
88
- * Only fires if at least one patch occurred.
89
- */
90
- type StoreOnPatch<T$1> = (entries: ReadonlyArray<readonly [string, T$1]>) => void;
91
- /**
92
- * Called once per commit with all deleted keys (IDs).
93
- * Only fires if at least one delete occurred.
94
- */
95
- type StoreOnDelete = (keys: ReadonlyArray<string>) => void;
96
- /**
97
- * Called before a put operation is applied.
98
- * Throws to reject the operation.
99
- */
100
- type StoreOnBeforePut<T$1> = (key: string, value: T$1) => void;
101
- /**
102
- * Called before a patch operation is applied.
103
- * Throws to reject the operation.
104
- */
105
- type StoreOnBeforePatch<T$1> = (key: string, value: DeepPartial<T$1>) => void;
32
+ //#endregion
33
+ //#region src/store.d.ts
106
34
  /**
107
- * Called before a delete operation is applied.
108
- * Throws to reject the operation.
35
+ * Type constraint to prevent Promise returns from set callbacks.
36
+ * Transactions must be synchronous operations.
109
37
  */
110
- type StoreOnBeforeDelete = (key: string) => void;
38
+ type NotPromise<T$1> = T$1 extends Promise<any> ? never : T$1;
111
39
  /**
112
- * Hook callbacks that receive batches of decoded entries.
113
- * Hooks fire on commit only, never during staged operations.
114
- * Arrays are readonly to prevent external mutation.
40
+ * Plugin lifecycle and event hooks.
41
+ * All hooks are optional except onInit and onDispose, which are required.
115
42
  */
116
- type StoreHooks<T$1> = {
117
- onBeforePut?: StoreOnBeforePut<T$1>;
118
- onBeforePatch?: StoreOnBeforePatch<T$1>;
119
- onBeforeDelete?: StoreOnBeforeDelete;
120
- onPut?: StoreOnPut<T$1>;
121
- onPatch?: StoreOnPatch<T$1>;
122
- onDelete?: StoreOnDelete;
123
- };
124
- type StoreTransaction<T$1> = {
125
- put: (key: string, value: T$1) => void;
126
- patch: (key: string, value: DeepPartial<T$1>) => void;
127
- merge: (doc: EncodedDocument) => void;
128
- del: (key: string) => void;
129
- has: (key: string) => boolean;
130
- commit: (opts?: {
131
- silent: boolean;
132
- }) => void;
133
- rollback: () => void;
43
+ type PluginHooks<T$1> = {
44
+ onInit: (store: Store<T$1>) => Promise<void> | void;
45
+ onDispose: () => Promise<void> | void;
46
+ onAdd?: (entries: ReadonlyArray<readonly [string, T$1]>) => void;
47
+ onUpdate?: (entries: ReadonlyArray<readonly [string, T$1]>) => void;
48
+ onDelete?: (keys: ReadonlyArray<string>) => void;
134
49
  };
135
50
  type PluginMethods = Record<string, (...args: any[]) => any>;
136
- type PluginHandle<T$1, M$1 extends PluginMethods = {}> = {
137
- init: () => Promise<void> | void;
138
- dispose: () => Promise<void> | void;
139
- hooks?: StoreHooks<T$1>;
51
+ type Plugin<T$1, M$1 extends PluginMethods = {}> = {
52
+ hooks: PluginHooks<T$1>;
140
53
  methods?: M$1;
141
54
  };
142
- type Plugin<T$1, M$1 extends PluginMethods = {}> = (store: Store<T$1, any>) => PluginHandle<T$1, M$1>;
143
55
  type Store<T$1, Extended = {}> = {
144
56
  get: (key: string) => T$1 | null;
145
- has: (key: string) => boolean;
146
- readonly size: number;
147
- values: () => IterableIterator<T$1>;
57
+ begin: <R = void>(callback: (tx: StoreSetTransaction<T$1>) => NotPromise<R>, opts?: {
58
+ silent?: boolean;
59
+ }) => NotPromise<R>;
60
+ add: (value: T$1, options?: StorePutOptions) => string;
61
+ update: (key: string, value: DeepPartial<T$1>) => void;
62
+ del: (key: string) => void;
148
63
  entries: () => IterableIterator<readonly [string, T$1]>;
149
64
  snapshot: () => EncodedDocument[];
150
- put: (key: string, value: T$1) => void;
151
- patch: (key: string, value: DeepPartial<T$1>) => void;
152
- del: (key: string) => void;
153
- begin: () => StoreTransaction<T$1>;
154
65
  use: <M extends PluginMethods>(plugin: Plugin<T$1, M>) => Store<T$1, Extended & M>;
155
66
  init: () => Promise<Store<T$1, Extended>>;
156
67
  dispose: () => Promise<void>;
157
68
  } & Extended;
158
- declare const create: <T>() => Store<T, {}>;
69
+ declare const createStore: <T>(config?: {
70
+ getId?: () => string;
71
+ }) => Store<T, {}>;
159
72
  //#endregion
160
- export { type clock_d_exports as Clock, document_d_exports as Document, eventstamp_d_exports as Eventstamp, kv_d_exports as KV, record_d_exports as Record, store_d_exports as Store, value_d_exports as Value };
73
+ export { type EncodedDocument, Plugin, PluginHooks, PluginMethods, Store, createStore };
package/dist/index.js CHANGED
@@ -1,404 +1 @@
1
- import { t as __export } from "./chunk-Bp6m_JJh.js";
2
-
3
- //#region src/eventstamp.ts
4
- var eventstamp_exports = /* @__PURE__ */ __export({
5
- decode: () => decode$3,
6
- encode: () => encode$3
7
- });
8
- const encode$3 = (timestampMs, counter) => {
9
- return `${new Date(timestampMs).toISOString()}|${counter.toString(16).padStart(8, "0")}`;
10
- };
11
- const decode$3 = (eventstamp) => {
12
- const pipeIndex = eventstamp.indexOf("|");
13
- const isoString = eventstamp.slice(0, pipeIndex);
14
- const hexCounter = eventstamp.slice(pipeIndex + 1);
15
- return {
16
- timestampMs: new Date(isoString).getTime(),
17
- counter: parseInt(hexCounter, 16)
18
- };
19
- };
20
-
21
- //#endregion
22
- //#region src/clock.ts
23
- var clock_exports = /* @__PURE__ */ __export({ create: () => create$2 });
24
- const create$2 = () => {
25
- let counter = 0;
26
- let lastMs = Date.now();
27
- return {
28
- now: () => {
29
- const nowMs = Date.now();
30
- if (nowMs <= lastMs) counter++;
31
- else {
32
- lastMs = nowMs;
33
- counter = 0;
34
- }
35
- return encode$3(nowMs, counter);
36
- },
37
- latest() {
38
- return encode$3(lastMs, counter);
39
- },
40
- forward(eventstamp) {
41
- if (eventstamp > this.latest()) {
42
- const newer = decode$3(eventstamp);
43
- lastMs = newer.timestampMs;
44
- counter = newer.counter;
45
- }
46
- }
47
- };
48
- };
49
-
50
- //#endregion
51
- //#region src/value.ts
52
- var value_exports = /* @__PURE__ */ __export({
53
- decode: () => decode$2,
54
- encode: () => encode$2,
55
- isEncoded: () => isEncoded,
56
- merge: () => merge$2
57
- });
58
- const encode$2 = (value, eventstamp) => ({
59
- "~value": value,
60
- "~eventstamp": eventstamp
61
- });
62
- const decode$2 = (value) => value["~value"];
63
- const merge$2 = (into, from) => ({
64
- "~value": into["~eventstamp"] > from["~eventstamp"] ? into["~value"] : from["~value"],
65
- "~eventstamp": into["~eventstamp"] > from["~eventstamp"] ? into["~eventstamp"] : from["~eventstamp"]
66
- });
67
- const isEncoded = (value) => !!(typeof value === "object" && value !== null && "~value" in value && "~eventstamp" in value);
68
-
69
- //#endregion
70
- //#region src/record.ts
71
- var record_exports = /* @__PURE__ */ __export({
72
- decode: () => decode$1,
73
- encode: () => encode$1,
74
- isObject: () => isObject,
75
- merge: () => merge$1
76
- });
77
- const isObject = (value) => !!(value != null && typeof value === "object" && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype);
78
- const encode$1 = (obj, eventstamp) => {
79
- const result = {};
80
- const step = (target, output) => {
81
- for (const key in target) {
82
- if (!Object.hasOwn(target, key)) continue;
83
- const value = target[key];
84
- if (isObject(value)) {
85
- output[key] = {};
86
- step(value, output[key]);
87
- } else output[key] = encode$2(value, eventstamp);
88
- }
89
- };
90
- step(obj, result);
91
- return result;
92
- };
93
- const decode$1 = (obj) => {
94
- const result = {};
95
- const step = (source, output) => {
96
- for (const key in source) {
97
- if (!Object.hasOwn(source, key)) continue;
98
- const value = source[key];
99
- if (isEncoded(value)) output[key] = decode$2(value);
100
- else if (isObject(value)) {
101
- output[key] = {};
102
- step(value, output[key]);
103
- }
104
- }
105
- };
106
- step(obj, result);
107
- return result;
108
- };
109
- const merge$1 = (into, from) => {
110
- const result = {};
111
- const step = (v1, v2, output) => {
112
- for (const key in v1) {
113
- if (!Object.hasOwn(v1, key)) continue;
114
- const value1 = v1[key];
115
- const value2 = v2[key];
116
- if (isEncoded(value1) && isEncoded(value2)) output[key] = merge$2(value1, value2);
117
- else if (isEncoded(value1)) output[key] = value1;
118
- else if (isObject(value1) && isObject(value2)) {
119
- output[key] = {};
120
- step(value1, value2, output[key]);
121
- } else if (value1) output[key] = value1;
122
- }
123
- for (const key in v2) {
124
- if (!Object.hasOwn(v2, key) || Object.hasOwn(output, key)) continue;
125
- const value = v2[key];
126
- if (value !== void 0) output[key] = value;
127
- }
128
- };
129
- step(into, from, result);
130
- return result;
131
- };
132
-
133
- //#endregion
134
- //#region src/document.ts
135
- var document_exports = /* @__PURE__ */ __export({
136
- decode: () => decode,
137
- del: () => del,
138
- encode: () => encode,
139
- merge: () => merge
140
- });
141
- const encode = (id, obj, eventstamp, deletedAt = null) => ({
142
- "~id": id,
143
- "~data": isObject(obj) ? encode$1(obj, eventstamp) : encode$2(obj, eventstamp),
144
- "~deletedAt": deletedAt
145
- });
146
- const decode = (doc) => ({
147
- "~id": doc["~id"],
148
- "~data": isEncoded(doc["~data"]) ? decode$2(doc["~data"]) : decode$1(doc["~data"]),
149
- "~deletedAt": doc["~deletedAt"]
150
- });
151
- const merge = (into, from) => {
152
- const intoIsValue = isEncoded(into["~data"]);
153
- const fromIsValue = isEncoded(from["~data"]);
154
- if (intoIsValue !== fromIsValue) throw new Error(`Cannot merge documents with incompatible types: ${intoIsValue ? "primitive" : "object"} vs ${fromIsValue ? "primitive" : "object"}`);
155
- const mergedData = intoIsValue && fromIsValue ? merge$2(into["~data"], from["~data"]) : merge$1(into["~data"], from["~data"]);
156
- const mergedDeletedAt = into["~deletedAt"] && from["~deletedAt"] ? into["~deletedAt"] > from["~deletedAt"] ? into["~deletedAt"] : from["~deletedAt"] : into["~deletedAt"] || from["~deletedAt"] || null;
157
- return {
158
- "~id": into["~id"],
159
- "~data": mergedData,
160
- "~deletedAt": mergedDeletedAt
161
- };
162
- };
163
- const del = (doc, eventstamp) => ({
164
- ...doc,
165
- "~deletedAt": eventstamp
166
- });
167
-
168
- //#endregion
169
- //#region src/kv.ts
170
- var kv_exports = /* @__PURE__ */ __export({ create: () => create$1 });
171
- const create$1 = (iterable) => {
172
- let readMap = new Map(iterable);
173
- function cloneMap(src) {
174
- return new Map(src);
175
- }
176
- return {
177
- get(key) {
178
- return readMap.get(key) ?? null;
179
- },
180
- has(key) {
181
- return readMap.has(key);
182
- },
183
- values() {
184
- return readMap.values();
185
- },
186
- entries() {
187
- return readMap.entries();
188
- },
189
- get size() {
190
- return readMap.size;
191
- },
192
- begin() {
193
- const staging = cloneMap(readMap);
194
- let committed = false;
195
- return {
196
- get(key) {
197
- return staging.get(key) ?? null;
198
- },
199
- put(key, value) {
200
- staging.set(key, value);
201
- },
202
- patch(key, value) {
203
- const prev = staging.get(key);
204
- staging.set(key, prev ? merge(prev, value) : value);
205
- },
206
- del(key, eventstamp) {
207
- const prev = staging.get(key);
208
- if (prev) staging.set(key, del(prev, eventstamp));
209
- },
210
- has(key) {
211
- return staging.get(key) !== void 0;
212
- },
213
- commit() {
214
- if (committed) return;
215
- committed = true;
216
- readMap = staging;
217
- },
218
- rollback() {
219
- committed = true;
220
- }
221
- };
222
- }
223
- };
224
- };
225
-
226
- //#endregion
227
- //#region src/store.ts
228
- var store_exports = /* @__PURE__ */ __export({ create: () => create });
229
- const create = () => {
230
- const kv = create$1();
231
- const clock = create$2();
232
- const encodeValue = (key, value) => encode(key, value, clock.now());
233
- const listeners = {
234
- beforePut: /* @__PURE__ */ new Set(),
235
- beforePatch: /* @__PURE__ */ new Set(),
236
- beforeDel: /* @__PURE__ */ new Set(),
237
- put: /* @__PURE__ */ new Set(),
238
- patch: /* @__PURE__ */ new Set(),
239
- del: /* @__PURE__ */ new Set()
240
- };
241
- const initializers = /* @__PURE__ */ new Set();
242
- const disposers = /* @__PURE__ */ new Set();
243
- const decodeActive = (doc) => {
244
- if (!doc || doc["~deletedAt"]) return null;
245
- return decode(doc)["~data"];
246
- };
247
- return {
248
- get(key) {
249
- return decodeActive(kv.get(key));
250
- },
251
- has(key) {
252
- return decodeActive(kv.get(key)) !== null;
253
- },
254
- values() {
255
- function* iterator() {
256
- for (const doc of kv.values()) {
257
- const data = decodeActive(doc);
258
- if (data !== null) yield data;
259
- }
260
- }
261
- return iterator();
262
- },
263
- entries() {
264
- function* iterator() {
265
- for (const [key, doc] of kv.entries()) {
266
- const data = decodeActive(doc);
267
- if (data !== null) yield [key, data];
268
- }
269
- }
270
- return iterator();
271
- },
272
- snapshot() {
273
- return Array.from(kv.values());
274
- },
275
- get size() {
276
- let count = 0;
277
- for (const doc of kv.values()) if (doc && !doc["~deletedAt"]) count++;
278
- return count;
279
- },
280
- put(key, value) {
281
- const tx = this.begin();
282
- tx.put(key, value);
283
- tx.commit();
284
- },
285
- patch(key, value) {
286
- const tx = this.begin();
287
- tx.patch(key, value);
288
- tx.commit();
289
- },
290
- del(key) {
291
- const tx = this.begin();
292
- tx.del(key);
293
- tx.commit();
294
- },
295
- begin() {
296
- const tx = kv.begin();
297
- const putKeyValues = [];
298
- const patchKeyValues = [];
299
- const deleteKeys = [];
300
- return {
301
- put(key, value) {
302
- for (const fn of listeners.beforePut) fn(key, value);
303
- tx.put(key, encodeValue(key, value));
304
- putKeyValues.push([key, value]);
305
- },
306
- patch(key, value) {
307
- for (const fn of listeners.beforePatch) fn(key, value);
308
- tx.patch(key, encode(key, value, clock.now()));
309
- const merged = decodeActive(tx.get(key));
310
- if (merged) patchKeyValues.push([key, merged]);
311
- },
312
- merge(doc) {
313
- if (tx.has(doc["~id"])) tx.patch(doc["~id"], doc);
314
- else tx.put(doc["~id"], doc);
315
- const currentDoc = tx.get(doc["~id"]);
316
- if (currentDoc && !currentDoc["~deletedAt"]) {
317
- const merged = decode(currentDoc)["~data"];
318
- patchKeyValues.push([doc["~id"], merged]);
319
- }
320
- },
321
- del(key) {
322
- for (const fn of listeners.beforeDel) fn(key);
323
- if (!tx.get(key)) return;
324
- tx.del(key, clock.now());
325
- deleteKeys.push(key);
326
- },
327
- has(key) {
328
- return tx.has(key);
329
- },
330
- commit(opts = { silent: false }) {
331
- tx.commit();
332
- if (opts.silent) return;
333
- if (putKeyValues.length > 0) for (const fn of listeners.put) fn(Object.freeze([...putKeyValues]));
334
- if (patchKeyValues.length > 0) for (const fn of listeners.patch) fn(Object.freeze([...patchKeyValues]));
335
- if (deleteKeys.length > 0) for (const fn of listeners.del) fn(Object.freeze([...deleteKeys]));
336
- },
337
- rollback() {
338
- tx.rollback();
339
- }
340
- };
341
- },
342
- use(plugin) {
343
- const { hooks: pluginHooks, init, dispose, methods } = plugin(this);
344
- if (pluginHooks) {
345
- if (pluginHooks.onBeforePut) {
346
- const callback = pluginHooks.onBeforePut;
347
- listeners.beforePut.add(callback);
348
- disposers.add(() => {
349
- listeners.beforePut.delete(callback);
350
- });
351
- }
352
- if (pluginHooks.onBeforePatch) {
353
- const callback = pluginHooks.onBeforePatch;
354
- listeners.beforePatch.add(callback);
355
- disposers.add(() => {
356
- listeners.beforePatch.delete(callback);
357
- });
358
- }
359
- if (pluginHooks.onBeforeDelete) {
360
- const callback = pluginHooks.onBeforeDelete;
361
- listeners.beforeDel.add(callback);
362
- disposers.add(() => {
363
- listeners.beforeDel.delete(callback);
364
- });
365
- }
366
- if (pluginHooks.onPut) {
367
- const callback = pluginHooks.onPut;
368
- listeners.put.add(callback);
369
- disposers.add(() => {
370
- listeners.put.delete(callback);
371
- });
372
- }
373
- if (pluginHooks.onPatch) {
374
- const callback = pluginHooks.onPatch;
375
- listeners.patch.add(callback);
376
- disposers.add(() => {
377
- listeners.patch.delete(callback);
378
- });
379
- }
380
- if (pluginHooks.onDelete) {
381
- const callback = pluginHooks.onDelete;
382
- listeners.del.add(callback);
383
- disposers.add(() => {
384
- listeners.del.delete(callback);
385
- });
386
- }
387
- }
388
- if (methods) Object.assign(this, methods);
389
- initializers.add(init);
390
- disposers.add(dispose);
391
- return this;
392
- },
393
- async init() {
394
- for (const fn of initializers) await fn();
395
- return this;
396
- },
397
- async dispose() {
398
- for (const fn of Array.from(disposers).toReversed()) await fn();
399
- }
400
- };
401
- };
402
-
403
- //#endregion
404
- export { clock_exports as Clock, document_exports as Document, eventstamp_exports as Eventstamp, kv_exports as KV, record_exports as Record, store_exports as Store, value_exports as Value };
1
+ const e=(e,t)=>`${new Date(e).toISOString()}|${t.toString(16).padStart(8,`0`)}`,t=e=>{let t=e.indexOf(`|`),n=e.slice(0,t),r=e.slice(t+1);return{timestampMs:new Date(n).getTime(),counter:parseInt(r,16)}},n=()=>{let n=0,r=Date.now();return{now:()=>{let t=Date.now();return t<=r?n++:(r=t,n=0),e(t,n)},latest(){return e(r,n)},forward(e){if(e>this.latest()){let i=t(e);r=i.timestampMs,n=i.counter}}}},r=e=>!!(typeof e==`object`&&e&&!Array.isArray(e)&&Object.getPrototypeOf(e)===Object.prototype),i=(e,t)=>({"~value":e,"~eventstamp":t}),a=e=>e[`~value`],o=(e,t)=>e[`~eventstamp`]>t[`~eventstamp`]?e:t,s=e=>!!(typeof e==`object`&&e&&`~value`in e&&`~eventstamp`in e),c=(e,t)=>{let n={},a=(e,n)=>{for(let o in e){if(!Object.hasOwn(e,o))continue;let s=e[o];r(s)?(n[o]={},a(s,n[o])):n[o]=i(s,t)}};return a(e,n),n},l=e=>{let t={},n=(e,t)=>{for(let i in e){if(!Object.hasOwn(e,i))continue;let o=e[i];s(o)?t[i]=a(o):r(o)&&(t[i]={},n(o,t[i]))}};return n(e,t),t},u=(e,t)=>{let n={},i=(e,t,n)=>{for(let a in e){if(!Object.hasOwn(e,a))continue;let c=e[a],l=t[a];s(c)&&s(l)?n[a]=o(c,l):s(c)?n[a]=c:r(c)&&r(l)?(n[a]={},i(c,l,n[a])):c&&(n[a]=c)}for(let e in t){if(!Object.hasOwn(t,e)||Object.hasOwn(n,e))continue;let r=t[e];r!==void 0&&(n[e]=r)}};return i(e,t,n),n},d=(e,t,n,a=null)=>({"~id":e,"~data":r(t)?c(t,n):i(t,n),"~deletedAt":a}),f=e=>({"~id":e[`~id`],"~data":s(e[`~data`])?a(e[`~data`]):l(e[`~data`]),"~deletedAt":e[`~deletedAt`]}),p=(e,t)=>{let n=s(e[`~data`]),r=s(t[`~data`]);if(n!==r)throw Error(`Merge error: Incompatible types`);let i=n&&r?o(e[`~data`],t[`~data`]):u(e[`~data`],t[`~data`]),a=e[`~deletedAt`]&&t[`~deletedAt`]?e[`~deletedAt`]>t[`~deletedAt`]?e[`~deletedAt`]:t[`~deletedAt`]:e[`~deletedAt`]||t[`~deletedAt`]||null;return{"~id":e[`~id`],"~data":i,"~deletedAt":a}},m=(e,t)=>({"~id":e[`~id`],"~data":e[`~data`],"~deletedAt":t}),h=e=>{let t=new Map(e);return{get(e){return t.get(e)??null},values(){return t.values()},entries(){return t.entries()},get size(){return t.size},begin(e){let n=new Map(t),r=!1;e({get(e){return n.get(e)??null},set(e,t,r){if(r?.replace)n.set(e,t);else{let r=n.get(e);n.set(e,r?p(r,t):t)}},del(e,t){let r=n.get(e);r&&n.set(e,m(r,t))},rollback(){r=!0}}),r||(t=n)}}},g=(e,t,n,r,i,a,o,s)=>{let c={rolledBack:!1},l={rolledBack:!1,add(t,i){let o=i?.withId??n();return e.set(o,r(o,t),{replace:!0}),a.push([o,t]),o},update(n,r){e.set(n,d(n,r,t.now()));let a=i(e.get(n));a&&o.push([n,a])},merge(t){e.get(t[`~id`])?e.set(t[`~id`],t):e.set(t[`~id`],t,{replace:!0});let n=e.get(t[`~id`]);if(n&&!n[`~deletedAt`]){let e=f(n)[`~data`];o.push([t[`~id`],e])}},del(n){e.get(n)&&(e.del(n,t.now()),s.push(n))},get(t){return i(e.get(t))},rollback(){c.rolledBack=!0,l.rolledBack=!0,e.rollback()}};return l},_=(e={})=>{let t=h(),r=n(),i=e.getId??(()=>crypto.randomUUID()),a=(e,t)=>d(e,t,r.now()),o=e=>!e||e[`~deletedAt`]?null:f(e)[`~data`],s=new Set,c=new Set,l=new Set,u=new Set,p=new Set;return{get(e){return o(t.get(e))},entries(){function*e(){for(let[e,n]of t.entries()){let t=o(n);t!==null&&(yield[e,t])}}return e()},snapshot(){return Array.from(t.values())},begin(e,n){let s=n?.silent??!1,c=[],d=[],f=[],m,h=!1;return t.begin(t=>{let n=g(t,r,i,a,o,c,d,f);m=e(n),!n.rolledBack&&!s&&(h=!0)}),h&&(c.length>0&&l.forEach(e=>{e(c)}),d.length>0&&u.forEach(e=>{e(d)}),f.length>0&&p.forEach(e=>{e(f)})),m},add(e,t){return this.begin(n=>n.add(e,t))},update(e,t){return this.begin(n=>n.update(e,t))},del(e){return this.begin(t=>t.del(e))},use(e){let{hooks:t,methods:n}=e;if(t.onAdd||t.onUpdate||t.onDelete){if(t.onAdd){let e=t.onAdd;l.add(e),c.add(()=>{l.delete(e)})}if(t.onUpdate){let e=t.onUpdate;u.add(e),c.add(()=>{u.delete(e)})}if(t.onDelete){let e=t.onDelete;p.add(e),c.add(()=>{p.delete(e)})}}return n&&Object.assign(this,n),s.add(t.onInit),c.add(t.onDispose),this},async init(){for(let e of s)await e(this);return this},async dispose(){let e=Array.from(c);e.reverse();for(let t of e)await t()}}};export{_ as createStore};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byearlybird/starling",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",
@@ -1,13 +0,0 @@
1
- //#region rolldown:runtime
2
- var __defProp = Object.defineProperty;
3
- var __export = (all) => {
4
- let target = {};
5
- for (var name in all) __defProp(target, name, {
6
- get: all[name],
7
- enumerable: true
8
- });
9
- return target;
10
- };
11
-
12
- //#endregion
13
- export { __export as t };