@keepkit/core 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -64
- package/dist/{chunk-J7NKIOXV.js → chunk-AWQWKK4V.js} +23 -14
- package/dist/chunk-AWQWKK4V.js.map +1 -0
- package/dist/{chunk-X4UVKTBK.js → chunk-DBRHZ6XU.js} +1 -1
- package/dist/chunk-DBRHZ6XU.js.map +1 -0
- package/dist/core.d.ts +3 -3
- package/dist/core.js +2 -2
- package/dist/react.d.ts +21 -26
- package/dist/react.js +50 -92
- package/dist/react.js.map +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +1 -1
- package/dist/{store-DyjKY0s4.d.ts → store-CqNh-2DS.d.ts} +15 -13
- package/dist/{types-BRfvVnCA.d.ts → types-BCziYE6E.d.ts} +8 -1
- package/package.json +1 -1
- package/dist/chunk-J7NKIOXV.js.map +0 -1
- package/dist/chunk-X4UVKTBK.js.map +0 -1
package/README.md
CHANGED
|
@@ -4,93 +4,67 @@
|
|
|
4
4
|
|
|
5
5
|
## 日本語
|
|
6
6
|
|
|
7
|
-
React
|
|
7
|
+
フレームワーク中立の保存・コレクションプリミティブとReactの低レベルbindingを提供します。通常のReactアプリケーションでは、より少ないコードで利用できる`@keepkit/ui`を推奨します。
|
|
8
8
|
|
|
9
9
|
```tsx
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { KeepButton, KeepProvider, useKeepItem, useKeepList } from "@keepkit/core/react";
|
|
11
|
+
import { createBrowserStorageAdapter } from "@keepkit/core/storage";
|
|
12
12
|
|
|
13
|
-
const storage =
|
|
13
|
+
const storage = createBrowserStorageAdapter({ key: "my-app:items" });
|
|
14
|
+
const article = { id: "article-123", targetType: "article", meta: { title: "Example", url: "/article" } };
|
|
14
15
|
|
|
15
16
|
<KeepProvider storage={storage}>
|
|
16
|
-
<KeepButton
|
|
17
|
-
item={{
|
|
18
|
-
id: "article-123",
|
|
19
|
-
targetType: "article",
|
|
20
|
-
meta: { title: "Example article", url: "/articles/123" },
|
|
21
|
-
}}
|
|
22
|
-
/>
|
|
17
|
+
<KeepButton item={article} />
|
|
23
18
|
</KeepProvider>;
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
`useKeepItem(id, payload)` では保存、切り替え、削除、ノート・タグ更新を行えます。`useKeepList()` ではコレクションの取得、タグ絞り込み・検索・ソート・ページネーション、`removeBatch` / `updateTagsBatch` / `addTagsBatch` / `removeTagsBatch` による一括操作ができます。`KeepProvider` は `isHydrated` / `isMutating` と typed storage errors を公開します。`LocalStorageAdapter` はSSR環境からimportでき、`StorageAdapter<TMeta>` または `createStorageAdapter` でサーバー側のストアに接続できます。
|
|
27
|
-
|
|
28
|
-
`exportItems(adapter)` / `importItems(adapter, json, { mode: "replace" | "merge" })` でversion付きJSONバックアップを扱えます。結果には `imported` / `failed` 件数が含まれます。
|
|
29
|
-
|
|
30
|
-
`KeepButton` の標準ARIAラベルは `savedAriaLabel` / `unsavedAriaLabel` または `getAriaLabel` で多言語化できます。`useKeepItem(id).refreshMetadata` と `isKeepItemMetadataStale` はメタデータの再取得に使えます。`useKeepList().revalidate` または `useKeepContext().revalidateItems` は削除・非公開・期限切れの対象を検出します。検出した状態を整理する場合は `removeStatuses` を明示してください。
|
|
31
19
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
push: (operation) => api.syncKeepOperation(operation),
|
|
39
|
-
},
|
|
40
|
-
resolveConflict: (local, remote) => ({
|
|
41
|
-
...remote,
|
|
42
|
-
note: local?.note ?? remote.note,
|
|
43
|
-
}),
|
|
20
|
+
const item = useKeepItem(article);
|
|
21
|
+
const list = useKeepList({
|
|
22
|
+
targetType: "article",
|
|
23
|
+
search: { query: "react" },
|
|
24
|
+
sort: { by: "updatedAt", direction: "desc" },
|
|
25
|
+
pagination: { page: 1, pageSize: 20 },
|
|
44
26
|
});
|
|
45
|
-
|
|
46
|
-
<KeepProvider
|
|
47
|
-
storage={storage}
|
|
48
|
-
schema={{ parse: (value) => validateMeta(value) }}
|
|
49
|
-
invalidItemPolicy="drop"
|
|
50
|
-
/>;
|
|
51
27
|
```
|
|
52
28
|
|
|
53
|
-
`
|
|
29
|
+
`KeepItemInput`は`id`、`meta`、`targetType`、`note`、`tags`だけを持つ最小入力です。保存時刻・更新時刻・タグ正規化は内部で処理されます。
|
|
30
|
+
|
|
31
|
+
`KeepListQuery`は`targetType`、`tags`、`search`、`sort`、`pagination`、`filter`、`savedBetween`で構成されます。`queryKeepItems`はReactなしで同じ条件を適用できます。
|
|
54
32
|
|
|
55
|
-
|
|
33
|
+
`@keepkit/core/core`はフレームワーク中立、`@keepkit/core/react`はReact、`@keepkit/core/storage`はlocalStorage、IndexedDB、fallback、同期adapter、`@keepkit/core/schema`はschema処理を公開します。パッケージルートにはexportがありません。
|
|
56
34
|
|
|
57
|
-
|
|
35
|
+
### 0.4.xからの変更
|
|
58
36
|
|
|
59
|
-
|
|
37
|
+
- `createKeepKit`は`Provider`、`Button`、`useContext`、`useItem`、`useList`、`useShortcut`を返します。
|
|
38
|
+
- `useKeepItem(id, payload)`は`useKeepItem(item)`に変わりました。
|
|
39
|
+
- `useKeepShortcut({ id, itemPayload })`は`useKeepShortcut({ item })`に変わりました。
|
|
40
|
+
- `KeepListOptions`は`KeepListQuery`に変わり、一覧条件は`search`、`sort`、`pagination`へ統一されました。
|
|
60
41
|
|
|
61
42
|
## English
|
|
62
43
|
|
|
63
|
-
|
|
44
|
+
`@keepkit/core` provides framework-neutral saved-collection primitives and low-level React bindings. For standard React applications, use `@keepkit/ui` for the shortest integration path.
|
|
64
45
|
|
|
65
46
|
```tsx
|
|
66
|
-
import {
|
|
67
|
-
import {
|
|
47
|
+
import { KeepButton, KeepProvider, useKeepItem, useKeepList } from "@keepkit/core/react";
|
|
48
|
+
import { createBrowserStorageAdapter } from "@keepkit/core/storage";
|
|
68
49
|
|
|
69
|
-
const storage =
|
|
50
|
+
const storage = createBrowserStorageAdapter({ key: "my-app:items" });
|
|
51
|
+
const article = { id: "article-123", targetType: "article", meta: { title: "Example", url: "/article" } };
|
|
70
52
|
|
|
71
53
|
<KeepProvider storage={storage}>
|
|
72
|
-
<KeepButton
|
|
73
|
-
item={{
|
|
74
|
-
id: "article-123",
|
|
75
|
-
targetType: "article",
|
|
76
|
-
meta: { title: "Example article", url: "/articles/123" },
|
|
77
|
-
}}
|
|
78
|
-
/>
|
|
54
|
+
<KeepButton item={article} />
|
|
79
55
|
</KeepProvider>;
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
Use `useKeepItem(id, payload)` for saving, toggling, removing, and updating notes or tags. Use `useKeepList()` to read, filter, sort, and perform bulk removal/tag updates. `KeepProvider` exposes `isHydrated`, `isMutating`, and typed storage errors. `LocalStorageAdapter` is safe to import in SSR environments; implement `StorageAdapter<TMeta>` or use `createStorageAdapter` to connect a server-backed store.
|
|
83
|
-
|
|
84
|
-
Use `exportItems(adapter)` and `importItems(adapter, json, { mode: "replace" | "merge" })` for versioned JSON backups. Results include imported and failed counts.
|
|
85
|
-
|
|
86
|
-
Localize the default `KeepButton` ARIA label with `savedAriaLabel` / `unsavedAriaLabel` or `getAriaLabel`. `useKeepItem(id).refreshMetadata` and `isKeepItemMetadataStale` fetch current metadata, while `useKeepList().revalidate` or `useKeepContext().revalidateItems` detects deleted, private, and expired targets. Pass `removeStatuses` explicitly when detected records should be cleaned up.
|
|
87
56
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
57
|
+
const item = useKeepItem(article);
|
|
58
|
+
const list = useKeepList({
|
|
59
|
+
targetType: "article",
|
|
60
|
+
search: { query: "react" },
|
|
61
|
+
sort: { by: "updatedAt", direction: "desc" },
|
|
62
|
+
pagination: { page: 1, pageSize: 20 },
|
|
63
|
+
});
|
|
64
|
+
```
|
|
91
65
|
|
|
92
|
-
|
|
66
|
+
`KeepItemInput` is a minimal input containing `id`, `meta`, `targetType`, `note`, and `tags`. KeepKit owns persistence timestamps and tag normalization. `KeepListQuery` uses the canonical `targetType`, `tags`, `search`, `sort`, `pagination`, `filter`, and `savedBetween` fields.
|
|
93
67
|
|
|
94
|
-
|
|
68
|
+
Use `@keepkit/core/core` for framework-neutral code, `@keepkit/core/react` for React bindings, `@keepkit/core/storage` for browser/fallback/sync adapters, and `@keepkit/core/schema` for schema validation. The package root has no export.
|
|
95
69
|
|
|
96
|
-
|
|
70
|
+
The v0.5 factory returns `Provider`, `Button`, `useContext`, `useItem`, `useList`, and `useShortcut`. Existing v0.4 applications should follow the migration guide in the repository root.
|
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
// src/query.ts
|
|
2
|
-
function queryKeepItems(source,
|
|
2
|
+
function queryKeepItems(source, query = {}) {
|
|
3
3
|
const filtered = source.filter((item) => {
|
|
4
|
-
const [from, to] =
|
|
4
|
+
const [from, to] = query.savedBetween ?? [];
|
|
5
5
|
const savedAt = item.savedAt;
|
|
6
6
|
const lowerBound = from === void 0 ? void 0 : toTimestamp(from);
|
|
7
7
|
const upperBound = to === void 0 ? void 0 : toTimestamp(to);
|
|
8
|
-
return (
|
|
8
|
+
return (query.targetType === void 0 || item.targetType === query.targetType) && (query.tags === void 0 || query.tags.every((tag) => item.tags?.includes(tag))) && (lowerBound === void 0 || savedAt >= lowerBound) && (upperBound === void 0 || savedAt <= upperBound) && matchesSearch(item, query.search) && (query.filter?.(item) ?? true);
|
|
9
9
|
});
|
|
10
10
|
const tagCounts = getTagCounts(filtered);
|
|
11
|
-
const sortBy =
|
|
12
|
-
const direction =
|
|
11
|
+
const sortBy = query.sort?.by;
|
|
12
|
+
const direction = query.sort?.direction === "asc" ? 1 : -1;
|
|
13
13
|
const sorted = sortBy ? [...filtered].sort((a, b) => (a[sortBy] - b[sortBy]) * direction) : filtered;
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
14
|
+
const pageSize = Math.max(1, query.pagination?.pageSize ?? (sorted.length || 1));
|
|
15
|
+
const pageCount = Math.max(1, Math.ceil(sorted.length / pageSize));
|
|
16
|
+
const page = Math.min(Math.max(1, query.pagination?.page ?? 1), pageCount);
|
|
17
|
+
const offset = (page - 1) * pageSize;
|
|
18
|
+
return {
|
|
19
|
+
items: sorted.slice(offset, offset + pageSize),
|
|
20
|
+
totalCount: sorted.length,
|
|
21
|
+
tagCounts,
|
|
22
|
+
page,
|
|
23
|
+
pageCount,
|
|
24
|
+
hasNextPage: page < pageCount,
|
|
25
|
+
hasPreviousPage: page > 1
|
|
26
|
+
};
|
|
17
27
|
}
|
|
18
28
|
function getTagCounts(items) {
|
|
19
29
|
const counts = {};
|
|
@@ -22,8 +32,8 @@ function getTagCounts(items) {
|
|
|
22
32
|
}
|
|
23
33
|
return Object.fromEntries(Object.entries(counts).sort(([a], [b]) => a.localeCompare(b)));
|
|
24
34
|
}
|
|
25
|
-
function matchesSearch(item,
|
|
26
|
-
const query = search?.query
|
|
35
|
+
function matchesSearch(item, search) {
|
|
36
|
+
const query = search?.query;
|
|
27
37
|
if (!query?.trim()) return true;
|
|
28
38
|
const fields = search?.fields ?? ["note", "meta", "tags"];
|
|
29
39
|
const values = fields.map((field) => {
|
|
@@ -36,11 +46,10 @@ function matchesSearch(item, searchQuery, search) {
|
|
|
36
46
|
}
|
|
37
47
|
});
|
|
38
48
|
const text = values.join(" ").toLocaleLowerCase();
|
|
39
|
-
if (!search) return text.includes(query.trim().toLocaleLowerCase());
|
|
40
49
|
const normalized = query.trim().toLocaleLowerCase();
|
|
41
|
-
const needles = search
|
|
50
|
+
const needles = search?.tokenize === false ? [normalized] : normalized.split(/\s+/).filter(Boolean);
|
|
42
51
|
const matches = needles.map((needle) => text.includes(needle));
|
|
43
|
-
return search
|
|
52
|
+
return search?.mode === "or" ? matches.some(Boolean) : matches.every(Boolean);
|
|
44
53
|
}
|
|
45
54
|
function toTimestamp(value) {
|
|
46
55
|
return value instanceof Date ? value.getTime() : value;
|
|
@@ -139,4 +148,4 @@ export {
|
|
|
139
148
|
reconcileKeepItems,
|
|
140
149
|
KeepStore
|
|
141
150
|
};
|
|
142
|
-
//# sourceMappingURL=chunk-
|
|
151
|
+
//# sourceMappingURL=chunk-AWQWKK4V.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/query.ts","../src/revalidation.ts","../src/store.ts"],"sourcesContent":["import type { KeepItem } from \"./types\";\n\nexport type KeepListQuery<TMeta = Record<string, unknown>> = {\n targetType?: string;\n tags?: string[];\n sort?: {\n by: \"savedAt\" | \"updatedAt\";\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\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 (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 sorted = sortBy ? [...filtered].sort((a, b) => (a[sortBy] - b[sortBy]) * direction) : filtered;\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\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 type { KeepItem, StorageAdapter } from \"./types\";\n\nexport type KeepItemStatus = \"available\" | \"deleted\" | \"private\" | \"expired\" | \"unknown\";\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 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 = {\n /** Statuses that should be removed after they are detected. Detection is the default. */\n removeStatuses?: Array<Exclude<KeepItemStatus, \"available\">>;\n now?: () => number;\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 = {},\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 if (result.status === \"available\") {\n const timestamp = now();\n const updated =\n result.meta === undefined\n ? item\n : { ...item, 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 shouldRemove = removeStatuses.has(result.status);\n if (shouldRemove) removedIds.push(item.id);\n else items.push(item);\n results.push({ item, status: result.status, reason: result.reason, updated: false });\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 = {},\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 persistItems(storage, summary.updatedItems);\n if (summary.removedIds.length > 0) await removeItems(storage, summary.removedIds);\n return summary;\n}\n\nasync function persistItems<TMeta>(storage: StorageAdapter<TMeta>, items: KeepItem<TMeta>[]): Promise<void> {\n if (storage.setMany) {\n await storage.setMany(items);\n return;\n }\n for (const item of items) await storage.set(item);\n}\n\nasync function removeItems<TMeta>(storage: StorageAdapter<TMeta>, ids: string[]): Promise<void> {\n if (storage.removeMany) {\n await storage.removeMany(ids);\n return;\n }\n for (const id of ids) await storage.remove(id);\n}\n","import type {\n KeepItemMetadataRefresher,\n KeepItemRevalidationSummary,\n KeepItemRevalidator,\n RevalidateKeepItemsOptions,\n} from \"./revalidation\";\nimport type { KeepChangeContext, KeepItem } from \"./types\";\n\nexport type KeepStoreState<TMeta = Record<string, unknown>> = {\n items: KeepItem<TMeta>[];\n isLoading: boolean;\n isHydrated: boolean;\n isMutating: boolean;\n error: unknown | null;\n lastChange?: KeepChangeContext<TMeta>;\n};\n\nexport type KeepStoreActions<TMeta = Record<string, unknown>> = {\n saveItem: (item: KeepItem<TMeta>) => Promise<void>;\n updateNote: (id: string, note?: string) => Promise<void>;\n updateTags: (id: string, tags?: 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 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,\n ) => Promise<KeepItemRevalidationSummary<TMeta>>;\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":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/storage/sync.ts","../src/storage/index.ts"],"sourcesContent":["export type KeepItem<TMeta = Record<string, unknown>> = {\n id: string;\n savedAt: number;\n updatedAt: number;\n meta: TMeta;\n targetType?: string;\n note?: string;\n tags?: string[];\n schemaVersion?: number;\n /** Optional server-provided revision used by synchronizing adapters. */\n revision?: string;\n /** Timestamp for the last successful refresh of source metadata. */\n metaUpdatedAt?: number;\n};\n\n/** The minimal item description accepted by save controls and hooks. */\nexport type KeepItemInput<TMeta = Record<string, unknown>> = {\n id: string;\n meta: TMeta;\n targetType?: string;\n note?: string;\n tags?: string[];\n};\n\nexport interface StorageAdapter<TMeta = Record<string, unknown>> {\n getAll(): Promise<KeepItem<TMeta>[]>;\n set(item: KeepItem<TMeta>): Promise<void>;\n setMany?(items: KeepItem<TMeta>[]): Promise<void>;\n remove(id: string): Promise<void>;\n removeMany?(ids: string[]): Promise<void>;\n clear(): Promise<void>;\n merge?(localItems: KeepItem<TMeta>[]): Promise<KeepItem<TMeta>[]>;\n subscribe?(listener: () => void): () => void;\n readonly storageKey?: string;\n}\n\nexport type KeepAction =\n | \"refresh\"\n | \"save\"\n | \"updateNote\"\n | \"updateTags\"\n | \"updateTagsBatch\"\n | \"revalidate\"\n | \"remove\"\n | \"removeBatch\"\n | \"clear\";\n\nexport type KeepChangePhase = \"local\" | \"synced\";\n\nexport type KeepChangeContext<TMeta = Record<string, unknown>> = {\n action: KeepAction;\n id?: string;\n item?: KeepItem<TMeta>;\n items?: KeepItem<TMeta>[];\n phase: KeepChangePhase;\n};\n\nexport type KeepPluginContext<TMeta = Record<string, unknown>> = {\n action: KeepAction;\n id?: string;\n item?: KeepItem<TMeta>;\n items?: KeepItem<TMeta>[];\n};\n\nexport type KeepPlugin<TMeta = Record<string, unknown>> = {\n name?: string;\n before?: (context: KeepPluginContext<TMeta>) => void | Promise<void>;\n after?: (context: KeepPluginContext<TMeta>) => void | Promise<void>;\n onError?: (error: unknown, context: KeepErrorContext) => void;\n};\n\nexport type KeepSchemaParseResult<T> = { success: true; data: T } | { success: false; error?: unknown };\n\nexport type KeepSchema<T> =\n | { parse: (value: unknown) => T | Promise<T> }\n | { safeParse: (value: unknown) => KeepSchemaParseResult<T> | Promise<KeepSchemaParseResult<T>> }\n | {\n \"~standard\": {\n validate: (\n value: unknown,\n ) => { value?: T; issues?: readonly unknown[] } | Promise<{ value?: T; issues?: readonly unknown[] }>;\n };\n };\n\nexport type KeepInvalidItemPolicy = \"error\" | \"drop\";\n\nexport type KeepSyncStatus = \"idle\" | \"pending\" | \"syncing\" | \"synced\" | \"conflict\" | \"error\";\n\nexport type KeepSyncState = {\n status: KeepSyncStatus;\n pendingCount: number;\n conflictIds: string[];\n lastSyncedAt?: number;\n error?: unknown;\n};\n\nexport type SyncOperation<TMeta = Record<string, unknown>> = {\n operationId: string;\n type: \"upsert\" | \"remove\";\n id: string;\n item?: KeepItem<TMeta>;\n createdAt: number;\n baseRevision?: string;\n};\n\nexport type RemoteSyncResult<TMeta = Record<string, unknown>> =\n | { type: \"synced\"; item?: KeepItem<TMeta>; revision?: string }\n | { type: \"conflict\"; remote: KeepItem<TMeta>; revision?: string };\n\nexport type KeepConflictContext<TMeta = Record<string, unknown>> = {\n operation: SyncOperation<TMeta>;\n remoteRevision?: string;\n};\n\nexport type KeepConflictResolver<TMeta = Record<string, unknown>> = (\n local: KeepItem<TMeta> | undefined,\n remote: KeepItem<TMeta>,\n context: KeepConflictContext<TMeta>,\n) => KeepItem<TMeta> | undefined | Promise<KeepItem<TMeta> | undefined>;\n\nexport interface RemoteSyncDriver<TMeta = Record<string, unknown>> {\n push(operation: SyncOperation<TMeta>): Promise<RemoteSyncResult<TMeta>>;\n pull?: () => Promise<KeepItem<TMeta>[]>;\n}\n\nexport interface SyncQueueAdapter<TMeta = Record<string, unknown>> {\n getAll(): Promise<SyncOperation<TMeta>[]>;\n setMany(operations: SyncOperation<TMeta>[]): Promise<void>;\n remove(operationIds: string[]): Promise<void>;\n clear(): Promise<void>;\n}\n\nexport interface SyncCapableStorageAdapter<TMeta = Record<string, unknown>> extends StorageAdapter<TMeta> {\n getSyncState(): KeepSyncState;\n subscribeSync(listener: () => void): () => void;\n flushSync(): Promise<void>;\n dispose?(): void;\n}\n\nexport type KeepStorageOperation = \"getAll\" | \"set\" | \"remove\" | \"clear\" | \"merge\";\n\nexport class KeepStorageError extends Error {\n readonly operation: KeepStorageOperation;\n readonly storageKey?: string;\n readonly cause?: unknown;\n\n constructor(\n message: string,\n options: {\n operation: KeepStorageOperation;\n storageKey?: string;\n cause?: unknown;\n },\n ) {\n super(message);\n this.name = \"KeepStorageError\";\n this.operation = options.operation;\n this.storageKey = options.storageKey;\n if (options.cause !== undefined) this.cause = options.cause;\n }\n}\n\nexport class KeepStorageQuotaError extends KeepStorageError {\n constructor(options: { operation: KeepStorageOperation; storageKey?: string; cause?: unknown }) {\n super(\"KeepKit storage quota was exceeded.\", options);\n this.name = \"KeepStorageQuotaError\";\n }\n}\n\nexport class KeepStorageAccessError extends KeepStorageError {\n constructor(options: { operation: KeepStorageOperation; storageKey?: string; cause?: unknown }) {\n super(\"KeepKit could not access the configured storage.\", options);\n this.name = \"KeepStorageAccessError\";\n }\n}\n\nexport class KeepStorageParseError extends KeepStorageError {\n constructor(options: { operation: KeepStorageOperation; storageKey?: string; cause?: unknown }) {\n super(\"KeepKit found invalid data in the configured storage.\", options);\n this.name = \"KeepStorageParseError\";\n }\n}\n\nexport type KeepErrorContext = {\n action: KeepAction;\n id?: string;\n};\n\nexport type KeepErrorHandler = (error: unknown, context: KeepErrorContext) => void;\n\nexport type KeepEventHandlers<TMeta = Record<string, unknown>> = {\n onSave?: (item: KeepItem<TMeta>) => void;\n onRemove?: (item: KeepItem<TMeta>) => void;\n onNoteUpdate?: (id: string, note?: string) => void;\n onTagsUpdate?: (id: string, tags?: string[]) => void;\n onChange?: (context: KeepChangeContext<TMeta>) => void | Promise<void>;\n onError?: KeepErrorHandler;\n};\n\nexport function normalizeKeepTags(tags?: string[]): string[] | undefined {\n if (!tags) return undefined;\n const normalized = [...new Set(tags.map((tag) => tag.trim()).filter(Boolean))];\n return normalized.length > 0 ? normalized : undefined;\n}\n","import type {\n KeepConflictResolver,\n KeepItem,\n KeepSyncState,\n RemoteSyncDriver,\n StorageAdapter,\n SyncCapableStorageAdapter,\n SyncOperation,\n SyncQueueAdapter,\n} from \"../types\";\n\nexport type LocalStorageSyncQueueOptions = {\n key?: string;\n storage?: Storage;\n};\n\nexport type IndexedDBSyncQueueOptions = {\n databaseName?: string;\n storeName?: string;\n version?: number;\n indexedDB?: IDBFactory;\n};\n\nexport type FallbackSyncQueueAdapterOptions<TMeta = Record<string, unknown>> = {\n primary: SyncQueueAdapter<TMeta>;\n fallback: SyncQueueAdapter<TMeta>;\n shouldFallback?: (error: unknown) => boolean;\n};\n\nexport type SyncStorageAdapterOptions<TMeta = Record<string, unknown>> = {\n local: StorageAdapter<TMeta>;\n remote: RemoteSyncDriver<TMeta>;\n queue?: SyncQueueAdapter<TMeta>;\n queueKey?: string;\n queueDatabaseName?: string;\n clientId?: string;\n now?: () => number;\n resolveConflict?: KeepConflictResolver<TMeta>;\n};\n\nexport const DEFAULT_SYNC_QUEUE_KEY = \"keepkit:sync-queue\";\nexport const DEFAULT_SYNC_QUEUE_DATABASE = \"keepkit-sync\";\nexport const DEFAULT_SYNC_QUEUE_STORE = \"sync-queue\";\n\nexport class LocalStorageSyncQueueAdapter<TMeta = Record<string, unknown>> implements SyncQueueAdapter<TMeta> {\n private readonly key: string;\n private readonly storage: Storage | undefined;\n\n constructor(options: LocalStorageSyncQueueOptions = {}) {\n this.key = options.key ?? DEFAULT_SYNC_QUEUE_KEY;\n this.storage = options.storage ?? getBrowserStorage();\n }\n\n async getAll(): Promise<SyncOperation<TMeta>[]> {\n if (!this.storage) return [];\n const raw = this.storage.getItem(this.key);\n if (!raw) return [];\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch (cause) {\n throw Object.assign(new Error(\"KeepKit sync queue contains invalid JSON.\"), { cause });\n }\n if (!Array.isArray(value) || !value.every(isSyncOperation)) {\n throw new Error(\"KeepKit sync queue contains invalid operations.\");\n }\n return value as SyncOperation<TMeta>[];\n }\n\n async setMany(operations: SyncOperation<TMeta>[]): Promise<void> {\n if (!this.storage) return;\n this.storage.setItem(this.key, JSON.stringify(operations));\n }\n\n async remove(operationIds: string[]): Promise<void> {\n const ids = new Set(operationIds);\n const current = await this.getAll();\n await this.setMany(current.filter((operation) => !ids.has(operation.operationId)));\n }\n\n async clear(): Promise<void> {\n this.storage?.removeItem(this.key);\n }\n}\n\nexport class IndexedDBSyncQueueAdapter<TMeta = Record<string, unknown>> implements SyncQueueAdapter<TMeta> {\n private readonly databaseName: string;\n private readonly storeName: string;\n private readonly version: number;\n private readonly indexedDB: IDBFactory | undefined;\n private databasePromise: Promise<IDBDatabase | undefined> | undefined;\n\n constructor(options: IndexedDBSyncQueueOptions = {}) {\n this.databaseName = options.databaseName ?? DEFAULT_SYNC_QUEUE_DATABASE;\n this.storeName = options.storeName ?? DEFAULT_SYNC_QUEUE_STORE;\n this.version = options.version ?? 1;\n this.indexedDB = options.indexedDB ?? getBrowserIndexedDB();\n }\n\n async getAll(): Promise<SyncOperation<TMeta>[]> {\n const database = await this.open();\n if (!database) return [];\n const transaction = database.transaction(this.storeName, \"readonly\");\n const value: unknown = await requestToPromise(transaction.objectStore(this.storeName).getAll());\n if (!Array.isArray(value) || !value.every(isSyncOperation)) {\n throw new Error(\"KeepKit sync queue contains invalid operations.\");\n }\n return value as SyncOperation<TMeta>[];\n }\n\n async setMany(operations: SyncOperation<TMeta>[]): Promise<void> {\n const database = await this.open();\n if (!database) return;\n const transaction = database.transaction(this.storeName, \"readwrite\");\n const store = transaction.objectStore(this.storeName);\n for (const operation of operations) store.put(operation);\n await transactionToPromise(transaction);\n }\n\n async remove(operationIds: string[]): Promise<void> {\n const database = await this.open();\n if (!database) return;\n const transaction = database.transaction(this.storeName, \"readwrite\");\n const store = transaction.objectStore(this.storeName);\n for (const operationId of new Set(operationIds)) store.delete(operationId);\n await transactionToPromise(transaction);\n }\n\n async clear(): Promise<void> {\n const database = await this.open();\n if (!database) return;\n const transaction = database.transaction(this.storeName, \"readwrite\");\n transaction.objectStore(this.storeName).clear();\n await transactionToPromise(transaction);\n }\n\n private open(): Promise<IDBDatabase | undefined> {\n if (!this.indexedDB) return Promise.resolve(undefined);\n if (!this.databasePromise) {\n this.databasePromise = new Promise((resolve, reject) => {\n let request: IDBOpenDBRequest;\n try {\n request = this.indexedDB?.open(this.databaseName, this.version) as IDBOpenDBRequest;\n } catch (cause) {\n reject(cause);\n return;\n }\n request.onupgradeneeded = () => {\n if (!request.result.objectStoreNames.contains(this.storeName)) {\n request.result.createObjectStore(this.storeName, { keyPath: \"operationId\" });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n request.onblocked = () => reject(request.error ?? new Error(\"IndexedDB open was blocked.\"));\n });\n }\n return this.databasePromise.catch((cause) => {\n this.databasePromise = undefined;\n throw cause;\n });\n }\n}\n\n/** Keeps the durable sync queue available when IndexedDB is blocked or fails. */\nexport class FallbackSyncQueueAdapter<TMeta = Record<string, unknown>> implements SyncQueueAdapter<TMeta> {\n private readonly primary: SyncQueueAdapter<TMeta>;\n private readonly fallback: SyncQueueAdapter<TMeta>;\n private readonly shouldFallback: (error: unknown) => boolean;\n private active: \"primary\" | \"fallback\" = \"primary\";\n\n constructor(options: FallbackSyncQueueAdapterOptions<TMeta>) {\n this.primary = options.primary;\n this.fallback = options.fallback;\n this.shouldFallback = options.shouldFallback ?? (() => true);\n }\n\n get isUsingFallback(): boolean {\n return this.active === \"fallback\";\n }\n\n getAll(): Promise<SyncOperation<TMeta>[]> {\n return this.execute((adapter) => adapter.getAll());\n }\n\n setMany(operations: SyncOperation<TMeta>[]): Promise<void> {\n return this.execute((adapter) => adapter.setMany(operations));\n }\n\n remove(operationIds: string[]): Promise<void> {\n return this.execute((adapter) => adapter.remove(operationIds));\n }\n\n clear(): Promise<void> {\n return this.execute((adapter) => adapter.clear());\n }\n\n private async execute<TResult>(operation: (adapter: SyncQueueAdapter<TMeta>) => Promise<TResult>): Promise<TResult> {\n const adapter = this.active === \"primary\" ? this.primary : this.fallback;\n try {\n return await operation(adapter);\n } catch (error) {\n if (this.active !== \"primary\" || !this.shouldFallback(error)) throw error;\n this.active = \"fallback\";\n return operation(this.fallback);\n }\n }\n}\n\n/** A local-first adapter that persists remote operations until they are acknowledged. */\nexport class SyncStorageAdapter<TMeta = Record<string, unknown>> implements SyncCapableStorageAdapter<TMeta> {\n readonly storageKey?: string;\n private readonly local: StorageAdapter<TMeta>;\n private readonly remote: RemoteSyncDriver<TMeta>;\n private readonly queue: SyncQueueAdapter<TMeta>;\n private readonly clientId: string;\n private readonly now: () => number;\n private readonly resolveConflict?: KeepConflictResolver<TMeta>;\n private readonly listeners = new Set<() => void>();\n private readonly dataListeners = new Set<() => void>();\n private queueItems: SyncOperation<TMeta>[] = [];\n private queueLoaded = false;\n private queueLoadPromise: Promise<void> | undefined;\n private flushPromise: Promise<void> | undefined;\n private state: KeepSyncState = { status: \"idle\", pendingCount: 0, conflictIds: [] };\n private onlineHandler?: () => void;\n\n constructor(options: SyncStorageAdapterOptions<TMeta>) {\n this.local = options.local;\n this.remote = options.remote;\n this.queue = options.queue ?? createDefaultQueue<TMeta>(options);\n this.clientId = options.clientId ?? createId();\n this.now = options.now ?? Date.now;\n this.resolveConflict = options.resolveConflict;\n this.storageKey = this.local.storageKey;\n if (typeof window !== \"undefined\") {\n this.onlineHandler = () => void this.flushSync();\n window.addEventListener(\"online\", this.onlineHandler);\n }\n void this.resumeQueue();\n }\n\n getSyncState = (): KeepSyncState => this.state;\n\n subscribeSync = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n subscribe = (listener: () => void): (() => void) => {\n this.dataListeners.add(listener);\n const unsubscribeLocal = this.local.subscribe?.(listener) ?? (() => undefined);\n return () => {\n this.dataListeners.delete(listener);\n unsubscribeLocal();\n };\n };\n\n getAll(): Promise<KeepItem<TMeta>[]> {\n return this.local.getAll();\n }\n\n async set(item: KeepItem<TMeta>): Promise<void> {\n const operation = this.createOperation(\"upsert\", item.id, item);\n await this.enqueueBeforeLocalWrite(operation);\n try {\n await this.local.set(item);\n } catch (cause) {\n await this.removeQueued(operation.operationId);\n throw cause;\n }\n this.notifyDataListeners();\n this.setPendingState();\n }\n\n async setMany(items: KeepItem<TMeta>[]): Promise<void> {\n const operations = items.map((item) => this.createOperation(\"upsert\", item.id, item));\n await this.enqueueManyBeforeLocalWrite(operations);\n try {\n if (this.local.setMany) await this.local.setMany(items);\n else for (const item of items) await this.local.set(item);\n } catch (cause) {\n await this.removeQueued(operations.map((operation) => operation.operationId));\n throw cause;\n }\n this.notifyDataListeners();\n this.setPendingState();\n }\n\n async remove(id: string): Promise<void> {\n const operation = this.createOperation(\"remove\", id);\n await this.enqueueBeforeLocalWrite(operation);\n try {\n await this.local.remove(id);\n } catch (cause) {\n await this.removeQueued(operation.operationId);\n throw cause;\n }\n this.notifyDataListeners();\n this.setPendingState();\n }\n\n async removeMany(ids: string[]): Promise<void> {\n const operations = [...new Set(ids)].map((id) => this.createOperation(\"remove\", id));\n await this.enqueueManyBeforeLocalWrite(operations);\n try {\n if (this.local.removeMany) await this.local.removeMany(ids);\n else for (const id of ids) await this.local.remove(id);\n } catch (cause) {\n await this.removeQueued(operations.map((operation) => operation.operationId));\n throw cause;\n }\n this.notifyDataListeners();\n this.setPendingState();\n }\n\n async clear(): Promise<void> {\n const items = await this.local.getAll();\n await this.removeMany(items.map((item) => item.id));\n await this.local.clear();\n }\n\n async merge(localItems: KeepItem<TMeta>[]): Promise<KeepItem<TMeta>[]> {\n const merged = this.local.merge\n ? await this.local.merge(localItems)\n : await mergeLocalItems(localItems, this.local);\n await this.setMany(localItems);\n return merged;\n }\n\n async flushSync(): Promise<void> {\n if (this.flushPromise) return this.flushPromise;\n this.flushPromise = this.runFlush().finally(() => {\n this.flushPromise = undefined;\n });\n return this.flushPromise;\n }\n\n dispose(): void {\n if (this.onlineHandler) window.removeEventListener(\"online\", this.onlineHandler);\n this.listeners.clear();\n this.dataListeners.clear();\n }\n\n private async runFlush(): Promise<void> {\n await this.loadQueue();\n if (!(await this.pullRemote())) return;\n if (this.queueItems.length === 0) {\n this.updateState({ status: \"synced\", pendingCount: 0, error: undefined });\n return;\n }\n this.updateState({ status: \"syncing\", error: undefined });\n for (const operation of [...this.queueItems]) {\n try {\n const result = await this.remote.push(operation);\n if (result.type === \"conflict\") {\n const local = operation.item;\n const resolved = this.resolveConflict\n ? await this.resolveConflict(local, result.remote, {\n operation,\n remoteRevision: result.revision,\n })\n : undefined;\n if (!resolved) {\n this.updateState({\n status: \"conflict\",\n conflictIds: [...new Set([...this.state.conflictIds, operation.id])],\n });\n continue;\n }\n const retry = this.createOperation(\"upsert\", resolved.id, {\n ...resolved,\n revision: result.revision ?? resolved.revision,\n });\n await this.local.set(retry.item as KeepItem<TMeta>);\n await this.replaceQueued(operation, retry);\n continue;\n }\n if (result.item) {\n await this.local.set({\n ...result.item,\n ...(result.revision ? { revision: result.revision } : {}),\n });\n this.notifyDataListeners();\n }\n await this.removeQueued(operation.operationId);\n this.updateState({\n status: this.queueItems.length > 0 ? \"syncing\" : \"synced\",\n lastSyncedAt: this.now(),\n conflictIds: this.state.conflictIds.filter((id) => id !== operation.id),\n });\n } catch (error) {\n this.updateState({ status: \"error\", error });\n return;\n }\n }\n if (this.queueItems.length === 0) this.updateState({ status: \"synced\", pendingCount: 0 });\n }\n\n private createOperation(\n type: SyncOperation<TMeta>[\"type\"],\n id: string,\n item?: KeepItem<TMeta>,\n ): SyncOperation<TMeta> {\n return {\n operationId: `${this.clientId}:${this.now()}:${createId()}`,\n type,\n id,\n ...(item ? { item } : {}),\n createdAt: this.now(),\n ...(item?.revision ? { baseRevision: item.revision } : {}),\n };\n }\n\n private async enqueueBeforeLocalWrite(operation: SyncOperation<TMeta>): Promise<void> {\n await this.enqueueManyBeforeLocalWrite([operation]);\n }\n\n private async enqueueManyBeforeLocalWrite(operations: SyncOperation<TMeta>[]): Promise<void> {\n await this.loadQueue();\n const next = [...this.queueItems];\n for (const operation of operations) {\n for (let index = next.length - 1; index >= 0; index -= 1) {\n if (next[index]?.id !== operation.id) continue;\n next.splice(index, 1);\n }\n next.push(operation);\n }\n await this.persistQueue(next);\n this.updateState({ status: \"pending\", pendingCount: this.queueItems.length });\n }\n\n private async loadQueue(): Promise<void> {\n if (this.queueLoaded) return;\n if (!this.queueLoadPromise) {\n this.queueLoadPromise = this.queue\n .getAll()\n .then((items) => {\n this.queueItems = items;\n this.queueLoaded = true;\n })\n .catch((error) => {\n this.queueLoadPromise = undefined;\n throw error;\n });\n }\n await this.queueLoadPromise;\n }\n\n private async resumeQueue(): Promise<void> {\n try {\n await this.loadQueue();\n if (this.queueItems.length === 0) return;\n this.updateState({ status: \"pending\", pendingCount: this.queueItems.length });\n if (isBrowserOnline()) await this.flushSync();\n } catch (error) {\n this.updateState({ status: \"error\", error });\n }\n }\n\n private async persistQueue(next: SyncOperation<TMeta>[]): Promise<void> {\n const previousIds = new Set(this.queueItems.map((operation) => operation.operationId));\n const nextIds = new Set(next.map((operation) => operation.operationId));\n const removed = [...previousIds].filter((id) => !nextIds.has(id));\n if (removed.length > 0) await this.queue.remove(removed);\n if (next.length > 0) await this.queue.setMany(next);\n this.queueItems = next;\n }\n\n private async removeQueued(operationIds: string | string[]): Promise<void> {\n await this.loadQueue();\n const ids = new Set(typeof operationIds === \"string\" ? [operationIds] : operationIds);\n await this.queue.remove([...ids]);\n this.queueItems = this.queueItems.filter((operation) => !ids.has(operation.operationId));\n this.setPendingState();\n }\n\n private async replaceQueued(previous: SyncOperation<TMeta>, next: SyncOperation<TMeta>): Promise<void> {\n await this.persistQueue(\n this.queueItems.map((operation) => (operation.operationId === previous.operationId ? next : operation)),\n );\n this.setPendingState();\n }\n\n private setPendingState(): void {\n this.updateState({\n status: this.queueItems.length > 0 ? \"pending\" : \"synced\",\n pendingCount: this.queueItems.length,\n });\n }\n\n private async pullRemote(): Promise<boolean> {\n if (!this.remote.pull) return true;\n try {\n const remoteItems = await this.remote.pull();\n const pendingIds = new Set(this.queueItems.map((operation) => operation.id));\n const localItems = await this.local.getAll();\n const localById = new Map(localItems.map((item) => [item.id, item]));\n const incoming = remoteItems.filter((item) => {\n const current = localById.get(item.id);\n return !pendingIds.has(item.id) && (!current || item.updatedAt >= current.updatedAt);\n });\n if (incoming.length === 0) return true;\n if (this.local.setMany) await this.local.setMany(incoming);\n else for (const item of incoming) await this.local.set(item);\n this.notifyDataListeners();\n return true;\n } catch (error) {\n this.updateState({ status: \"error\", error });\n return false;\n }\n }\n\n private notifyDataListeners(): void {\n for (const listener of this.dataListeners) listener();\n }\n\n private updateState(next: Partial<KeepSyncState>): void {\n this.state = {\n ...this.state,\n ...next,\n pendingCount: next.pendingCount ?? this.queueItems.length,\n };\n for (const listener of this.listeners) listener();\n }\n}\n\nasync function mergeLocalItems<TMeta>(\n localItems: KeepItem<TMeta>[],\n target: StorageAdapter<TMeta>,\n): Promise<KeepItem<TMeta>[]> {\n const remoteItems = await target.getAll();\n const byId = new Map(remoteItems.map((item) => [item.id, item]));\n for (const item of localItems) {\n const current = byId.get(item.id);\n if (!current || item.updatedAt > current.updatedAt) byId.set(item.id, item);\n }\n const merged = [...byId.values()].sort((a, b) => b.updatedAt - a.updatedAt);\n if (target.setMany) await target.setMany(merged);\n else for (const item of merged) await target.set(item);\n return merged;\n}\n\nfunction isSyncOperation(value: unknown): value is SyncOperation {\n if (!isRecord(value)) return false;\n return (\n typeof value.operationId === \"string\" &&\n (value.type === \"upsert\" || value.type === \"remove\") &&\n typeof value.id === \"string\" &&\n typeof value.createdAt === \"number\"\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction createId(): string {\n if (typeof crypto !== \"undefined\" && \"randomUUID\" in crypto) return crypto.randomUUID();\n return Math.random().toString(36).slice(2);\n}\n\nfunction getBrowserStorage(): Storage | undefined {\n if (typeof window === \"undefined\") return undefined;\n try {\n return window.localStorage;\n } catch {\n return undefined;\n }\n}\n\nfunction getBrowserIndexedDB(): IDBFactory | undefined {\n if (typeof indexedDB === \"undefined\") return undefined;\n return indexedDB;\n}\n\nfunction isBrowserOnline(): boolean {\n return typeof navigator === \"undefined\" || navigator.onLine !== false;\n}\n\nfunction createDefaultQueue<TMeta>(options: SyncStorageAdapterOptions<TMeta>): SyncQueueAdapter<TMeta> {\n const queueKey = options.queueKey ?? `${DEFAULT_SYNC_QUEUE_KEY}:${options.local.storageKey ?? \"default\"}`;\n const fallback = new LocalStorageSyncQueueAdapter<TMeta>({ key: queueKey });\n const indexedDB = getBrowserIndexedDB();\n if (!indexedDB) return fallback;\n return new FallbackSyncQueueAdapter<TMeta>({\n primary: new IndexedDBSyncQueueAdapter<TMeta>({\n databaseName: options.queueDatabaseName,\n indexedDB,\n }),\n fallback,\n });\n}\n\nfunction requestToPromise<T>(request: IDBRequest<T>): Promise<T> {\n return new Promise((resolve, reject) => {\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nfunction transactionToPromise(transaction: IDBTransaction): Promise<void> {\n return new Promise((resolve, reject) => {\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => reject(transaction.error);\n transaction.onabort = () => reject(transaction.error ?? new Error(\"IndexedDB transaction aborted.\"));\n });\n}\n","import {\n type KeepItem,\n KeepStorageAccessError,\n KeepStorageError,\n type KeepStorageOperation,\n KeepStorageParseError,\n KeepStorageQuotaError,\n type StorageAdapter,\n} from \"../types\";\n\nexport const DEFAULT_STORAGE_KEY = \"keepkit:items\";\n\nexport type LocalStorageAdapterOptions = {\n key?: string;\n storage?: Storage;\n};\n\nexport type IndexedDBAdapterOptions = {\n databaseName?: string;\n dbName?: string;\n /** Alias for databaseName, useful when switching from LocalStorageAdapter. */\n key?: string;\n storeName?: string;\n version?: number;\n indexedDB?: IDBFactory;\n};\n\nexport const DEFAULT_INDEXEDDB_DATABASE = \"keepkit\";\nexport const DEFAULT_INDEXEDDB_STORE = \"items\";\n\nexport type StorageAdapterFactoryOptions<TMeta = Record<string, unknown>> = {\n getAll: () => KeepItem<TMeta>[] | Promise<KeepItem<TMeta>[]>;\n set: (item: KeepItem<TMeta>) => void | Promise<void>;\n setMany?: (items: KeepItem<TMeta>[]) => void | Promise<void>;\n remove: (id: string) => void | Promise<void>;\n removeMany?: (ids: string[]) => void | Promise<void>;\n clear: () => void | Promise<void>;\n merge?: (localItems: KeepItem<TMeta>[]) => KeepItem<TMeta>[] | Promise<KeepItem<TMeta>[]>;\n subscribe?: (listener: () => void) => undefined | (() => void);\n storageKey?: string;\n};\n\nexport type FallbackStorageAdapterOptions<TMeta = Record<string, unknown>> = {\n primary: StorageAdapter<TMeta>;\n fallback: StorageAdapter<TMeta>;\n /** Decide which primary adapter failures should activate the fallback. */\n shouldFallback?: (error: unknown) => boolean;\n onFallback?: (error: unknown) => void;\n /** Copy fallback data into an empty primary on the first read. */\n migrateFallbackOnEmpty?: boolean;\n /** Keep the fallback current while the primary is healthy. */\n mirrorWrites?: boolean;\n};\n\n/**\n * A storage adapter that switches to a fallback after an availability failure.\n * Parse errors remain visible so corrupt data is never silently hidden.\n */\nexport class FallbackStorageAdapter<TMeta = Record<string, unknown>> implements StorageAdapter<TMeta> {\n public readonly storageKey: string | undefined;\n private readonly primary: StorageAdapter<TMeta>;\n private readonly fallback: StorageAdapter<TMeta>;\n private readonly shouldFallback: (error: unknown) => boolean;\n private readonly onFallback?: (error: unknown) => void;\n private readonly migrateFallbackOnEmpty: boolean;\n private readonly mirrorWrites: boolean;\n private active: \"primary\" | \"fallback\" = \"primary\";\n private readonly listeners = new Set<() => void>();\n\n constructor(options: FallbackStorageAdapterOptions<TMeta>) {\n this.primary = options.primary;\n this.fallback = options.fallback;\n this.shouldFallback = options.shouldFallback ?? isRecoverableStorageError;\n this.onFallback = options.onFallback;\n this.migrateFallbackOnEmpty = options.migrateFallbackOnEmpty ?? false;\n this.mirrorWrites = options.mirrorWrites ?? false;\n this.storageKey = options.fallback.storageKey ?? options.primary.storageKey;\n }\n\n get isUsingFallback(): boolean {\n return this.active === \"fallback\";\n }\n\n getAll(): Promise<KeepItem<TMeta>[]> {\n return this.readAll();\n }\n\n set(item: KeepItem<TMeta>): Promise<void> {\n return this.executeWrite((adapter) => adapter.set(item));\n }\n\n setMany(items: KeepItem<TMeta>[]): Promise<void> {\n return this.executeWrite((adapter) =>\n adapter.setMany\n ? adapter.setMany(items)\n : Promise.all(items.map((item) => adapter.set(item))).then(() => undefined),\n );\n }\n\n remove(id: string): Promise<void> {\n return this.executeWrite((adapter) => adapter.remove(id));\n }\n\n removeMany(ids: string[]): Promise<void> {\n return this.executeWrite((adapter) =>\n adapter.removeMany\n ? adapter.removeMany(ids)\n : Promise.all(ids.map((id) => adapter.remove(id))).then(() => undefined),\n );\n }\n\n clear(): Promise<void> {\n return this.executeWrite((adapter) => adapter.clear());\n }\n\n merge(localItems: KeepItem<TMeta>[]): Promise<KeepItem<TMeta>[]> {\n return this.execute(async (adapter) => {\n const merged = adapter.merge ? await adapter.merge(localItems) : await mergeItems(adapter, localItems);\n if (this.active === \"primary\" && this.mirrorWrites) {\n try {\n if (this.fallback.setMany) await this.fallback.setMany(merged);\n else for (const item of merged) await this.fallback.set(item);\n } catch {\n // The fallback is best-effort while the primary is healthy.\n }\n }\n return merged;\n });\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n const notify = (source: \"primary\" | \"fallback\") => {\n if (source === this.active) listener();\n };\n const unsubscribePrimary = this.primary.subscribe?.(() => notify(\"primary\"));\n const unsubscribeFallback = this.fallback.subscribe?.(() => notify(\"fallback\"));\n return () => {\n this.listeners.delete(listener);\n unsubscribePrimary?.();\n unsubscribeFallback?.();\n };\n }\n\n private async readAll(): Promise<KeepItem<TMeta>[]> {\n if (this.active === \"fallback\") return this.fallback.getAll();\n let items: KeepItem<TMeta>[];\n try {\n items = await this.primary.getAll();\n } catch (error) {\n if (!this.shouldFallback(error)) throw error;\n this.activateFallback(error);\n return this.fallback.getAll();\n }\n if (!this.migrateFallbackOnEmpty || items.length > 0) return items;\n\n const fallbackItems = await this.fallback.getAll();\n if (fallbackItems.length === 0) return items;\n try {\n if (this.primary.setMany) await this.primary.setMany(fallbackItems);\n else for (const item of fallbackItems) await this.primary.set(item);\n return fallbackItems;\n } catch (error) {\n if (!this.shouldFallback(error)) throw error;\n this.activateFallback(error);\n return fallbackItems;\n }\n }\n\n private activateFallback(error: unknown): void {\n this.active = \"fallback\";\n this.onFallback?.(error);\n for (const listener of this.listeners) listener();\n }\n\n private async executeWrite<TResult>(\n operation: (adapter: StorageAdapter<TMeta>) => Promise<TResult>,\n ): Promise<TResult> {\n const result = await this.execute(operation);\n if (this.active === \"primary\" && this.mirrorWrites) {\n try {\n await operation(this.fallback);\n } catch {\n // The fallback is best-effort while the primary is healthy.\n }\n }\n return result;\n }\n\n private async execute<TResult>(operation: (adapter: StorageAdapter<TMeta>) => Promise<TResult>): Promise<TResult> {\n const adapter = this.active === \"primary\" ? this.primary : this.fallback;\n try {\n return await operation(adapter);\n } catch (error) {\n if (this.active !== \"primary\" || !this.shouldFallback(error)) throw error;\n this.activateFallback(error);\n return operation(this.fallback);\n }\n }\n}\n\nexport type BrowserStorageAdapterOptions = {\n key?: string;\n databaseName?: string;\n storeName?: string;\n version?: number;\n indexedDB?: IDBFactory;\n storage?: Storage;\n};\n\n/** IndexedDB-first browser storage with localStorage fallback. */\nexport function createBrowserStorageAdapter<TMeta = Record<string, unknown>>(\n options: BrowserStorageAdapterOptions = {},\n): StorageAdapter<TMeta> {\n const browserIndexedDB = options.indexedDB ?? getBrowserIndexedDB();\n const fallback = new LocalStorageAdapter<TMeta>({ key: options.key, storage: options.storage });\n if (!browserIndexedDB) return fallback;\n return new FallbackStorageAdapter<TMeta>({\n primary: new IndexedDBAdapter<TMeta>({\n databaseName: options.databaseName,\n storeName: options.storeName,\n version: options.version,\n indexedDB: browserIndexedDB,\n }),\n fallback,\n migrateFallbackOnEmpty: true,\n mirrorWrites: true,\n });\n}\n\n/** Adapt sync or async persistence functions to the StorageAdapter contract. */\nexport function createStorageAdapter<TMeta = Record<string, unknown>>(\n options: StorageAdapterFactoryOptions<TMeta>,\n): StorageAdapter<TMeta> {\n const merge = options.merge;\n const subscribe = options.subscribe;\n const setMany = options.setMany;\n const removeMany = options.removeMany;\n return {\n getAll: async () => options.getAll(),\n set: async (item) => options.set(item),\n ...(setMany ? { setMany: async (items: KeepItem<TMeta>[]) => setMany(items) } : {}),\n remove: async (id) => options.remove(id),\n ...(removeMany ? { removeMany: async (ids: string[]) => removeMany(ids) } : {}),\n clear: async () => options.clear(),\n ...(merge ? { merge: async (items: KeepItem<TMeta>[]) => merge(items) } : {}),\n ...(subscribe\n ? {\n subscribe: (listener: () => void) => subscribe(listener) ?? (() => undefined),\n }\n : {}),\n ...(options.storageKey ? { storageKey: options.storageKey } : {}),\n };\n}\n\nasync function mergeItems<TMeta>(\n adapter: StorageAdapter<TMeta>,\n localItems: KeepItem<TMeta>[],\n): Promise<KeepItem<TMeta>[]> {\n const remoteItems = await adapter.getAll();\n const byId = new Map(remoteItems.map((item) => [item.id, item]));\n for (const item of localItems) {\n const current = byId.get(item.id);\n if (!current || item.updatedAt > current.updatedAt) byId.set(item.id, item);\n }\n const merged = [...byId.values()].sort((a, b) => b.updatedAt - a.updatedAt);\n if (adapter.setMany) await adapter.setMany(merged);\n else for (const item of merged) await adapter.set(item);\n return merged;\n}\n\n/** An async StorageAdapter backed by browser localStorage. */\nexport class LocalStorageAdapter<TMeta = Record<string, unknown>> implements StorageAdapter<TMeta> {\n public readonly storageKey: string;\n private readonly storage: Storage | undefined;\n\n constructor(options: LocalStorageAdapterOptions = {}) {\n this.storageKey = options.key ?? DEFAULT_STORAGE_KEY;\n this.storage = options.storage ?? getBrowserStorage();\n }\n\n async getAll(): Promise<KeepItem<TMeta>[]> {\n if (!this.storage) return [];\n\n let raw: string | null;\n try {\n raw = this.storage.getItem(this.storageKey);\n } catch (cause) {\n throw new KeepStorageAccessError({\n operation: \"getAll\",\n storageKey: this.storageKey,\n cause,\n });\n }\n\n if (!raw) return [];\n\n try {\n const value: unknown = JSON.parse(raw);\n if (!isKeepItemArray(value)) {\n throw new KeepStorageParseError({\n operation: \"getAll\",\n storageKey: this.storageKey,\n });\n }\n return value as KeepItem<TMeta>[];\n } catch (cause) {\n if (cause instanceof KeepStorageParseError) throw cause;\n throw new KeepStorageParseError({\n operation: \"getAll\",\n storageKey: this.storageKey,\n cause,\n });\n }\n }\n\n async set(item: KeepItem<TMeta>): Promise<void> {\n await this.setMany([item]);\n }\n\n async setMany(items: KeepItem<TMeta>[]): Promise<void> {\n const current = await this.getAll();\n const byId = new Map(current.map((item) => [item.id, item]));\n for (const item of items) byId.set(item.id, item);\n this.write([...byId.values()], \"set\");\n }\n\n async remove(id: string): Promise<void> {\n await this.removeMany([id]);\n }\n\n async removeMany(ids: string[]): Promise<void> {\n const idSet = new Set(ids);\n const items = await this.getAll();\n this.write(\n items.filter((item) => !idSet.has(item.id)),\n \"remove\",\n );\n }\n\n async clear(): Promise<void> {\n if (!this.storage) return;\n try {\n this.storage.removeItem(this.storageKey);\n } catch (cause) {\n throw new KeepStorageAccessError({\n operation: \"clear\",\n storageKey: this.storageKey,\n cause,\n });\n }\n }\n\n async merge(localItems: KeepItem<TMeta>[]): Promise<KeepItem<TMeta>[]> {\n const remoteItems = await this.getAll();\n const byId = new Map(remoteItems.map((item) => [item.id, item]));\n\n for (const localItem of localItems) {\n const remoteItem = byId.get(localItem.id);\n if (!remoteItem || localItem.updatedAt > remoteItem.updatedAt) {\n byId.set(localItem.id, localItem);\n }\n }\n\n const merged = [...byId.values()].sort((a, b) => b.updatedAt - a.updatedAt);\n this.write(merged, \"merge\");\n return merged;\n }\n\n subscribe(listener: () => void): () => void {\n if (typeof window === \"undefined\") return () => undefined;\n\n const handleStorage = (event: StorageEvent) => {\n if (event.key !== null && event.key !== this.storageKey) return;\n listener();\n };\n\n window.addEventListener(\"storage\", handleStorage);\n return () => window.removeEventListener(\"storage\", handleStorage);\n }\n\n private write(items: KeepItem<TMeta>[], operation: KeepStorageOperation): void {\n if (!this.storage) return;\n try {\n this.storage.setItem(this.storageKey, JSON.stringify(items));\n } catch (cause) {\n if (isQuotaExceededError(cause)) {\n throw new KeepStorageQuotaError({\n operation,\n storageKey: this.storageKey,\n cause,\n });\n }\n throw new KeepStorageAccessError({\n operation,\n storageKey: this.storageKey,\n cause,\n });\n }\n }\n}\n\n/** An async StorageAdapter backed by IndexedDB, with one object store per adapter. */\nexport class IndexedDBAdapter<TMeta = Record<string, unknown>> implements StorageAdapter<TMeta> {\n public readonly storageKey: string;\n private readonly databaseName: string;\n private readonly storeName: string;\n private readonly version: number;\n private readonly indexedDB: IDBFactory | undefined;\n private databasePromise: Promise<IDBDatabase | undefined> | undefined;\n\n constructor(options: IndexedDBAdapterOptions = {}) {\n this.databaseName = options.databaseName ?? options.dbName ?? options.key ?? DEFAULT_INDEXEDDB_DATABASE;\n this.storeName = options.storeName ?? DEFAULT_INDEXEDDB_STORE;\n this.version = options.version ?? 1;\n this.indexedDB = options.indexedDB ?? getBrowserIndexedDB();\n this.storageKey = `${this.databaseName}:${this.storeName}`;\n }\n\n async getAll(): Promise<KeepItem<TMeta>[]> {\n const database = await this.open(\"getAll\");\n if (!database) return [];\n try {\n const transaction = database.transaction(this.storeName, \"readonly\");\n const value: unknown = await requestToPromise(transaction.objectStore(this.storeName).getAll());\n if (!isKeepItemArray(value)) {\n throw new KeepStorageParseError({ operation: \"getAll\", storageKey: this.storageKey });\n }\n return value as KeepItem<TMeta>[];\n } catch (cause) {\n if (cause instanceof KeepStorageParseError) throw cause;\n throw new KeepStorageAccessError({ operation: \"getAll\", storageKey: this.storageKey, cause });\n }\n }\n\n async set(item: KeepItem<TMeta>): Promise<void> {\n return this.setMany([item]);\n }\n\n async setMany(items: KeepItem<TMeta>[]): Promise<void> {\n const database = await this.open(\"set\");\n if (!database) return;\n try {\n const transaction = database.transaction(this.storeName, \"readwrite\");\n const objectStore = transaction.objectStore(this.storeName);\n for (const item of items) objectStore.put(item);\n await transactionToPromise(transaction);\n this.notifySubscribers();\n } catch (cause) {\n if (isQuotaExceededError(cause)) {\n throw new KeepStorageQuotaError({ operation: \"set\", storageKey: this.storageKey, cause });\n }\n throw new KeepStorageAccessError({ operation: \"set\", storageKey: this.storageKey, cause });\n }\n }\n\n async remove(id: string): Promise<void> {\n return this.removeMany([id]);\n }\n\n async removeMany(ids: string[]): Promise<void> {\n const database = await this.open(\"remove\");\n if (!database) return;\n try {\n const transaction = database.transaction(this.storeName, \"readwrite\");\n const objectStore = transaction.objectStore(this.storeName);\n for (const id of new Set(ids)) objectStore.delete(id);\n await transactionToPromise(transaction);\n this.notifySubscribers();\n } catch (cause) {\n throw new KeepStorageAccessError({ operation: \"remove\", storageKey: this.storageKey, cause });\n }\n }\n\n async clear(): Promise<void> {\n const database = await this.open(\"clear\");\n if (!database) return;\n try {\n const transaction = database.transaction(this.storeName, \"readwrite\");\n transaction.objectStore(this.storeName).clear();\n await transactionToPromise(transaction);\n this.notifySubscribers();\n } catch (cause) {\n throw new KeepStorageAccessError({ operation: \"clear\", storageKey: this.storageKey, cause });\n }\n }\n\n async merge(localItems: KeepItem<TMeta>[]): Promise<KeepItem<TMeta>[]> {\n try {\n const remoteItems = await this.getAll();\n const byId = new Map(remoteItems.map((item) => [item.id, item]));\n for (const localItem of localItems) {\n const remoteItem = byId.get(localItem.id);\n if (!remoteItem || localItem.updatedAt > remoteItem.updatedAt) byId.set(localItem.id, localItem);\n }\n const merged = [...byId.values()].sort((a, b) => b.updatedAt - a.updatedAt);\n await this.setMany(merged);\n return merged;\n } catch (cause) {\n if (cause instanceof KeepStorageError) throw cause;\n throw new KeepStorageAccessError({ operation: \"merge\", storageKey: this.storageKey, cause });\n }\n }\n\n subscribe(listener: () => void): () => void {\n if (!this.indexedDB || typeof BroadcastChannel === \"undefined\") return () => undefined;\n const channel = new BroadcastChannel(`keepkit:${this.storageKey}`);\n channel.onmessage = () => listener();\n return () => channel.close();\n }\n\n private notifySubscribers(): void {\n if (!this.indexedDB || typeof BroadcastChannel === \"undefined\") return;\n const channel = new BroadcastChannel(`keepkit:${this.storageKey}`);\n channel.postMessage({ type: \"keepkit:changed\" });\n channel.close();\n }\n\n private open(operation: KeepStorageOperation): Promise<IDBDatabase | undefined> {\n if (!this.indexedDB) return Promise.resolve(undefined);\n if (!this.databasePromise) {\n this.databasePromise = new Promise((resolve, reject) => {\n let request: IDBOpenDBRequest;\n try {\n request = this.indexedDB?.open(this.databaseName, this.version) as IDBOpenDBRequest;\n } catch (cause) {\n reject(new KeepStorageAccessError({ operation, storageKey: this.storageKey, cause }));\n return;\n }\n request.onupgradeneeded = () => {\n if (!request.result.objectStoreNames.contains(this.storeName)) {\n request.result.createObjectStore(this.storeName, { keyPath: \"id\" });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n request.onblocked = () => reject(request.error ?? new Error(\"IndexedDB open was blocked.\"));\n });\n }\n return this.databasePromise.catch((cause) => {\n this.databasePromise = undefined;\n if (cause instanceof KeepStorageError) throw cause;\n throw new KeepStorageAccessError({ operation, storageKey: this.storageKey, cause });\n });\n }\n}\n\nfunction isKeepItemArray(value: unknown): value is KeepItem[] {\n return (\n Array.isArray(value) &&\n value.every(\n (item) =>\n isRecord(item) &&\n typeof item.id === \"string\" &&\n typeof item.savedAt === \"number\" &&\n Number.isFinite(item.savedAt) &&\n typeof item.updatedAt === \"number\" &&\n Number.isFinite(item.updatedAt) &&\n \"meta\" in item &&\n (item.targetType === undefined || typeof item.targetType === \"string\") &&\n (item.note === undefined || typeof item.note === \"string\") &&\n (item.schemaVersion === undefined ||\n (typeof item.schemaVersion === \"number\" && Number.isFinite(item.schemaVersion))) &&\n (item.revision === undefined || typeof item.revision === \"string\") &&\n (item.metaUpdatedAt === undefined ||\n (typeof item.metaUpdatedAt === \"number\" && Number.isFinite(item.metaUpdatedAt))) &&\n (item.tags === undefined || (Array.isArray(item.tags) && item.tags.every((tag) => typeof tag === \"string\"))),\n )\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction getBrowserStorage(): Storage | undefined {\n if (typeof window === \"undefined\") return undefined;\n try {\n return window.localStorage;\n } catch {\n return undefined;\n }\n}\n\nfunction getBrowserIndexedDB(): IDBFactory | undefined {\n if (typeof indexedDB === \"undefined\") return undefined;\n return indexedDB;\n}\n\nfunction isRecoverableStorageError(error: unknown): boolean {\n return error instanceof KeepStorageAccessError || error instanceof KeepStorageQuotaError;\n}\n\nfunction requestToPromise<T>(request: IDBRequest<T>): Promise<T> {\n return new Promise((resolve, reject) => {\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nfunction transactionToPromise(transaction: IDBTransaction): Promise<void> {\n return new Promise((resolve, reject) => {\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => reject(transaction.error);\n transaction.onabort = () => reject(transaction.error ?? new Error(\"IndexedDB transaction aborted.\"));\n });\n}\n\nfunction isQuotaExceededError(cause: unknown): boolean {\n if (!isRecord(cause)) return false;\n return (\n cause.name === \"QuotaExceededError\" ||\n cause.name === \"NS_ERROR_DOM_QUOTA_REACHED\" ||\n cause.code === 22 ||\n cause.code === 1014\n );\n}\n\nexport {\n DEFAULT_SYNC_QUEUE_DATABASE,\n DEFAULT_SYNC_QUEUE_KEY,\n DEFAULT_SYNC_QUEUE_STORE,\n FallbackSyncQueueAdapter,\n type FallbackSyncQueueAdapterOptions,\n IndexedDBSyncQueueAdapter,\n type IndexedDBSyncQueueOptions,\n LocalStorageSyncQueueAdapter,\n type LocalStorageSyncQueueOptions,\n SyncStorageAdapter,\n type SyncStorageAdapterOptions,\n} from \"./sync\";\n"],"mappings":"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","names":["indexedDB","getBrowserIndexedDB","getBrowserStorage","requestToPromise","transactionToPromise","isRecord"]}
|
package/dist/core.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { K as KeepSchema, b as KeepInvalidItemPolicy, a as KeepItem, S as StorageAdapter, c as KeepPluginContext, d as KeepPlugin } from './types-
|
|
2
|
-
export { e as KeepAction, f as KeepChangeContext, g as KeepChangePhase, h as KeepConflictContext, i as KeepConflictResolver, j as KeepErrorContext, k as KeepErrorHandler, l as KeepEventHandlers, m as KeepItemInput, n as KeepSchemaParseResult, o as KeepStorageAccessError, p as KeepStorageError, q as KeepStorageOperation, r as KeepStorageParseError, s as KeepStorageQuotaError, t as KeepSyncState, u as KeepSyncStatus, R as RemoteSyncDriver, v as RemoteSyncResult, w as SyncCapableStorageAdapter, x as SyncOperation, y as SyncQueueAdapter, z as normalizeKeepTags } from './types-
|
|
3
|
-
export { K as KeepItemMetadataRefresher, a as KeepItemRevalidationRecord, b as KeepItemRevalidationResult, c as KeepItemRevalidationSummary, d as KeepItemRevalidator, e as KeepItemStatus, f as
|
|
1
|
+
import { K as KeepSchema, b as KeepInvalidItemPolicy, a as KeepItem, S as StorageAdapter, c as KeepPluginContext, d as KeepPlugin } from './types-BCziYE6E.js';
|
|
2
|
+
export { e as KeepAction, f as KeepChangeContext, g as KeepChangePhase, h as KeepConflictContext, i as KeepConflictResolver, j as KeepErrorContext, k as KeepErrorHandler, l as KeepEventHandlers, m as KeepItemInput, n as KeepSchemaParseResult, o as KeepStorageAccessError, p as KeepStorageError, q as KeepStorageOperation, r as KeepStorageParseError, s as KeepStorageQuotaError, t as KeepSyncState, u as KeepSyncStatus, R as RemoteSyncDriver, v as RemoteSyncResult, w as SyncCapableStorageAdapter, x as SyncOperation, y as SyncQueueAdapter, z as normalizeKeepTags } from './types-BCziYE6E.js';
|
|
3
|
+
export { K as KeepItemMetadataRefresher, a as KeepItemRevalidationRecord, b as KeepItemRevalidationResult, c as KeepItemRevalidationSummary, d as KeepItemRevalidator, e as KeepItemStatus, f as KeepListQuery, g as KeepStore, h as KeepStoreActions, i as KeepStoreState, Q as QueryKeepItemsResult, R as RevalidateKeepItemsOptions, j as getTagCounts, k as isKeepItemMetadataStale, q as queryKeepItems, r as reconcileKeepItems, l as revalidateKeepItems } from './store-CqNh-2DS.js';
|
|
4
4
|
export { KeepSchemaValidationError, parseKeepMeta, validateKeepItem } from './schema.js';
|
|
5
5
|
export { BrowserStorageAdapterOptions, DEFAULT_INDEXEDDB_DATABASE, DEFAULT_INDEXEDDB_STORE, DEFAULT_STORAGE_KEY, DEFAULT_SYNC_QUEUE_DATABASE, DEFAULT_SYNC_QUEUE_KEY, DEFAULT_SYNC_QUEUE_STORE, FallbackStorageAdapter, FallbackStorageAdapterOptions, FallbackSyncQueueAdapter, FallbackSyncQueueAdapterOptions, IndexedDBAdapter, IndexedDBAdapterOptions, IndexedDBSyncQueueAdapter, IndexedDBSyncQueueOptions, LocalStorageAdapter, LocalStorageAdapterOptions, LocalStorageSyncQueueAdapter, LocalStorageSyncQueueOptions, StorageAdapterFactoryOptions, SyncStorageAdapter, SyncStorageAdapterOptions, createBrowserStorageAdapter, createStorageAdapter } from './storage.js';
|
|
6
6
|
|
package/dist/core.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
queryKeepItems,
|
|
6
6
|
reconcileKeepItems,
|
|
7
7
|
revalidateKeepItems
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-AWQWKK4V.js";
|
|
9
9
|
import {
|
|
10
10
|
KeepSchemaValidationError,
|
|
11
11
|
parseKeepMeta,
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
createBrowserStorageAdapter,
|
|
33
33
|
createStorageAdapter,
|
|
34
34
|
normalizeKeepTags
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-DBRHZ6XU.js";
|
|
36
36
|
|
|
37
37
|
// src/migration.ts
|
|
38
38
|
async function mergeKeepItems(localItems, target) {
|
package/dist/react.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ButtonHTMLAttributes, MouseEvent, HTMLAttributes, ReactElement, PropsWithChildren, ComponentType } from 'react';
|
|
3
|
-
import { K as KeepItemMetadataRefresher, d as KeepItemRevalidator, R as RevalidateKeepItemsOptions, c as KeepItemRevalidationSummary, f as
|
|
4
|
-
export { b as KeepItemRevalidationResult, e as KeepItemStatus, k as isKeepItemMetadataStale } from './store-
|
|
5
|
-
import { m as KeepItemInput, a as KeepItem, l as KeepEventHandlers, S as StorageAdapter, d as KeepPlugin, K as KeepSchema, b as KeepInvalidItemPolicy, t as KeepSyncState } from './types-
|
|
3
|
+
import { K as KeepItemMetadataRefresher, d as KeepItemRevalidator, R as RevalidateKeepItemsOptions, c as KeepItemRevalidationSummary, f as KeepListQuery, g as KeepStore, h as KeepStoreActions } from './store-CqNh-2DS.js';
|
|
4
|
+
export { b as KeepItemRevalidationResult, e as KeepItemStatus, k as isKeepItemMetadataStale } from './store-CqNh-2DS.js';
|
|
5
|
+
import { m as KeepItemInput, a as KeepItem, l as KeepEventHandlers, S as StorageAdapter, d as KeepPlugin, K as KeepSchema, b as KeepInvalidItemPolicy, f as KeepChangeContext, t as KeepSyncState } from './types-BCziYE6E.js';
|
|
6
6
|
|
|
7
7
|
type UseKeepItemResult<TMeta = Record<string, unknown>> = {
|
|
8
8
|
item: KeepItem<TMeta> | undefined;
|
|
@@ -17,13 +17,18 @@ type UseKeepItemResult<TMeta = Record<string, unknown>> = {
|
|
|
17
17
|
updateTags: (tags?: string[]) => Promise<void>;
|
|
18
18
|
refreshMetadata: (refresh: KeepItemMetadataRefresher<TMeta>) => Promise<void>;
|
|
19
19
|
};
|
|
20
|
-
|
|
20
|
+
/** Read and mutate one saved item from its complete minimal input description. */
|
|
21
|
+
declare function useKeepItem<TMeta = Record<string, unknown>>(input?: KeepItemInput<TMeta>): UseKeepItemResult<TMeta>;
|
|
21
22
|
|
|
22
23
|
type UseKeepListResult<TMeta = Record<string, unknown>> = {
|
|
23
24
|
items: KeepItem<TMeta>[];
|
|
24
25
|
totalCount: number;
|
|
25
26
|
tags: string[];
|
|
26
27
|
tagCounts: Record<string, number>;
|
|
28
|
+
page: number;
|
|
29
|
+
pageCount: number;
|
|
30
|
+
hasNextPage: boolean;
|
|
31
|
+
hasPreviousPage: boolean;
|
|
27
32
|
isLoading: boolean;
|
|
28
33
|
isHydrated: boolean;
|
|
29
34
|
isMutating: boolean;
|
|
@@ -37,14 +42,13 @@ type UseKeepListResult<TMeta = Record<string, unknown>> = {
|
|
|
37
42
|
refresh: () => Promise<void>;
|
|
38
43
|
revalidate: (revalidator: KeepItemRevalidator<TMeta>, options?: RevalidateKeepItemsOptions) => Promise<KeepItemRevalidationSummary<TMeta>>;
|
|
39
44
|
};
|
|
40
|
-
declare function useKeepList<TMeta = Record<string, unknown>>(
|
|
45
|
+
declare function useKeepList<TMeta = Record<string, unknown>>(query?: KeepListQuery<TMeta>): UseKeepListResult<TMeta>;
|
|
41
46
|
|
|
42
47
|
type KeepShortcutModifier = "meta" | "ctrl" | "alt" | "shift";
|
|
43
48
|
type KeepShortcutOptions<TMeta = Record<string, unknown>> = {
|
|
44
49
|
key: string;
|
|
45
50
|
modifier?: KeepShortcutModifier;
|
|
46
|
-
|
|
47
|
-
itemPayload?: KeepItemInput<TMeta>;
|
|
51
|
+
item?: KeepItemInput<TMeta>;
|
|
48
52
|
action?: "toggle" | "save" | "remove";
|
|
49
53
|
enabled?: boolean;
|
|
50
54
|
preventDefault?: boolean;
|
|
@@ -55,9 +59,7 @@ type KeepShortcutOptions<TMeta = Record<string, unknown>> = {
|
|
|
55
59
|
/** Bind a keyboard shortcut to a Keep action or an arbitrary command. */
|
|
56
60
|
declare function useKeepShortcut<TMeta = Record<string, unknown>>(options: KeepShortcutOptions<TMeta>): void;
|
|
57
61
|
|
|
58
|
-
type KeepButtonItem<TMeta = Record<string, unknown>> = KeepItemInput<TMeta
|
|
59
|
-
id: string;
|
|
60
|
-
};
|
|
62
|
+
type KeepButtonItem<TMeta = Record<string, unknown>> = KeepItemInput<TMeta>;
|
|
61
63
|
type KeepButtonSharedProps<TMeta> = {
|
|
62
64
|
item: KeepButtonItem<TMeta>;
|
|
63
65
|
children?: ReactNode | ((state: KeepButtonState<TMeta>) => ReactNode);
|
|
@@ -98,6 +100,7 @@ type KeepContextValue<TMeta = Record<string, unknown>> = {
|
|
|
98
100
|
isHydrated: boolean;
|
|
99
101
|
isMutating: boolean;
|
|
100
102
|
error: unknown | null;
|
|
103
|
+
lastChange?: KeepChangeContext<TMeta>;
|
|
101
104
|
syncState: KeepSyncState;
|
|
102
105
|
saveItem: (item: KeepItem<TMeta>) => Promise<void>;
|
|
103
106
|
updateNote: (id: string, note?: string) => Promise<void>;
|
|
@@ -136,24 +139,16 @@ declare function KeepProvider<TMeta = Record<string, unknown>>({ storage, initia
|
|
|
136
139
|
declare function useKeepContext<TMeta = Record<string, unknown>>(): KeepContextValue<TMeta>;
|
|
137
140
|
declare function useKeepStore<TMeta = Record<string, unknown>>(): KeepStoreAccess<TMeta>;
|
|
138
141
|
|
|
139
|
-
type CreateKeepKitOptions<TMeta = Record<string, unknown>> =
|
|
140
|
-
initialItems?: KeepProviderProps<TMeta>["initialItems"];
|
|
141
|
-
plugins?: KeepPlugin<TMeta>[];
|
|
142
|
-
schemaVersion?: number;
|
|
143
|
-
schema?: KeepSchema<TMeta>;
|
|
144
|
-
invalidItemPolicy?: KeepInvalidItemPolicy;
|
|
145
|
-
onInvalidItem?: KeepProviderProps<TMeta>["onInvalidItem"];
|
|
146
|
-
migrateMeta?: KeepProviderProps<TMeta>["migrateMeta"];
|
|
147
|
-
};
|
|
142
|
+
type CreateKeepKitOptions<TMeta = Record<string, unknown>> = Omit<KeepProviderProps<TMeta>, "children">;
|
|
148
143
|
type KeepKit<TMeta> = {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
144
|
+
Provider: ComponentType<KeepProviderProps<TMeta>>;
|
|
145
|
+
Button: ComponentType<KeepButtonProps<TMeta>>;
|
|
146
|
+
useContext: () => ReturnType<typeof useKeepContext<TMeta>>;
|
|
147
|
+
useItem: (item?: KeepItemInput<TMeta>) => UseKeepItemResult<TMeta>;
|
|
148
|
+
useList: (query?: KeepListQuery<TMeta>) => UseKeepListResult<TMeta>;
|
|
149
|
+
useShortcut: (options: KeepShortcutOptions<TMeta>) => void;
|
|
155
150
|
};
|
|
156
151
|
/** Create an app-specific, fully typed set of KeepKit components and hooks. */
|
|
157
152
|
declare function createKeepKit<TMeta = Record<string, unknown>>(options?: CreateKeepKitOptions<TMeta>): KeepKit<TMeta>;
|
|
158
153
|
|
|
159
|
-
export { type CreateKeepKitOptions, KeepButton, type KeepButtonItem, type KeepButtonProps, type KeepButtonState, type KeepContextValue, KeepItemMetadataRefresher, KeepItemRevalidationSummary, KeepItemRevalidator, type KeepKit,
|
|
154
|
+
export { type CreateKeepKitOptions, KeepButton, type KeepButtonItem, type KeepButtonProps, type KeepButtonState, type KeepContextValue, KeepItemMetadataRefresher, KeepItemRevalidationSummary, KeepItemRevalidator, type KeepKit, KeepListQuery, KeepProvider, type KeepProviderProps, type KeepShortcutModifier, type KeepShortcutOptions, RevalidateKeepItemsOptions, type UseKeepItemResult, type UseKeepListResult, createKeepKit, useKeepContext, useKeepItem, useKeepList, useKeepShortcut, useKeepStore };
|