@keepkit/core 0.28.5 → 0.28.7
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 +66 -4
- package/dist/{chunk-AUNFZU3A.js → chunk-EMOPFB5D.js} +174 -43
- package/dist/chunk-EMOPFB5D.js.map +1 -0
- package/dist/{chunk-NZLAW4LY.js → chunk-SLH4DFYQ.js} +382 -70
- package/dist/chunk-SLH4DFYQ.js.map +1 -0
- package/dist/core.d.ts +35 -10
- package/dist/core.js +252 -92
- package/dist/core.js.map +1 -1
- package/dist/react.d.ts +5 -5
- package/dist/react.js +2 -2
- package/dist/schema.d.ts +1 -1
- package/dist/{scope-BteyH-b9.d.ts → scope-1bxGd68Y.d.ts} +4 -2
- package/dist/storage.d.ts +18 -12
- package/dist/storage.js +1 -1
- package/dist/{store-DVP3QyVp.d.ts → store-98vWM3tV.d.ts} +20 -2
- package/dist/{types-SKIL2p2c.d.ts → types-GTCMFt5T.d.ts} +52 -5
- package/package.json +1 -1
- package/dist/chunk-AUNFZU3A.js.map +0 -1
- package/dist/chunk-NZLAW4LY.js.map +0 -1
package/dist/storage.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as StorageAdapter, R as RemoteSyncDriver, d as SyncQueueAdapter,
|
|
2
|
-
import { K as KeepScope } from './scope-
|
|
3
|
-
export { S as ScopedStorageAdapter, a as ScopedSyncQueueAdapter, c as createScopedStorageAdapter } from './scope-
|
|
1
|
+
import { a as StorageAdapter, R as RemoteSyncDriver, d as SyncQueueAdapter, x as KeepConflictResolver, S as SyncScope, e as KeepSyncQueueOperation, p as SyncCapableStorageAdapter, K as KeepCollectionDefinition, b as KeepCollectionMembership, M as KeepSyncState, c as KeepItem, L as KeepSyncResolution } from './types-GTCMFt5T.js';
|
|
2
|
+
import { K as KeepScope } from './scope-1bxGd68Y.js';
|
|
3
|
+
export { S as ScopedStorageAdapter, a as ScopedSyncQueueAdapter, c as createScopedStorageAdapter } from './scope-1bxGd68Y.js';
|
|
4
4
|
|
|
5
5
|
type LocalStorageSyncQueueOptions = {
|
|
6
6
|
key?: string;
|
|
@@ -87,7 +87,7 @@ declare class SyncStorageAdapter<TMeta = Record<string, unknown>> implements Syn
|
|
|
87
87
|
private readonly clientId;
|
|
88
88
|
private readonly now;
|
|
89
89
|
private readonly resolveConflict?;
|
|
90
|
-
|
|
90
|
+
readonly scope?: SyncScope;
|
|
91
91
|
private readonly maxRetries;
|
|
92
92
|
private readonly retryDelayMs;
|
|
93
93
|
private readonly retryBackoff;
|
|
@@ -115,13 +115,17 @@ declare class SyncStorageAdapter<TMeta = Record<string, unknown>> implements Syn
|
|
|
115
115
|
flushSync(): Promise<void>;
|
|
116
116
|
retrySync(): Promise<void>;
|
|
117
117
|
resolveSyncConflict(id: string, resolution: KeepSyncResolution, item?: KeepItem<TMeta>): Promise<void>;
|
|
118
|
+
resolveCollectionSyncConflict(id: string, resolution: "local" | "remote", collection?: KeepCollectionDefinition): Promise<void>;
|
|
118
119
|
dispose(): void;
|
|
119
120
|
private runFlush;
|
|
120
121
|
private createOperation;
|
|
121
122
|
private createCollectionOperation;
|
|
123
|
+
private createMembershipOperation;
|
|
122
124
|
private applyScope;
|
|
123
125
|
private pushWithRetry;
|
|
124
126
|
private pushCollectionWithRetry;
|
|
127
|
+
private applyCollectionPushResult;
|
|
128
|
+
private pushMembershipWithRetry;
|
|
125
129
|
private enqueueBeforeLocalWrite;
|
|
126
130
|
private enqueueManyBeforeLocalWrite;
|
|
127
131
|
private loadQueue;
|
|
@@ -161,8 +165,8 @@ type StorageAdapterFactoryOptions<TMeta = Record<string, unknown>> = {
|
|
|
161
165
|
removeCollectionMembership?: (collectionId: string, itemId: string, scope?: KeepScope) => void | Promise<void>;
|
|
162
166
|
set: (item: KeepItem<TMeta>) => void | Promise<void>;
|
|
163
167
|
setMany?: (items: KeepItem<TMeta>[]) => void | Promise<void>;
|
|
164
|
-
remove: (id: string) => void | Promise<void>;
|
|
165
|
-
removeMany?: (ids: string[]) => void | Promise<void>;
|
|
168
|
+
remove: (id: string, scope?: KeepScope) => void | Promise<void>;
|
|
169
|
+
removeMany?: (ids: string[], scope?: KeepScope) => void | Promise<void>;
|
|
166
170
|
clear: () => void | Promise<void>;
|
|
167
171
|
merge?: (localItems: KeepItem<TMeta>[]) => KeepItem<TMeta>[] | Promise<KeepItem<TMeta>[]>;
|
|
168
172
|
subscribe?: (listener: () => void) => undefined | (() => void);
|
|
@@ -185,6 +189,7 @@ type FallbackStorageAdapterOptions<TMeta = Record<string, unknown>> = {
|
|
|
185
189
|
*/
|
|
186
190
|
declare class FallbackStorageAdapter<TMeta = Record<string, unknown>> implements StorageAdapter<TMeta> {
|
|
187
191
|
readonly storageKey: string | undefined;
|
|
192
|
+
readonly scope: KeepScope | undefined;
|
|
188
193
|
readonly getCollections?: () => Promise<KeepCollectionDefinition[]>;
|
|
189
194
|
readonly setCollection?: (collection: KeepCollectionDefinition) => Promise<void>;
|
|
190
195
|
readonly removeCollection?: (id: string, scope?: KeepScope) => Promise<void>;
|
|
@@ -204,8 +209,8 @@ declare class FallbackStorageAdapter<TMeta = Record<string, unknown>> implements
|
|
|
204
209
|
getAll(): Promise<KeepItem<TMeta>[]>;
|
|
205
210
|
set(item: KeepItem<TMeta>): Promise<void>;
|
|
206
211
|
setMany(items: KeepItem<TMeta>[]): Promise<void>;
|
|
207
|
-
remove(id: string): Promise<void>;
|
|
208
|
-
removeMany(ids: string[]): Promise<void>;
|
|
212
|
+
remove(id: string, scope?: KeepScope): Promise<void>;
|
|
213
|
+
removeMany(ids: string[], scope?: KeepScope): Promise<void>;
|
|
209
214
|
clear(): Promise<void>;
|
|
210
215
|
merge(localItems: KeepItem<TMeta>[]): Promise<KeepItem<TMeta>[]>;
|
|
211
216
|
subscribe(listener: () => void): () => void;
|
|
@@ -238,12 +243,13 @@ declare class LocalStorageAdapter<TMeta = Record<string, unknown>> implements St
|
|
|
238
243
|
setCollection(collection: KeepCollectionDefinition): Promise<void>;
|
|
239
244
|
removeCollection(id: string, scope?: KeepScope): Promise<void>;
|
|
240
245
|
getCollectionMemberships(): Promise<KeepCollectionMembership[]>;
|
|
246
|
+
private readMemberships;
|
|
241
247
|
setCollectionMembership(membership: KeepCollectionMembership): Promise<void>;
|
|
242
248
|
removeCollectionMembership(collectionId: string, itemId: string, scope?: KeepScope): Promise<void>;
|
|
243
249
|
set(item: KeepItem<TMeta>): Promise<void>;
|
|
244
250
|
setMany(items: KeepItem<TMeta>[]): Promise<void>;
|
|
245
|
-
remove(id: string): Promise<void>;
|
|
246
|
-
removeMany(ids: string[]): Promise<void>;
|
|
251
|
+
remove(id: string, scope?: KeepScope): Promise<void>;
|
|
252
|
+
removeMany(ids: string[], scope?: KeepScope): Promise<void>;
|
|
247
253
|
clear(): Promise<void>;
|
|
248
254
|
merge(localItems: KeepItem<TMeta>[]): Promise<KeepItem<TMeta>[]>;
|
|
249
255
|
subscribe(listener: () => void): () => void;
|
|
@@ -270,8 +276,8 @@ declare class IndexedDBAdapter<TMeta = Record<string, unknown>> implements Stora
|
|
|
270
276
|
removeCollectionMembership(collectionId: string, itemId: string, scope?: KeepScope): Promise<void>;
|
|
271
277
|
set(item: KeepItem<TMeta>): Promise<void>;
|
|
272
278
|
setMany(items: KeepItem<TMeta>[]): Promise<void>;
|
|
273
|
-
remove(id: string): Promise<void>;
|
|
274
|
-
removeMany(ids: string[]): Promise<void>;
|
|
279
|
+
remove(id: string, scope?: KeepScope): Promise<void>;
|
|
280
|
+
removeMany(ids: string[], scope?: KeepScope): Promise<void>;
|
|
275
281
|
clear(): Promise<void>;
|
|
276
282
|
merge(localItems: KeepItem<TMeta>[]): Promise<KeepItem<TMeta>[]>;
|
|
277
283
|
subscribe(listener: () => void): () => void;
|
package/dist/storage.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as KeepItem, f as KeepItemStatus, a as StorageAdapter, g as KeepSchema, h as KeepInvalidItemPolicy, K as KeepCollectionDefinition, b as KeepCollectionMembership, i as KeepChangeContext, j as KeepUndoState } from './types-
|
|
1
|
+
import { c as KeepItem, f as KeepItemStatus, a as StorageAdapter, g as KeepSchema, h as KeepInvalidItemPolicy, S as SyncScope, K as KeepCollectionDefinition, b as KeepCollectionMembership, i as KeepChangeContext, j as KeepUndoState } from './types-GTCMFt5T.js';
|
|
2
2
|
|
|
3
3
|
type KeepNavigationState<TMeta = Record<string, unknown>> = {
|
|
4
4
|
items: KeepItem<TMeta>[];
|
|
@@ -179,6 +179,8 @@ type KeepBackupV2<TMeta = Record<string, unknown>> = {
|
|
|
179
179
|
items: KeepItem<TMeta>[];
|
|
180
180
|
collections: KeepCollectionDefinition[];
|
|
181
181
|
memberships: KeepCollectionMembership[];
|
|
182
|
+
/** Scopes represented by the records in this backup. Omitted by early v2 backups. */
|
|
183
|
+
scopes?: SyncScope[];
|
|
182
184
|
};
|
|
183
185
|
type KeepBackup<TMeta = Record<string, unknown>> = KeepBackupV1<TMeta> | KeepBackupV2<TMeta>;
|
|
184
186
|
type ImportItemsOptions<TMeta = unknown> = {
|
|
@@ -186,6 +188,14 @@ type ImportItemsOptions<TMeta = unknown> = {
|
|
|
186
188
|
schema?: KeepSchema<TMeta>;
|
|
187
189
|
invalidItemPolicy?: KeepInvalidItemPolicy;
|
|
188
190
|
onInvalidItem?: (error: unknown, item: KeepItem<unknown>) => void;
|
|
191
|
+
/** Resolves a same-ID collection name collision when merging. Defaults to the backup name. */
|
|
192
|
+
collectionNameConflict?: "backup" | "existing";
|
|
193
|
+
};
|
|
194
|
+
type KeepBackupDataType = "items" | "collections" | "memberships";
|
|
195
|
+
type KeepBackupAppliedCounts = {
|
|
196
|
+
items: number;
|
|
197
|
+
collections: number;
|
|
198
|
+
memberships: number;
|
|
189
199
|
};
|
|
190
200
|
type ImportItemsResult<TMeta = Record<string, unknown>> = {
|
|
191
201
|
mode: "replace" | "merge";
|
|
@@ -193,6 +203,10 @@ type ImportItemsResult<TMeta = Record<string, unknown>> = {
|
|
|
193
203
|
failed: number;
|
|
194
204
|
total: number;
|
|
195
205
|
items: KeepItem<TMeta>[];
|
|
206
|
+
applied: KeepBackupAppliedCounts;
|
|
207
|
+
missingCollectionIds: string[];
|
|
208
|
+
includedData: KeepBackupDataType[];
|
|
209
|
+
scopes: SyncScope[];
|
|
196
210
|
};
|
|
197
211
|
declare class KeepBackupParseError extends Error {
|
|
198
212
|
readonly cause?: unknown;
|
|
@@ -204,11 +218,15 @@ declare class KeepBackupImportError extends Error {
|
|
|
204
218
|
readonly mode: "replace" | "merge";
|
|
205
219
|
readonly imported: number;
|
|
206
220
|
readonly failed: number;
|
|
221
|
+
readonly applied: KeepBackupAppliedCounts;
|
|
222
|
+
readonly failedStage: "items" | "collections" | "memberships" | "clear" | "validation";
|
|
207
223
|
readonly cause?: unknown;
|
|
208
224
|
constructor(message: string, options: {
|
|
209
225
|
mode: "replace" | "merge";
|
|
210
226
|
imported: number;
|
|
211
227
|
failed: number;
|
|
228
|
+
applied?: KeepBackupAppliedCounts;
|
|
229
|
+
failedStage?: "items" | "collections" | "memberships" | "clear" | "validation";
|
|
212
230
|
cause?: unknown;
|
|
213
231
|
});
|
|
214
232
|
}
|
|
@@ -272,4 +290,4 @@ declare class KeepStore<TMeta = Record<string, unknown>> {
|
|
|
272
290
|
setState(next: Partial<KeepStoreState<TMeta>>): void;
|
|
273
291
|
}
|
|
274
292
|
|
|
275
|
-
export {
|
|
293
|
+
export { type KeepUrlSyncOptions as A, createInboxQuery as B, createRediscoveryQuery as C, DEFAULT_KEEP_URL_PARAMS as D, decodeKeepListQuery as E, encodeKeepListQuery as F, exportItems as G, getKeepNavigationState as H, type ImportItemsOptions as I, getTagCounts as J, type KeepListQuery as K, importItems as L, isKeepItemMetadataStale as M, mergeKeepListQueryFromUrl as N, moveKeepItem as O, orderKeepItems as P, type QueryKeepItemsResult as Q, type RevalidateKeepItemsOptions as R, queryKeepItems as S, reconcileKeepItems as T, reorderKeepItems as U, revalidateKeepItems as V, serializeKeepListQuery as W, type ImportItemsResult as a, KEEP_BACKUP_FORMAT as b, KEEP_BACKUP_VERSION as c, type KeepAutoRevalidationOptions as d, type KeepBackup as e, type KeepBackupAppliedCounts as f, type KeepBackupDataType as g, KeepBackupImportError as h, KeepBackupParseError as i, type KeepBackupV1 as j, type KeepBackupV2 as k, type KeepCollectionMeta as l, type KeepItemMetadataRefresher as m, type KeepItemResolver as n, type KeepItemRevalidationRecord as o, type KeepItemRevalidationResult as p, type KeepItemRevalidationSummary as q, type KeepItemRevalidator as r, type KeepNavigationState as s, type KeepRediscoveryOptions as t, type KeepRediscoveryStrategy as u, KeepStore as v, type KeepStoreActions as w, type KeepStoreState as x, type KeepUrlParamNames as y, type KeepUrlState as z };
|
|
@@ -7,6 +7,9 @@ type KeepCollectionDefinition = {
|
|
|
7
7
|
id: string;
|
|
8
8
|
name: string;
|
|
9
9
|
scope?: SyncScope;
|
|
10
|
+
/** Server revision used for optimistic collection conflict checks. */
|
|
11
|
+
revision?: string;
|
|
12
|
+
updatedAt?: number;
|
|
10
13
|
};
|
|
11
14
|
/** A course-specific membership; the same item may have memberships in several collections. */
|
|
12
15
|
type KeepCollectionMembership = {
|
|
@@ -59,6 +62,8 @@ type KeepItemInput<TMeta = Record<string, unknown>> = {
|
|
|
59
62
|
collectionId?: string;
|
|
60
63
|
};
|
|
61
64
|
interface StorageAdapter<TMeta = Record<string, unknown>> {
|
|
65
|
+
/** Active user/tenant scope when this adapter is scoped. */
|
|
66
|
+
readonly scope?: SyncScope;
|
|
62
67
|
getAll(): Promise<KeepItem<TMeta>[]>;
|
|
63
68
|
/** Optional local collection metadata; independent of saved items and item backups. */
|
|
64
69
|
getCollections?(): Promise<KeepCollectionDefinition[]>;
|
|
@@ -71,8 +76,8 @@ interface StorageAdapter<TMeta = Record<string, unknown>> {
|
|
|
71
76
|
removeCollectionMembership?(collectionId: string, itemId: string, scope?: SyncScope): Promise<void>;
|
|
72
77
|
set(item: KeepItem<TMeta>): Promise<void>;
|
|
73
78
|
setMany?(items: KeepItem<TMeta>[]): Promise<void>;
|
|
74
|
-
remove(id: string): Promise<void>;
|
|
75
|
-
removeMany?(ids: string[]): Promise<void>;
|
|
79
|
+
remove(id: string, scope?: SyncScope): Promise<void>;
|
|
80
|
+
removeMany?(ids: string[], scope?: SyncScope): Promise<void>;
|
|
76
81
|
clear(): Promise<void>;
|
|
77
82
|
merge?(localItems: KeepItem<TMeta>[]): Promise<KeepItem<TMeta>[]>;
|
|
78
83
|
subscribe?(listener: () => void): () => void;
|
|
@@ -136,6 +141,7 @@ type KeepSyncState<TMeta = Record<string, unknown>> = {
|
|
|
136
141
|
conflictIds: string[];
|
|
137
142
|
/** Detailed conflict records when the adapter supports interactive resolution. */
|
|
138
143
|
conflicts?: KeepSyncConflict<TMeta>[];
|
|
144
|
+
collectionConflicts?: KeepCollectionSyncConflict[];
|
|
139
145
|
lastSyncedAt?: number;
|
|
140
146
|
error?: unknown;
|
|
141
147
|
};
|
|
@@ -159,10 +165,46 @@ type KeepCollectionSyncOperation = {
|
|
|
159
165
|
id: string;
|
|
160
166
|
collection?: KeepCollectionDefinition;
|
|
161
167
|
createdAt: number;
|
|
168
|
+
baseRevision?: string;
|
|
169
|
+
attempts?: number;
|
|
170
|
+
scope?: SyncScope;
|
|
171
|
+
};
|
|
172
|
+
/** A conflict carries a tombstone or the complete definition needed to inspect or apply its state. */
|
|
173
|
+
type KeepCollectionConflictState = {
|
|
174
|
+
deleted: true;
|
|
175
|
+
collection?: never;
|
|
176
|
+
} | {
|
|
177
|
+
deleted: false;
|
|
178
|
+
collection: KeepCollectionDefinition;
|
|
179
|
+
};
|
|
180
|
+
type KeepCollectionSyncResult = {
|
|
181
|
+
type: "synced";
|
|
182
|
+
collection?: KeepCollectionDefinition;
|
|
183
|
+
deleted?: boolean;
|
|
184
|
+
revision?: string;
|
|
185
|
+
} | ({
|
|
186
|
+
type: "conflict";
|
|
187
|
+
resolution: "local" | "remote" | "manual";
|
|
188
|
+
revision?: string;
|
|
189
|
+
} & KeepCollectionConflictState);
|
|
190
|
+
type KeepCollectionSyncConflict = {
|
|
191
|
+
operation: KeepCollectionSyncOperation;
|
|
192
|
+
resolution: "local" | "remote" | "manual";
|
|
193
|
+
revision?: string;
|
|
194
|
+
} & KeepCollectionConflictState;
|
|
195
|
+
type KeepMembershipSyncOperation = {
|
|
196
|
+
operationId: string;
|
|
197
|
+
type: "upsert" | "remove";
|
|
198
|
+
entity: "membership";
|
|
199
|
+
id: string;
|
|
200
|
+
collectionId: string;
|
|
201
|
+
itemId: string;
|
|
202
|
+
membership?: KeepCollectionMembership;
|
|
203
|
+
createdAt: number;
|
|
162
204
|
attempts?: number;
|
|
163
205
|
scope?: SyncScope;
|
|
164
206
|
};
|
|
165
|
-
type KeepSyncQueueOperation<TMeta = Record<string, unknown>> = SyncOperation<TMeta
|
|
207
|
+
type KeepSyncQueueOperation<TMeta = Record<string, unknown>> = SyncOperation<TMeta> | KeepCollectionSyncOperation | KeepMembershipSyncOperation;
|
|
166
208
|
type KeepSyncAuthStatus = 401 | 403;
|
|
167
209
|
/** Indicates that a sync request needs the host application to re-authenticate. */
|
|
168
210
|
declare class KeepSyncAuthError<TMeta = Record<string, unknown>> extends Error {
|
|
@@ -195,9 +237,13 @@ interface RemoteSyncDriver<TMeta = Record<string, unknown>> {
|
|
|
195
237
|
push(operation: SyncOperation<TMeta>): Promise<RemoteSyncResult<TMeta>>;
|
|
196
238
|
pull?: () => Promise<KeepItem<TMeta>[]>;
|
|
197
239
|
/** Push collection operations through the same scoped, durable queue as item operations. */
|
|
198
|
-
pushCollection?(operation: KeepCollectionSyncOperation): Promise<void>;
|
|
240
|
+
pushCollection?(operation: KeepCollectionSyncOperation): Promise<void | KeepCollectionSyncResult>;
|
|
199
241
|
/** Return the complete collection snapshot for the active authenticated scope. */
|
|
200
242
|
pullCollections?: () => Promise<KeepCollectionDefinition[]>;
|
|
243
|
+
/** Push collection/item membership operations through the same durable queue. */
|
|
244
|
+
pushMembership?(operation: KeepMembershipSyncOperation): Promise<void>;
|
|
245
|
+
/** Return the complete membership snapshot for the active authenticated scope. */
|
|
246
|
+
pullMemberships?: () => Promise<KeepCollectionMembership[]>;
|
|
201
247
|
}
|
|
202
248
|
interface SyncQueueAdapter<TMeta = Record<string, unknown>> {
|
|
203
249
|
getAll(): Promise<KeepSyncQueueOperation<TMeta>[]>;
|
|
@@ -212,6 +258,7 @@ interface SyncCapableStorageAdapter<TMeta = Record<string, unknown>> extends Sto
|
|
|
212
258
|
flushSync(): Promise<void>;
|
|
213
259
|
retrySync?(): Promise<void>;
|
|
214
260
|
resolveSyncConflict?(id: string, resolution: KeepSyncResolution, item?: KeepItem<TMeta>): Promise<void>;
|
|
261
|
+
resolveCollectionSyncConflict?(id: string, resolution: "local" | "remote", collection?: KeepCollectionDefinition): Promise<void>;
|
|
215
262
|
dispose?(): void;
|
|
216
263
|
}
|
|
217
264
|
type KeepStorageOperation = "getAll" | "set" | "remove" | "clear" | "merge";
|
|
@@ -268,4 +315,4 @@ type KeepUndoState = {
|
|
|
268
315
|
};
|
|
269
316
|
declare function normalizeKeepTags(tags?: string[]): string[] | undefined;
|
|
270
317
|
|
|
271
|
-
export {
|
|
318
|
+
export { type KeepEventHandlers as A, type KeepItemInput as B, type KeepSchemaParseResult as C, KeepStorageAccessError as D, KeepStorageError as E, type KeepStorageOperation as F, KeepStorageParseError as G, KeepStorageQuotaError as H, type KeepSyncAuthStatus as I, type KeepSyncConflict as J, type KeepCollectionDefinition as K, type KeepSyncResolution as L, type KeepSyncState as M, type KeepSyncStatus as N, isKeepSyncAuthError as O, normalizeKeepTags as P, type RemoteSyncDriver as R, type SyncScope as S, type StorageAdapter as a, type KeepCollectionMembership as b, type KeepItem as c, type SyncQueueAdapter as d, type KeepSyncQueueOperation as e, type KeepItemStatus as f, type KeepSchema as g, type KeepInvalidItemPolicy as h, type KeepChangeContext as i, type KeepUndoState as j, type KeepPluginContext as k, type KeepPlugin as l, type SyncOperation as m, type KeepCollectionSyncOperation as n, type KeepMembershipSyncOperation as o, type SyncCapableStorageAdapter as p, type RemoteSyncResult as q, KeepSyncAuthError as r, type KeepAction as s, type KeepChangePhase as t, type KeepCollectionSyncConflict as u, type KeepCollectionSyncResult as v, type KeepConflictContext as w, type KeepConflictResolver as x, type KeepErrorContext as y, type KeepErrorHandler as z };
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/features/items/navigation.ts","../src/features/persistence/migration.ts","../src/features/persistence/backup.ts","../src/features/items/query.ts","../src/features/items/revalidation.ts","../src/features/store/store.ts"],"sourcesContent":["import type { KeepItem } from \"./types\";\n\nexport type KeepNavigationState<TMeta = Record<string, unknown>> = {\n items: KeepItem<TMeta>[];\n currentIndex: number;\n currentPosition: number | null;\n currentItem: KeepItem<TMeta> | null;\n hasNext: boolean;\n hasPrev: boolean;\n nextItem: KeepItem<TMeta> | null;\n prevItem: KeepItem<TMeta> | null;\n};\n\n/** Return items in their persisted custom order, leaving legacy items stable. */\nexport function orderKeepItems<TMeta>(items: readonly KeepItem<TMeta>[]): KeepItem<TMeta>[] {\n if (!items.some((item) => item.order !== undefined)) return [...items];\n return items\n .map((item, index) => ({ item, index }))\n .sort((left, right) => {\n const leftOrder = left.item.order;\n const rightOrder = right.item.order;\n if (leftOrder === undefined && rightOrder !== undefined) return 1;\n if (leftOrder !== undefined && rightOrder === undefined) return -1;\n if (leftOrder !== undefined && rightOrder !== undefined && leftOrder !== rightOrder) {\n return leftOrder - rightOrder;\n }\n return left.index - right.index;\n })\n .map(({ item }) => item);\n}\n\n/** Derive the previous/current/next view for a list and an item id or index. */\nexport function getKeepNavigationState<TMeta = Record<string, unknown>>(\n source: readonly KeepItem<TMeta>[],\n current?: string | number,\n): KeepNavigationState<TMeta> {\n const items = orderKeepItems(source);\n const currentIndex =\n typeof current === \"number\"\n ? Number.isInteger(current) && current >= 0 && current < items.length\n ? current\n : -1\n : current === undefined\n ? -1\n : items.findIndex((item) => item.id === current);\n const currentItem = currentIndex >= 0 ? (items[currentIndex] ?? null) : null;\n return {\n items,\n currentIndex,\n currentPosition: currentIndex >= 0 ? currentIndex + 1 : null,\n currentItem,\n hasNext: currentIndex >= 0 && currentIndex < items.length - 1,\n hasPrev: currentIndex > 0,\n nextItem: currentIndex >= 0 ? (items[currentIndex + 1] ?? null) : null,\n prevItem: currentIndex > 0 ? (items[currentIndex - 1] ?? null) : null,\n };\n}\n\n/** Apply a partial or complete id order and assign stable zero-based positions. */\nexport function reorderKeepItems<TMeta = Record<string, unknown>>(\n source: readonly KeepItem<TMeta>[],\n orderedIds: readonly string[],\n): KeepItem<TMeta>[] {\n const byId = new Map(source.map((item) => [item.id, item]));\n const seen = new Set<string>();\n for (const id of orderedIds) {\n if (!byId.has(id)) throw new Error(`Cannot reorder unknown Keep item \"${id}\".`);\n if (seen.has(id)) throw new Error(`Cannot reorder Keep items with duplicate id \"${id}\".`);\n seen.add(id);\n }\n const current = orderKeepItems(source);\n const sequence = [...orderedIds, ...current.map((item) => item.id).filter((id) => !seen.has(id))];\n return sequence.map((id, order) => {\n const item = byId.get(id);\n if (!item) throw new Error(`Cannot reorder unknown Keep item \"${id}\".`);\n return { ...item, order };\n });\n}\n\n/** Move one item within the current custom/legacy order. */\nexport function moveKeepItem<TMeta = Record<string, unknown>>(\n source: readonly KeepItem<TMeta>[],\n id: string,\n targetIndex: number,\n): KeepItem<TMeta>[] {\n const items = orderKeepItems(source);\n const currentIndex = items.findIndex((item) => item.id === id);\n if (currentIndex < 0) throw new Error(`Cannot move unknown Keep item \"${id}\".`);\n if (!Number.isInteger(targetIndex)) throw new Error(\"Keep item targetIndex must be an integer.\");\n const nextIndex = Math.min(Math.max(0, targetIndex), items.length - 1);\n const [item] = items.splice(currentIndex, 1);\n items.splice(nextIndex, 0, item);\n return reorderKeepItems(\n items,\n items.map((entry) => entry.id),\n );\n}\n","import type { KeepItem, StorageAdapter } from \"../items/types\";\nimport { mergeKeepItemLists } from \"./helpers\";\n\n/** Merge anonymous local items into a signed-in or remote adapter. */\nexport async function mergeKeepItems<TMeta>(\n localItems: KeepItem<TMeta>[],\n target: StorageAdapter<TMeta>,\n): Promise<KeepItem<TMeta>[]> {\n if (target.merge) return target.merge(localItems);\n\n const merged = mergeKeepItemLists(await target.getAll(), localItems);\n await Promise.all(merged.map((item) => target.set(item)));\n return merged;\n}\n\n/** Read anonymous items, merge them into the target, then clear the source. */\nexport async function migrateKeepItems<TMeta>(\n source: StorageAdapter<TMeta>,\n target: StorageAdapter<TMeta>,\n): Promise<KeepItem<TMeta>[]> {\n const localItems = await source.getAll();\n const merged = await mergeKeepItems(localItems, target);\n await source.clear();\n return merged;\n}\n","import type {\n KeepCollectionDefinition,\n KeepCollectionMembership,\n KeepInvalidItemPolicy,\n KeepItem,\n KeepSchema,\n StorageAdapter,\n} from \"../items/types\";\nimport { isKeepCollectionDefinition, isKeepCollectionMembership, isKeepItem, isRecord } from \"./helpers\";\nimport { mergeKeepItems } from \"./migration\";\nimport { validateKeepItem } from \"./schema\";\n\nexport const KEEP_BACKUP_FORMAT = \"keepkit\";\nexport const KEEP_BACKUP_VERSION = 2;\n\nexport type KeepBackupV1<TMeta = Record<string, unknown>> = {\n format: typeof KEEP_BACKUP_FORMAT;\n version: 1;\n exportedAt: number;\n items: KeepItem<TMeta>[];\n};\n\nexport type KeepBackupV2<TMeta = Record<string, unknown>> = {\n format: typeof KEEP_BACKUP_FORMAT;\n version: typeof KEEP_BACKUP_VERSION;\n exportedAt: number;\n items: KeepItem<TMeta>[];\n collections: KeepCollectionDefinition[];\n memberships: KeepCollectionMembership[];\n};\n\nexport type KeepBackup<TMeta = Record<string, unknown>> = KeepBackupV1<TMeta> | KeepBackupV2<TMeta>;\n\ntype ParsedKeepBackup<TMeta> = Omit<KeepBackupV2<TMeta>, \"version\"> & { version: 1 | typeof KEEP_BACKUP_VERSION };\n\nexport type ImportItemsOptions<TMeta = unknown> = {\n mode?: \"replace\" | \"merge\";\n schema?: KeepSchema<TMeta>;\n invalidItemPolicy?: KeepInvalidItemPolicy;\n onInvalidItem?: (error: unknown, item: KeepItem<unknown>) => void;\n};\n\nexport type ImportItemsResult<TMeta = Record<string, unknown>> = {\n mode: \"replace\" | \"merge\";\n imported: number;\n failed: number;\n total: number;\n items: KeepItem<TMeta>[];\n};\n\nexport class KeepBackupParseError extends Error {\n readonly cause?: unknown;\n\n constructor(message: string, options?: { cause?: unknown }) {\n super(message);\n this.name = \"KeepBackupParseError\";\n if (options?.cause !== undefined) this.cause = options.cause;\n }\n}\n\nexport class KeepBackupImportError extends Error {\n readonly mode: \"replace\" | \"merge\";\n readonly imported: number;\n readonly failed: number;\n readonly cause?: unknown;\n\n constructor(\n message: string,\n options: {\n mode: \"replace\" | \"merge\";\n imported: number;\n failed: number;\n cause?: unknown;\n },\n ) {\n super(message);\n this.name = \"KeepBackupImportError\";\n this.mode = options.mode;\n this.imported = options.imported;\n this.failed = options.failed;\n if (options.cause !== undefined) this.cause = options.cause;\n }\n}\n\n/** Serialize all adapter data into a versioned JSON backup. */\nexport async function exportItems<TMeta>(adapter: StorageAdapter<TMeta>): Promise<string> {\n const backup: KeepBackupV2<TMeta> = {\n format: KEEP_BACKUP_FORMAT,\n version: KEEP_BACKUP_VERSION,\n exportedAt: Date.now(),\n items: await adapter.getAll(),\n collections: (await adapter.getCollections?.()) ?? [],\n memberships: (await adapter.getCollectionMemberships?.()) ?? [],\n };\n return JSON.stringify(backup, null, 2);\n}\n\n/** Validate and restore a backup, either replacing or merging existing data. */\nexport async function importItems<TMeta>(\n adapter: StorageAdapter<TMeta>,\n data: string | KeepBackup<TMeta>,\n options: ImportItemsOptions<TMeta> = {},\n): Promise<ImportItemsResult<TMeta>> {\n const backup = parseBackup<TMeta>(data);\n const mode = options.mode ?? \"merge\";\n if (\n (backup.collections.length > 0 &&\n (!adapter.getCollections || !adapter.setCollection || !adapter.removeCollection)) ||\n (backup.memberships.length > 0 &&\n (!adapter.getCollectionMemberships || !adapter.setCollectionMembership || !adapter.removeCollectionMembership))\n ) {\n throw new KeepBackupImportError(\"The storage adapter cannot restore collection data from this backup.\", {\n mode,\n imported: 0,\n failed: backup.items.length + backup.collections.length + backup.memberships.length,\n });\n }\n const validItems: KeepItem<TMeta>[] = [];\n let failed = 0;\n for (const item of backup.items) {\n if (!options.schema) {\n validItems.push(item);\n continue;\n }\n try {\n validItems.push(await validateKeepItem(item, options.schema));\n } catch (cause) {\n options.onInvalidItem?.(cause, item);\n if ((options.invalidItemPolicy ?? \"error\") === \"drop\") {\n failed += 1;\n continue;\n }\n throw cause;\n }\n }\n let items: KeepItem<TMeta>[];\n\n if (mode === \"merge\") {\n try {\n items = await mergeKeepItems(validItems, adapter);\n await restoreCollections(adapter, backup.collections, \"merge\");\n await restoreMemberships(adapter, backup.memberships, \"merge\");\n } catch (cause) {\n throw new KeepBackupImportError(\"KeepKit could not merge the backup.\", {\n mode,\n imported: 0,\n failed: validItems.length + failed,\n cause,\n });\n }\n } else {\n let imported = 0;\n try {\n await adapter.clear();\n await restoreCollections(adapter, [], \"replace\");\n await restoreMemberships(adapter, [], \"replace\");\n for (const item of validItems) {\n await adapter.set(item);\n imported += 1;\n }\n await restoreCollections(adapter, backup.collections, \"replace\");\n await restoreMemberships(adapter, backup.memberships, \"replace\");\n items = await adapter.getAll();\n } catch (cause) {\n throw new KeepBackupImportError(\"KeepKit could not replace the stored items.\", {\n mode,\n imported,\n failed: validItems.length + failed - imported,\n cause,\n });\n }\n }\n\n return {\n mode,\n imported: validItems.length,\n failed,\n total: items.length,\n items,\n };\n}\n\nfunction parseBackup<TMeta>(data: string | KeepBackup<TMeta>): ParsedKeepBackup<TMeta> {\n let value: unknown = data;\n if (typeof data === \"string\") {\n try {\n value = JSON.parse(data);\n } catch (cause) {\n throw new KeepBackupParseError(\"KeepKit backup is not valid JSON.\", { cause });\n }\n }\n\n if (!isRecord(value)) throw new KeepBackupParseError(\"KeepKit backup must be an object.\");\n if (value.format !== KEEP_BACKUP_FORMAT || (value.version !== 1 && value.version !== KEEP_BACKUP_VERSION)) {\n throw new KeepBackupParseError(\"KeepKit backup format or version is unsupported.\");\n }\n if (typeof value.exportedAt !== \"number\" || !Number.isFinite(value.exportedAt)) {\n throw new KeepBackupParseError(\"KeepKit backup has an invalid export timestamp.\");\n }\n if (!Array.isArray(value.items) || !value.items.every(isKeepItem)) {\n throw new KeepBackupParseError(\"KeepKit backup contains invalid items.\");\n }\n if (value.version === 1) {\n return {\n format: KEEP_BACKUP_FORMAT,\n version: 1,\n exportedAt: value.exportedAt,\n items: value.items as KeepItem<TMeta>[],\n collections: [],\n memberships: [],\n };\n }\n if (\n !Array.isArray(value.collections) ||\n !value.collections.every(isKeepCollectionDefinition) ||\n !Array.isArray(value.memberships) ||\n !value.memberships.every(isKeepCollectionMembership)\n ) {\n throw new KeepBackupParseError(\"KeepKit backup contains invalid collection data.\");\n }\n return value as ParsedKeepBackup<TMeta>;\n}\n\nasync function restoreCollections<TMeta>(\n adapter: StorageAdapter<TMeta>,\n collections: KeepCollectionDefinition[],\n mode: \"merge\" | \"replace\",\n): Promise<void> {\n if (!adapter.getCollections || !adapter.setCollection || !adapter.removeCollection) return;\n if (mode === \"replace\") {\n const current = await adapter.getCollections();\n for (const collection of current) await adapter.removeCollection(collection.id, collection.scope);\n }\n for (const collection of collections) await adapter.setCollection(collection);\n}\n\nasync function restoreMemberships<TMeta>(\n adapter: StorageAdapter<TMeta>,\n memberships: KeepCollectionMembership[],\n mode: \"merge\" | \"replace\",\n): Promise<void> {\n if (!adapter.getCollectionMemberships || !adapter.setCollectionMembership || !adapter.removeCollectionMembership)\n return;\n if (mode === \"replace\") {\n const current = await adapter.getCollectionMemberships();\n for (const membership of current) {\n await adapter.removeCollectionMembership(membership.collectionId, membership.itemId, membership.scope);\n }\n }\n for (const membership of memberships) await adapter.setCollectionMembership(membership);\n}\n","import { orderKeepItems } from \"./navigation\";\nimport type { KeepItem } from \"./types\";\n\nexport type KeepListQuery<TMeta = Record<string, unknown>> = {\n targetType?: string;\n tags?: string[];\n /** Defaults to active (not archived) items; true selects archived items. */\n archived?: boolean;\n /** Optional explicit archive scope. When provided, this takes precedence over `archived`. */\n archiveScope?: \"active\" | \"archived\" | \"all\";\n collectionId?: string;\n organization?: {\n collection?: \"assigned\" | \"unassigned\";\n tags?: \"assigned\" | \"unassigned\";\n note?: \"assigned\" | \"unassigned\";\n };\n pinnedFirst?: boolean;\n activity?: {\n opened?: \"ever\" | \"never\";\n lastOpenedBefore?: number;\n lastOpenedAfter?: number;\n inactiveForMs?: number;\n };\n sort?: {\n by: \"savedAt\" | \"updatedAt\" | \"lastOpenedAt\";\n direction?: \"asc\" | \"desc\";\n };\n search?: {\n query?: string;\n mode?: \"and\" | \"or\";\n tokenize?: boolean;\n fields?: Array<\"note\" | \"meta\" | \"tags\">;\n };\n pagination?: {\n page?: number;\n pageSize?: number;\n };\n filter?: (item: KeepItem<TMeta>) => boolean;\n savedBetween?: readonly [Date | number, Date | number];\n};\n\nexport type QueryKeepItemsResult<TMeta = Record<string, unknown>> = {\n items: KeepItem<TMeta>[];\n totalCount: number;\n tagCounts: Record<string, number>;\n page: number;\n pageCount: number;\n hasNextPage: boolean;\n hasPreviousPage: boolean;\n};\n\nexport type KeepRediscoveryStrategy = \"never-opened\" | \"forgotten\" | \"recently-opened\";\n\nexport type KeepRediscoveryOptions = {\n strategy: KeepRediscoveryStrategy;\n inactiveForMs?: number;\n};\n\n/** Build the default Inbox query: active items without a collection. */\nexport function createInboxQuery<TMeta = Record<string, unknown>>(\n options: { organization?: KeepListQuery<TMeta>[\"organization\"] } = {},\n): KeepListQuery<TMeta> {\n return { organization: { collection: \"unassigned\", ...options.organization } };\n}\n\nconst DEFAULT_REDISCOVERY_INACTIVE_FOR_MS = 30 * 24 * 60 * 60 * 1000;\n\n/** Build a serializable query for common rediscovery views. */\nexport function createRediscoveryQuery<TMeta = Record<string, unknown>>(\n options: KeepRediscoveryOptions,\n): KeepListQuery<TMeta> {\n if (options.strategy === \"never-opened\") return { activity: { opened: \"never\" } };\n if (options.strategy === \"recently-opened\") {\n return { activity: { opened: \"ever\" }, sort: { by: \"lastOpenedAt\", direction: \"desc\" } };\n }\n return { activity: { inactiveForMs: options.inactiveForMs ?? DEFAULT_REDISCOVERY_INACTIVE_FOR_MS } };\n}\n\n/** Apply the collection query and one-based pagination without React. */\nexport function queryKeepItems<TMeta = Record<string, unknown>>(\n source: KeepItem<TMeta>[],\n query: KeepListQuery<TMeta> = {},\n): QueryKeepItemsResult<TMeta> {\n const filtered = source.filter((item) => {\n const [from, to] = query.savedBetween ?? [];\n const savedAt = item.savedAt;\n const lowerBound = from === undefined ? undefined : toTimestamp(from);\n const upperBound = to === undefined ? undefined : toTimestamp(to);\n return (\n (query.targetType === undefined || item.targetType === query.targetType) &&\n (query.tags === undefined || query.tags.every((tag) => item.tags?.includes(tag))) &&\n matchesArchiveScope(item, query) &&\n (query.collectionId === undefined || item.collectionId === query.collectionId) &&\n matchesOrganization(item, query.organization) &&\n matchesActivity(item, query.activity) &&\n (lowerBound === undefined || savedAt >= lowerBound) &&\n (upperBound === undefined || savedAt <= upperBound) &&\n matchesSearch(item, query.search) &&\n (query.filter?.(item) ?? true)\n );\n });\n const tagCounts = getTagCounts(filtered);\n const sortBy = query.sort?.by;\n const direction = query.sort?.direction === \"asc\" ? 1 : -1;\n const sortedBase = sortBy\n ? filtered\n .map((item, index) => ({ item, index }))\n .sort((a, b) => compareSortValues(a.item[sortBy], b.item[sortBy], direction) || a.index - b.index)\n .map(({ item }) => item)\n : orderKeepItems(filtered);\n const sorted = query.pinnedFirst\n ? [...sortedBase.filter((item) => item.pinned === true), ...sortedBase.filter((item) => item.pinned !== true)]\n : sortedBase;\n const pageSize = Math.max(1, query.pagination?.pageSize ?? (sorted.length || 1));\n const pageCount = Math.max(1, Math.ceil(sorted.length / pageSize));\n const page = Math.min(Math.max(1, query.pagination?.page ?? 1), pageCount);\n const offset = (page - 1) * pageSize;\n\n return {\n items: sorted.slice(offset, offset + pageSize),\n totalCount: sorted.length,\n tagCounts,\n page,\n pageCount,\n hasNextPage: page < pageCount,\n hasPreviousPage: page > 1,\n };\n}\n\nfunction matchesOrganization<TMeta>(\n item: KeepItem<TMeta>,\n organization: KeepListQuery<TMeta>[\"organization\"],\n): boolean {\n if (organization?.collection === \"assigned\" && !item.collectionId?.trim()) return false;\n if (organization?.collection === \"unassigned\" && item.collectionId?.trim()) return false;\n if (organization?.tags === \"assigned\" && !item.tags?.some((tag) => tag.trim())) return false;\n if (organization?.tags === \"unassigned\" && item.tags?.some((tag) => tag.trim())) return false;\n if (organization?.note === \"assigned\" && !item.note?.trim()) return false;\n if (organization?.note === \"unassigned\" && item.note?.trim()) return false;\n return true;\n}\n\nfunction matchesActivity<TMeta>(item: KeepItem<TMeta>, activity?: KeepListQuery<TMeta>[\"activity\"]): boolean {\n if (!activity) return true;\n const lastOpenedAt = item.lastOpenedAt;\n const opened = lastOpenedAt !== undefined;\n if (activity.opened === \"ever\" && !opened) return false;\n if (activity.opened === \"never\" && opened) return false;\n if (activity.lastOpenedBefore !== undefined && (!opened || lastOpenedAt >= activity.lastOpenedBefore)) return false;\n if (activity.lastOpenedAfter !== undefined && (!opened || lastOpenedAt <= activity.lastOpenedAfter)) return false;\n if (activity.inactiveForMs !== undefined) {\n const cutoff = Date.now() - activity.inactiveForMs;\n const lastActivityAt = item.lastOpenedAt ?? item.savedAt;\n if (lastActivityAt > cutoff) return false;\n }\n return true;\n}\n\nfunction compareSortValues(left: number | undefined, right: number | undefined, direction: 1 | -1): number {\n if (left === undefined && right === undefined) return 0;\n if (left === undefined) return 1;\n if (right === undefined) return -1;\n return (left - right) * direction;\n}\n\nfunction matchesArchiveScope<TMeta>(item: KeepItem<TMeta>, query: KeepListQuery<TMeta>): boolean {\n if (query.archiveScope === \"all\") return true;\n if (query.archiveScope === \"archived\") return item.archived === true;\n if (query.archiveScope === \"active\") return item.archived !== true;\n return query.archived === true ? item.archived === true : item.archived !== true;\n}\n\nexport function getTagCounts<TMeta = Record<string, unknown>>(items: KeepItem<TMeta>[]): Record<string, number> {\n const counts: Record<string, number> = {};\n for (const item of items) {\n for (const tag of item.tags ?? []) counts[tag] = (counts[tag] ?? 0) + 1;\n }\n return Object.fromEntries(Object.entries(counts).sort(([a], [b]) => a.localeCompare(b)));\n}\n\nfunction matchesSearch<TMeta>(item: KeepItem<TMeta>, search?: KeepListQuery<TMeta>[\"search\"]): boolean {\n const query = search?.query;\n if (!query?.trim()) return true;\n const fields = search?.fields ?? [\"note\", \"meta\", \"tags\"];\n const values = fields.map((field) => {\n if (field === \"note\") return item.note ?? \"\";\n if (field === \"tags\") return (item.tags ?? []).join(\" \");\n try {\n return JSON.stringify(item.meta) ?? \"\";\n } catch {\n return String(item.meta);\n }\n });\n const text = values.join(\" \").toLocaleLowerCase();\n const normalized = query.trim().toLocaleLowerCase();\n const needles = search?.tokenize === false ? [normalized] : normalized.split(/\\s+/).filter(Boolean);\n const matches = needles.map((needle) => text.includes(needle));\n return search?.mode === \"or\" ? matches.some(Boolean) : matches.every(Boolean);\n}\n\nfunction toTimestamp(value: Date | number): number {\n return value instanceof Date ? value.getTime() : value;\n}\n","import { persistKeepItems, removeKeepItems } from \"../persistence/helpers\";\nimport type { KeepItem, KeepItemStatus, StorageAdapter } from \"./types\";\n\nexport type { KeepItemStatus } from \"./types\";\n\nexport type KeepItemRevalidationResult<TMeta = Record<string, unknown>> =\n | { status: \"available\"; meta?: TMeta }\n | { status: Exclude<KeepItemStatus, \"available\">; reason?: string };\n\nexport type KeepItemRevalidator<TMeta = Record<string, unknown>> = (\n item: KeepItem<TMeta>,\n) =>\n | KeepItemRevalidationResult<TMeta>\n | KeepItemRevalidationResult<TMeta>[\"status\"]\n | Promise<KeepItemRevalidationResult<TMeta> | KeepItemRevalidationResult<TMeta>[\"status\"]>;\n\nexport type KeepItemResolver<TMeta = Record<string, unknown>> = (\n item: KeepItem<TMeta>,\n result: KeepItemRevalidationResult<TMeta>,\n) => KeepItem<TMeta> | undefined | Promise<KeepItem<TMeta> | undefined>;\n\nexport type KeepItemMetadataRefresher<TMeta = Record<string, unknown>> = (\n item: KeepItem<TMeta>,\n) => TMeta | Promise<TMeta>;\n\n/** Return whether source metadata should be fetched again based on its age. */\nexport function isKeepItemMetadataStale<TMeta>(\n item: KeepItem<TMeta>,\n maxAgeMs: number,\n now: () => number = Date.now,\n): boolean {\n return item.metaUpdatedAt === undefined || now() - item.metaUpdatedAt >= maxAgeMs;\n}\n\nexport type KeepItemRevalidationRecord<TMeta = Record<string, unknown>> = {\n item: KeepItem<TMeta>;\n status: KeepItemStatus;\n reason?: string;\n updated: boolean;\n};\n\nexport type RevalidateKeepItemsOptions<TMeta = Record<string, unknown>> = {\n /** Statuses that should be removed after they are detected. Detection is the default. */\n removeStatuses?: Array<Exclude<KeepItemStatus, \"available\">>;\n now?: () => number;\n resolveItem?: KeepItemResolver<TMeta>;\n};\n\nexport type KeepAutoRevalidationOptions<TMeta = Record<string, unknown>> = {\n /** Revalidate after the provider hydrates. Defaults to true when validateItem is supplied. */\n onMount?: boolean;\n /** Revalidate when the browser returns online. Defaults to true. */\n onReconnect?: boolean;\n /** Revalidate repeatedly while mounted. Disabled by default. */\n intervalMs?: number;\n removeStatuses?: Array<Exclude<KeepItemStatus, \"available\">>;\n revalidator?: KeepItemRevalidator<TMeta>;\n};\n\nexport type KeepItemRevalidationSummary<TMeta = Record<string, unknown>> = {\n items: KeepItem<TMeta>[];\n checked: number;\n updated: number;\n removed: number;\n updatedItems: KeepItem<TMeta>[];\n removedIds: string[];\n results: KeepItemRevalidationRecord<TMeta>[];\n};\n\n/** Revalidate saved items without coupling the checker to a network client. */\nexport async function revalidateKeepItems<TMeta = Record<string, unknown>>(\n source: KeepItem<TMeta>[],\n revalidator: KeepItemRevalidator<TMeta>,\n options: RevalidateKeepItemsOptions<TMeta> = {},\n): Promise<KeepItemRevalidationSummary<TMeta>> {\n const removeStatuses = new Set(options.removeStatuses ?? []);\n const now = options.now ?? Date.now;\n const items: KeepItem<TMeta>[] = [];\n const updatedItems: KeepItem<TMeta>[] = [];\n const removedIds: string[] = [];\n const results: KeepItemRevalidationRecord<TMeta>[] = [];\n\n for (const item of source) {\n const rawResult = await revalidator(item);\n const result: KeepItemRevalidationResult<TMeta> = typeof rawResult === \"string\" ? { status: rawResult } : rawResult;\n const reason = result.status === \"available\" ? undefined : result.reason;\n const defaultResolved = {\n ...item,\n status: result.status,\n ...(result.status === \"available\" ? { statusReason: undefined } : { statusReason: reason }),\n };\n const resolved = options.resolveItem\n ? await (options.resolveItem as KeepItemResolver<TMeta>)(item, result)\n : defaultResolved;\n if (resolved === undefined) {\n removedIds.push(item.id);\n results.push({ item, status: result.status, reason, updated: false });\n continue;\n }\n if (result.status === \"available\") {\n const timestamp = now();\n const availableItem = clearItemStatus(resolved);\n const updated =\n result.meta === undefined\n ? availableItem\n : { ...availableItem, meta: result.meta, metaUpdatedAt: timestamp, updatedAt: timestamp };\n const didUpdate = updated !== item;\n items.push(updated);\n if (didUpdate) updatedItems.push(updated);\n results.push({ item: updated, status: \"available\", updated: didUpdate });\n continue;\n }\n\n const withStatus = { ...resolved, status: result.status, ...(reason ? { statusReason: reason } : {}) };\n const shouldRemove = removeStatuses.has(result.status);\n if (shouldRemove) removedIds.push(item.id);\n else items.push(withStatus);\n if (!shouldRemove && withStatus !== item) updatedItems.push(withStatus);\n results.push({ item: withStatus, status: result.status, reason, updated: !shouldRemove && withStatus !== item });\n }\n\n return {\n items,\n checked: source.length,\n updated: updatedItems.length,\n removed: removedIds.length,\n updatedItems,\n removedIds,\n results,\n };\n}\n\n/** Revalidate and persist saved items for framework-neutral applications. */\nexport async function reconcileKeepItems<TMeta = Record<string, unknown>>(\n storage: StorageAdapter<TMeta>,\n revalidator: KeepItemRevalidator<TMeta>,\n options: RevalidateKeepItemsOptions<TMeta> = {},\n): Promise<KeepItemRevalidationSummary<TMeta>> {\n const source = await storage.getAll();\n const summary = await revalidateKeepItems(source, revalidator, options);\n if (summary.updatedItems.length > 0) await persistKeepItems(storage, summary.updatedItems);\n if (summary.removedIds.length > 0) await removeKeepItems(storage, summary.removedIds);\n return summary;\n}\n\nfunction clearItemStatus<TMeta>(item: KeepItem<TMeta>): KeepItem<TMeta> {\n const next = { ...item };\n delete next.status;\n delete next.statusReason;\n return next;\n}\n","import type {\n KeepItemMetadataRefresher,\n KeepItemRevalidationSummary,\n KeepItemRevalidator,\n RevalidateKeepItemsOptions,\n} from \"../items/revalidation\";\nimport type { KeepChangeContext, KeepItem, KeepUndoState } from \"../items/types\";\n\nexport type KeepCollectionMeta = { name: string };\n\nexport type KeepStoreState<TMeta = Record<string, unknown>> = {\n items: KeepItem<TMeta>[];\n collections: Record<string, KeepCollectionMeta>;\n isLoading: boolean;\n isHydrated: boolean;\n isMutating: boolean;\n error: unknown | null;\n lastChange?: KeepChangeContext<TMeta>;\n undo?: KeepUndoState;\n};\n\nexport type KeepStoreActions<TMeta = Record<string, unknown>> = {\n saveItem: (item: KeepItem<TMeta>) => Promise<void>;\n recordOpen: (id: string, openedAt?: number) => Promise<void>;\n updateNote: (id: string, note?: string) => Promise<void>;\n updateTags: (id: string, tags?: string[]) => Promise<void>;\n toggleArchive: (id: string) => Promise<void>;\n archiveItem: (id: string) => Promise<void>;\n unarchiveItem: (id: string) => Promise<void>;\n togglePin: (id: string) => Promise<void>;\n moveToCollection: (id: string, collectionId?: string) => Promise<void>;\n archiveBatch: (ids: string[]) => Promise<void>;\n unarchiveBatch: (ids: string[]) => Promise<void>;\n pinBatch: (ids: string[]) => Promise<void>;\n unpinBatch: (ids: string[]) => Promise<void>;\n moveToCollectionBatch: (ids: string[], collectionId?: string) => Promise<void>;\n createCollection: (id: string, name: string) => Promise<void>;\n renameCollection: (id: string, name: string) => Promise<void>;\n removeCollection: (id: string) => Promise<void>;\n updateTagsBatch: (ids: string[], tags?: string[]) => Promise<void>;\n addTagsBatch: (ids: string[], tags: string[]) => Promise<void>;\n removeTagsBatch: (ids: string[], tags: string[]) => Promise<void>;\n removeItem: (id: string) => Promise<void>;\n removeItems: (ids: string[]) => Promise<void>;\n removeItemWithUndo: (id: string) => Promise<void>;\n removeItemsWithUndo: (ids: string[]) => Promise<void>;\n undoLastRemoval: () => Promise<void>;\n clear: () => Promise<void>;\n refresh: () => Promise<void>;\n refreshItemMetadata: (id: string, refresh: KeepItemMetadataRefresher<TMeta>) => Promise<void>;\n revalidateItems: (\n revalidator: KeepItemRevalidator<TMeta>,\n options?: RevalidateKeepItemsOptions<TMeta>,\n ) => Promise<KeepItemRevalidationSummary<TMeta>>;\n reorderItems: (orderedIds: string[]) => Promise<void>;\n moveItem: (id: string, targetIndex: number) => Promise<void>;\n};\n\nexport class KeepStore<TMeta = Record<string, unknown>> {\n private state: KeepStoreState<TMeta>;\n private readonly listeners = new Set<() => void>();\n\n constructor(initialState: KeepStoreState<TMeta>) {\n this.state = initialState;\n }\n\n getSnapshot = (): KeepStoreState<TMeta> => this.state;\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n setState(next: Partial<KeepStoreState<TMeta>>): void {\n let changed = false;\n for (const key of Object.keys(next) as Array<keyof KeepStoreState<TMeta>>) {\n if (!Object.is(this.state[key], next[key])) {\n changed = true;\n break;\n }\n }\n if (!changed) return;\n this.state = { ...this.state, ...next };\n for (const listener of this.listeners) listener();\n }\n}\n"],"mappings":"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","names":["item"]}
|