@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/dist/storage.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { a as StorageAdapter, R as RemoteSyncDriver, d as SyncQueueAdapter, u as KeepConflictResolver, S as SyncScope, e as KeepSyncQueueOperation, o as SyncCapableStorageAdapter, K as KeepCollectionDefinition, b as KeepCollectionMembership, I as KeepSyncState, c as KeepItem, H as KeepSyncResolution } from './types-SKIL2p2c.js';
2
- import { K as KeepScope } from './scope-BteyH-b9.js';
3
- export { S as ScopedStorageAdapter, a as ScopedSyncQueueAdapter, c as createScopedStorageAdapter } from './scope-BteyH-b9.js';
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
- private readonly scope?;
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
@@ -17,7 +17,7 @@ import {
17
17
  createBrowserStorageAdapter,
18
18
  createScopedStorageAdapter,
19
19
  createStorageAdapter
20
- } from "./chunk-NZLAW4LY.js";
20
+ } from "./chunk-SLH4DFYQ.js";
21
21
  export {
22
22
  DEFAULT_INDEXEDDB_DATABASE,
23
23
  DEFAULT_INDEXEDDB_STORE,
@@ -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-SKIL2p2c.js';
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 { createRediscoveryQuery as A, decodeKeepListQuery as B, encodeKeepListQuery as C, DEFAULT_KEEP_URL_PARAMS as D, exportItems as E, getKeepNavigationState as F, getTagCounts as G, importItems as H, type ImportItemsOptions as I, isKeepItemMetadataStale as J, type KeepListQuery as K, mergeKeepListQueryFromUrl as L, moveKeepItem as M, orderKeepItems as N, queryKeepItems as O, reconcileKeepItems as P, type QueryKeepItemsResult as Q, type RevalidateKeepItemsOptions as R, reorderKeepItems as S, revalidateKeepItems as T, serializeKeepListQuery as U, type ImportItemsResult as a, KEEP_BACKUP_FORMAT as b, KEEP_BACKUP_VERSION as c, type KeepAutoRevalidationOptions as d, type KeepBackup as e, KeepBackupImportError as f, KeepBackupParseError as g, type KeepBackupV1 as h, type KeepBackupV2 as i, type KeepCollectionMeta as j, type KeepItemMetadataRefresher as k, type KeepItemResolver as l, type KeepItemRevalidationRecord as m, type KeepItemRevalidationResult as n, type KeepItemRevalidationSummary as o, type KeepItemRevalidator as p, type KeepNavigationState as q, type KeepRediscoveryOptions as r, type KeepRediscoveryStrategy as s, KeepStore as t, type KeepStoreActions as u, type KeepStoreState as v, type KeepUrlParamNames as w, type KeepUrlState as x, type KeepUrlSyncOptions as y, createInboxQuery as z };
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 { KeepStorageAccessError as A, KeepStorageError as B, type KeepStorageOperation as C, KeepStorageParseError as D, KeepStorageQuotaError as E, type KeepSyncAuthStatus as F, type KeepSyncConflict as G, type KeepSyncResolution as H, type KeepSyncState as I, type KeepSyncStatus as J, type KeepCollectionDefinition as K, isKeepSyncAuthError as L, normalizeKeepTags as M, 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 SyncCapableStorageAdapter as o, type RemoteSyncResult as p, KeepSyncAuthError as q, type KeepAction as r, type KeepChangePhase as s, type KeepConflictContext as t, type KeepConflictResolver as u, type KeepErrorContext as v, type KeepErrorHandler as w, type KeepEventHandlers as x, type KeepItemInput as y, type KeepSchemaParseResult as z };
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@keepkit/core",
3
- "version": "0.28.5",
3
+ "version": "0.28.7",
4
4
  "description": "A flexible save-and-collect toolkit for React apps.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -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"]}