@keepkit/core 0.10.0 → 0.11.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 +4 -0
- package/dist/{chunk-EXE4E3GA.js → chunk-36YIELZE.js} +119 -5
- package/dist/chunk-36YIELZE.js.map +1 -0
- package/dist/{chunk-XF5VI6O5.js → chunk-MDTL5L64.js} +1 -1
- package/dist/chunk-MDTL5L64.js.map +1 -0
- package/dist/core.d.ts +27 -4
- package/dist/core.js +106 -2
- package/dist/core.js.map +1 -1
- package/dist/react.d.ts +17 -6
- package/dist/react.js +128 -7
- package/dist/react.js.map +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/scope-CtLSlZhq.d.ts +38 -0
- package/dist/storage.d.ts +7 -2
- package/dist/storage.js +7 -1
- package/dist/{types--YahIoEB.d.ts → types-D-xRiz1Y.d.ts} +8 -2
- package/dist/{store-Cgqx7_xd.d.ts → url-BYFEfulm.d.ts} +39 -2
- package/package.json +1 -1
- package/dist/chunk-EXE4E3GA.js.map +0 -1
- package/dist/chunk-XF5VI6O5.js.map +0 -1
package/dist/core.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
queryKeepItems,
|
|
14
14
|
reconcileKeepItems,
|
|
15
15
|
revalidateKeepItems
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-MDTL5L64.js";
|
|
17
17
|
import {
|
|
18
18
|
KeepSchemaValidationError,
|
|
19
19
|
parseKeepMeta,
|
|
@@ -36,11 +36,16 @@ import {
|
|
|
36
36
|
KeepStorageQuotaError,
|
|
37
37
|
LocalStorageAdapter,
|
|
38
38
|
LocalStorageSyncQueueAdapter,
|
|
39
|
+
ScopedStorageAdapter,
|
|
40
|
+
ScopedSyncQueueAdapter,
|
|
39
41
|
SyncStorageAdapter,
|
|
40
42
|
createBrowserStorageAdapter,
|
|
43
|
+
createScopedStorageAdapter,
|
|
41
44
|
createStorageAdapter,
|
|
45
|
+
getKeepScopeKey,
|
|
46
|
+
isSameKeepScope,
|
|
42
47
|
normalizeKeepTags
|
|
43
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-36YIELZE.js";
|
|
44
49
|
|
|
45
50
|
// src/integrations.ts
|
|
46
51
|
function createKeepInvalidationPlugin(options) {
|
|
@@ -52,9 +57,97 @@ function createKeepInvalidationPlugin(options) {
|
|
|
52
57
|
}
|
|
53
58
|
};
|
|
54
59
|
}
|
|
60
|
+
|
|
61
|
+
// src/presets.ts
|
|
62
|
+
function createKeepKitPreset(options = {}) {
|
|
63
|
+
const mode = options.mode ?? "local";
|
|
64
|
+
const local = options.storage ? options.scope ? createScopedStorageAdapter(options.storage, options.scope) : options.storage : createBrowserStorageAdapter({ key: options.key, scope: options.scope });
|
|
65
|
+
if (mode === "sync" && !options.remote) {
|
|
66
|
+
throw new Error('createKeepKitPreset({ mode: "sync" }) requires a remote driver.');
|
|
67
|
+
}
|
|
68
|
+
let storage = local;
|
|
69
|
+
if (mode === "sync") {
|
|
70
|
+
const remote = options.remote;
|
|
71
|
+
if (!remote) throw new Error('createKeepKitPreset({ mode: "sync" }) requires a remote driver.');
|
|
72
|
+
storage = new SyncStorageAdapter({
|
|
73
|
+
local,
|
|
74
|
+
remote,
|
|
75
|
+
userId: options.scope?.userId,
|
|
76
|
+
tenantId: options.scope?.tenantId
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
mode,
|
|
81
|
+
scope: options.scope,
|
|
82
|
+
storage,
|
|
83
|
+
exportBackup: () => exportItems(storage)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
var createKeepKitSetup = createKeepKitPreset;
|
|
87
|
+
|
|
88
|
+
// src/url.ts
|
|
89
|
+
var DEFAULT_KEEP_URL_PARAMS = {
|
|
90
|
+
search: "q",
|
|
91
|
+
tags: "tag",
|
|
92
|
+
sort: "sort",
|
|
93
|
+
page: "page"
|
|
94
|
+
};
|
|
95
|
+
function encodeKeepListQuery(query = {}, options = {}) {
|
|
96
|
+
const params = { ...DEFAULT_KEEP_URL_PARAMS, ...options.params };
|
|
97
|
+
const result = new URLSearchParams();
|
|
98
|
+
const search = query.search?.query?.trim();
|
|
99
|
+
if (search) result.set(params.search, search);
|
|
100
|
+
for (const tag of query.tags ?? []) {
|
|
101
|
+
const normalized = tag.trim();
|
|
102
|
+
if (normalized) result.append(params.tags, normalized);
|
|
103
|
+
}
|
|
104
|
+
if (query.sort?.by) result.set(params.sort, `${query.sort.by}:${query.sort.direction ?? "desc"}`);
|
|
105
|
+
const page = query.pagination?.page;
|
|
106
|
+
if (page !== void 0 && Number.isFinite(page) && page > 1) result.set(params.page, String(Math.floor(page)));
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
function decodeKeepListQuery(input, options = {}) {
|
|
110
|
+
const params = { ...DEFAULT_KEEP_URL_PARAMS, ...options.params };
|
|
111
|
+
const searchParams = input instanceof URLSearchParams ? input : new URL(input, "http://keepkit.invalid").searchParams;
|
|
112
|
+
const search = searchParams.get(params.search)?.trim();
|
|
113
|
+
const tags = [
|
|
114
|
+
...new Set(
|
|
115
|
+
searchParams.getAll(params.tags).map((tag) => tag.trim()).filter(Boolean)
|
|
116
|
+
)
|
|
117
|
+
];
|
|
118
|
+
const sortValue = searchParams.get(params.sort)?.split(":");
|
|
119
|
+
const sort = sortValue?.[0] === "savedAt" || sortValue?.[0] === "updatedAt" ? {
|
|
120
|
+
by: sortValue[0],
|
|
121
|
+
direction: sortValue[1] === "asc" ? "asc" : "desc"
|
|
122
|
+
} : void 0;
|
|
123
|
+
const rawPage = Number(searchParams.get(params.page));
|
|
124
|
+
const page = Number.isInteger(rawPage) && rawPage > 0 ? rawPage : void 0;
|
|
125
|
+
return {
|
|
126
|
+
...search ? { search: { query: search } } : {},
|
|
127
|
+
...tags.length > 0 ? { tags } : {},
|
|
128
|
+
...sort ? { sort } : {},
|
|
129
|
+
...page ? { pagination: { page } } : {}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function serializeKeepListQuery(query = {}, options = {}) {
|
|
133
|
+
const value = encodeKeepListQuery(query, options).toString();
|
|
134
|
+
return value ? `?${value}` : "";
|
|
135
|
+
}
|
|
136
|
+
function mergeKeepListQueryFromUrl(query, input, options = {}) {
|
|
137
|
+
const decoded = decodeKeepListQuery(input, options);
|
|
138
|
+
return {
|
|
139
|
+
...query,
|
|
140
|
+
...decoded,
|
|
141
|
+
search: decoded.search ?? query.search,
|
|
142
|
+
tags: decoded.tags ?? query.tags,
|
|
143
|
+
sort: decoded.sort ?? query.sort,
|
|
144
|
+
pagination: decoded.pagination ? { ...query.pagination, ...decoded.pagination } : query.pagination
|
|
145
|
+
};
|
|
146
|
+
}
|
|
55
147
|
export {
|
|
56
148
|
DEFAULT_INDEXEDDB_DATABASE,
|
|
57
149
|
DEFAULT_INDEXEDDB_STORE,
|
|
150
|
+
DEFAULT_KEEP_URL_PARAMS,
|
|
58
151
|
DEFAULT_STORAGE_KEY,
|
|
59
152
|
DEFAULT_SYNC_QUEUE_DATABASE,
|
|
60
153
|
DEFAULT_SYNC_QUEUE_KEY,
|
|
@@ -75,21 +168,32 @@ export {
|
|
|
75
168
|
KeepStore,
|
|
76
169
|
LocalStorageAdapter,
|
|
77
170
|
LocalStorageSyncQueueAdapter,
|
|
171
|
+
ScopedStorageAdapter,
|
|
172
|
+
ScopedSyncQueueAdapter,
|
|
78
173
|
SyncStorageAdapter,
|
|
79
174
|
createBrowserStorageAdapter,
|
|
80
175
|
createKeepInvalidationPlugin,
|
|
176
|
+
createKeepKitPreset,
|
|
177
|
+
createKeepKitSetup,
|
|
178
|
+
createScopedStorageAdapter,
|
|
81
179
|
createStorageAdapter,
|
|
180
|
+
decodeKeepListQuery,
|
|
181
|
+
encodeKeepListQuery,
|
|
82
182
|
exportItems,
|
|
183
|
+
getKeepScopeKey,
|
|
83
184
|
getTagCounts,
|
|
84
185
|
importItems,
|
|
85
186
|
isKeepItemMetadataStale,
|
|
187
|
+
isSameKeepScope,
|
|
86
188
|
mergeKeepItems,
|
|
189
|
+
mergeKeepListQueryFromUrl,
|
|
87
190
|
migrateKeepItems,
|
|
88
191
|
normalizeKeepTags,
|
|
89
192
|
parseKeepMeta,
|
|
90
193
|
queryKeepItems,
|
|
91
194
|
reconcileKeepItems,
|
|
92
195
|
revalidateKeepItems,
|
|
196
|
+
serializeKeepListQuery,
|
|
93
197
|
validateKeepItem
|
|
94
198
|
};
|
|
95
199
|
//# sourceMappingURL=core.js.map
|
package/dist/core.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/integrations.ts"],"sourcesContent":["import type { KeepPlugin, KeepPluginContext } from \"./types\";\n\nexport type KeepInvalidationPluginOptions<TMeta = Record<string, unknown>> = {\n /** Query keys to invalidate after a successful local KeepKit mutation. */\n queryKeys: readonly unknown[] | ((context: KeepPluginContext<TMeta>) => readonly (readonly unknown[])[]);\n /** Connect this callback to queryClient.invalidateQueries or SWR mutate. */\n invalidate: (queryKey: readonly unknown[], context: KeepPluginContext<TMeta>) => void | Promise<void>;\n name?: string;\n};\n\n/** Framework-neutral bridge for TanStack Query, SWR, and similar caches. */\nexport function createKeepInvalidationPlugin<TMeta = Record<string, unknown>>(\n options: KeepInvalidationPluginOptions<TMeta>,\n): KeepPlugin<TMeta> {\n return {\n name: options.name ?? \"keepkit-cache-invalidation\",\n after: async (context) => {\n const keys = typeof options.queryKeys === \"function\" ? options.queryKeys(context) : [options.queryKeys];\n await Promise.all(keys.map((queryKey) => options.invalidate(queryKey, context)));\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWO,SAAS,6BACd,SACmB;AACnB,SAAO;AAAA,IACL,MAAM,QAAQ,QAAQ;AAAA,IACtB,OAAO,OAAO,YAAY;AACxB,YAAM,OAAO,OAAO,QAAQ,cAAc,aAAa,QAAQ,UAAU,OAAO,IAAI,CAAC,QAAQ,SAAS;AACtG,YAAM,QAAQ,IAAI,KAAK,IAAI,CAAC,aAAa,QAAQ,WAAW,UAAU,OAAO,CAAC,CAAC;AAAA,IACjF;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/integrations.ts","../src/presets.ts","../src/url.ts"],"sourcesContent":["import type { KeepPlugin, KeepPluginContext } from \"./types\";\n\nexport type KeepInvalidationPluginOptions<TMeta = Record<string, unknown>> = {\n /** Query keys to invalidate after a successful local KeepKit mutation. */\n queryKeys: readonly unknown[] | ((context: KeepPluginContext<TMeta>) => readonly (readonly unknown[])[]);\n /** Connect this callback to queryClient.invalidateQueries or SWR mutate. */\n invalidate: (queryKey: readonly unknown[], context: KeepPluginContext<TMeta>) => void | Promise<void>;\n name?: string;\n};\n\n/** Framework-neutral bridge for TanStack Query, SWR, and similar caches. */\nexport function createKeepInvalidationPlugin<TMeta = Record<string, unknown>>(\n options: KeepInvalidationPluginOptions<TMeta>,\n): KeepPlugin<TMeta> {\n return {\n name: options.name ?? \"keepkit-cache-invalidation\",\n after: async (context) => {\n const keys = typeof options.queryKeys === \"function\" ? options.queryKeys(context) : [options.queryKeys];\n await Promise.all(keys.map((queryKey) => options.invalidate(queryKey, context)));\n },\n };\n}\n","import { exportItems } from \"./backup\";\nimport { createScopedStorageAdapter, type KeepScope } from \"./scope\";\nimport { createBrowserStorageAdapter } from \"./storage/index\";\nimport { SyncStorageAdapter } from \"./storage/sync\";\nimport type { RemoteSyncDriver, StorageAdapter } from \"./types\";\n\nexport type KeepKitPresetMode = \"local\" | \"sync\" | \"backup\";\n\nexport type KeepKitPresetOptions<TMeta = Record<string, unknown>> = {\n mode?: KeepKitPresetMode;\n key?: string;\n scope?: KeepScope;\n remote?: RemoteSyncDriver<TMeta>;\n storage?: StorageAdapter<TMeta>;\n};\n\nexport type KeepKitSetup<TMeta = Record<string, unknown>> = {\n mode: KeepKitPresetMode;\n scope?: KeepScope;\n storage: StorageAdapter<TMeta>;\n exportBackup: () => Promise<string>;\n};\n\n/**\n * Build the recommended local/sync/backup wiring without imposing an auth or\n * API client. Pass the current user and tenant scope whenever the account changes.\n */\nexport function createKeepKitPreset<TMeta = Record<string, unknown>>(\n options: KeepKitPresetOptions<TMeta> = {},\n): KeepKitSetup<TMeta> {\n const mode = options.mode ?? \"local\";\n const local = options.storage\n ? options.scope\n ? createScopedStorageAdapter(options.storage, options.scope)\n : options.storage\n : createBrowserStorageAdapter<TMeta>({ key: options.key, scope: options.scope });\n if (mode === \"sync\" && !options.remote) {\n throw new Error('createKeepKitPreset({ mode: \"sync\" }) requires a remote driver.');\n }\n let storage: StorageAdapter<TMeta> = local;\n if (mode === \"sync\") {\n const remote = options.remote;\n if (!remote) throw new Error('createKeepKitPreset({ mode: \"sync\" }) requires a remote driver.');\n storage = new SyncStorageAdapter<TMeta>({\n local,\n remote,\n userId: options.scope?.userId,\n tenantId: options.scope?.tenantId,\n });\n }\n return {\n mode,\n scope: options.scope,\n storage,\n exportBackup: () => exportItems(storage),\n };\n}\n\nexport const createKeepKitSetup = createKeepKitPreset;\n","import type { KeepListQuery } from \"./query\";\n\nexport type KeepUrlParamNames = {\n search: string;\n tags: string;\n sort: string;\n page: string;\n};\n\nexport type KeepUrlSyncOptions = {\n /** Parameters are intentionally short so shared collection URLs stay readable. */\n params?: Partial<KeepUrlParamNames>;\n /** Push is the default so browser back/forward restores collection states. */\n history?: \"replace\" | \"push\";\n /** URL to read/write. Defaults to the current browser URL. */\n url?: string;\n};\n\nexport const DEFAULT_KEEP_URL_PARAMS: KeepUrlParamNames = {\n search: \"q\",\n tags: \"tag\",\n sort: \"sort\",\n page: \"page\",\n};\n\nexport type KeepUrlState = Pick<KeepListQuery, \"search\" | \"tags\" | \"sort\" | \"pagination\">;\n\n/** Convert a list query to stable URLSearchParams without serializing functions or unsupported filters. */\nexport function encodeKeepListQuery<TMeta = Record<string, unknown>>(\n query: KeepListQuery<TMeta> = {},\n options: Pick<KeepUrlSyncOptions, \"params\"> = {},\n): URLSearchParams {\n const params = { ...DEFAULT_KEEP_URL_PARAMS, ...options.params };\n const result = new URLSearchParams();\n const search = query.search?.query?.trim();\n if (search) result.set(params.search, search);\n for (const tag of query.tags ?? []) {\n const normalized = tag.trim();\n if (normalized) result.append(params.tags, normalized);\n }\n if (query.sort?.by) result.set(params.sort, `${query.sort.by}:${query.sort.direction ?? \"desc\"}`);\n const page = query.pagination?.page;\n if (page !== undefined && Number.isFinite(page) && page > 1) result.set(params.page, String(Math.floor(page)));\n return result;\n}\n\n/** Parse a URL into the query fields supported by KeepCollection. Invalid values are ignored. */\nexport function decodeKeepListQuery(\n input: string | URL | URLSearchParams,\n options: Pick<KeepUrlSyncOptions, \"params\"> = {},\n): KeepUrlState {\n const params = { ...DEFAULT_KEEP_URL_PARAMS, ...options.params };\n const searchParams = input instanceof URLSearchParams ? input : new URL(input, \"http://keepkit.invalid\").searchParams;\n const search = searchParams.get(params.search)?.trim();\n const tags = [\n ...new Set(\n searchParams\n .getAll(params.tags)\n .map((tag) => tag.trim())\n .filter(Boolean),\n ),\n ];\n const sortValue = searchParams.get(params.sort)?.split(\":\");\n const sort: KeepListQuery[\"sort\"] =\n sortValue?.[0] === \"savedAt\" || sortValue?.[0] === \"updatedAt\"\n ? {\n by: sortValue[0],\n direction: sortValue[1] === \"asc\" ? (\"asc\" as const) : (\"desc\" as const),\n }\n : undefined;\n const rawPage = Number(searchParams.get(params.page));\n const page = Number.isInteger(rawPage) && rawPage > 0 ? rawPage : undefined;\n return {\n ...(search ? { search: { query: search } } : {}),\n ...(tags.length > 0 ? { tags } : {}),\n ...(sort ? { sort } : {}),\n ...(page ? { pagination: { page } } : {}),\n };\n}\n\nexport function serializeKeepListQuery<TMeta = Record<string, unknown>>(\n query: KeepListQuery<TMeta> = {},\n options: Pick<KeepUrlSyncOptions, \"params\"> = {},\n): string {\n const value = encodeKeepListQuery(query, options).toString();\n return value ? `?${value}` : \"\";\n}\n\nexport function mergeKeepListQueryFromUrl<TMeta = Record<string, unknown>>(\n query: KeepListQuery<TMeta>,\n input: string | URL | URLSearchParams,\n options: Pick<KeepUrlSyncOptions, \"params\"> = {},\n): KeepListQuery<TMeta> {\n const decoded = decodeKeepListQuery(input, options);\n return {\n ...query,\n ...decoded,\n search: decoded.search ?? query.search,\n tags: decoded.tags ?? query.tags,\n sort: decoded.sort ?? query.sort,\n pagination: decoded.pagination ? { ...query.pagination, ...decoded.pagination } : query.pagination,\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/react.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ButtonHTMLAttributes, MouseEvent, HTMLAttributes, ReactElement, ErrorInfo, Component, PropsWithChildren, ComponentType } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
export {
|
|
5
|
-
import {
|
|
6
|
-
export {
|
|
3
|
+
import { g as KeepItemMetadataRefresher, l as KeepItemRevalidator, R as RevalidateKeepItemsOptions, k as KeepItemRevalidationSummary, m as KeepListQuery, h as KeepItemResolver, c as KeepAutoRevalidationOptions, I as ImportItemsOptions, a as ImportItemsResult, n as KeepStore, o as KeepStoreActions } from './url-BYFEfulm.js';
|
|
4
|
+
export { j as KeepItemRevalidationResult, q as KeepUrlParamNames, r as KeepUrlState, s as KeepUrlSyncOptions, y as isKeepItemMetadataStale } from './url-BYFEfulm.js';
|
|
5
|
+
import { p as KeepItemInput, a as KeepItem, n as KeepEventHandlers, b as StorageAdapter, f as KeepPlugin, K as KeepSchema, o as KeepInvalidItemPolicy, h as KeepChangeContext, x as KeepSyncState, z as KeepUndoState } from './types-D-xRiz1Y.js';
|
|
6
|
+
export { q as KeepItemStatus } from './types-D-xRiz1Y.js';
|
|
7
|
+
export { K as KeepScope, S as ScopedStorageAdapter } from './scope-CtLSlZhq.js';
|
|
7
8
|
|
|
8
9
|
type UseKeepItemResult<TMeta = Record<string, unknown>> = {
|
|
9
10
|
item: KeepItem<TMeta> | undefined;
|
|
@@ -13,6 +14,8 @@ type UseKeepItemResult<TMeta = Record<string, unknown>> = {
|
|
|
13
14
|
error: unknown | null;
|
|
14
15
|
save: () => Promise<void>;
|
|
15
16
|
remove: () => Promise<void>;
|
|
17
|
+
removeWithUndo: () => Promise<void>;
|
|
18
|
+
undo: () => Promise<void>;
|
|
16
19
|
toggle: () => Promise<void>;
|
|
17
20
|
updateNote: (note?: string) => Promise<void>;
|
|
18
21
|
updateTags: (tags?: string[]) => Promise<void>;
|
|
@@ -36,6 +39,8 @@ type UseKeepListResult<TMeta = Record<string, unknown>> = {
|
|
|
36
39
|
error: unknown | null;
|
|
37
40
|
remove: (id: string) => Promise<void>;
|
|
38
41
|
removeBatch: (ids: string[]) => Promise<void>;
|
|
42
|
+
removeWithUndo: (id: string) => Promise<void>;
|
|
43
|
+
removeBatchWithUndo: (ids: string[]) => Promise<void>;
|
|
39
44
|
updateTagsBatch: (ids: string[], tags?: string[]) => Promise<void>;
|
|
40
45
|
addTagsBatch: (ids: string[], tags: string[]) => Promise<void>;
|
|
41
46
|
removeTagsBatch: (ids: string[], tags: string[]) => Promise<void>;
|
|
@@ -122,6 +127,7 @@ type KeepContextValue<TMeta = Record<string, unknown>> = {
|
|
|
122
127
|
error: unknown | null;
|
|
123
128
|
lastChange?: KeepChangeContext<TMeta>;
|
|
124
129
|
syncState: KeepSyncState;
|
|
130
|
+
undo: KeepUndoState;
|
|
125
131
|
saveItem: (item: KeepItem<TMeta>) => Promise<void>;
|
|
126
132
|
updateNote: (id: string, note?: string) => Promise<void>;
|
|
127
133
|
updateTags: (id: string, tags?: string[]) => Promise<void>;
|
|
@@ -130,6 +136,9 @@ type KeepContextValue<TMeta = Record<string, unknown>> = {
|
|
|
130
136
|
removeTagsBatch: (ids: string[], tags: string[]) => Promise<void>;
|
|
131
137
|
removeItem: (id: string) => Promise<void>;
|
|
132
138
|
removeItems: (ids: string[]) => Promise<void>;
|
|
139
|
+
removeItemWithUndo: (id: string) => Promise<void>;
|
|
140
|
+
removeItemsWithUndo: (ids: string[]) => Promise<void>;
|
|
141
|
+
undoLastRemoval: () => Promise<void>;
|
|
133
142
|
clear: () => Promise<void>;
|
|
134
143
|
refresh: () => Promise<void>;
|
|
135
144
|
flushSync: () => Promise<void>;
|
|
@@ -158,12 +167,14 @@ type KeepProviderProps<TMeta = Record<string, unknown>> = PropsWithChildren<Keep
|
|
|
158
167
|
boundaryResetKey?: unknown;
|
|
159
168
|
validateItem?: KeepItemRevalidator<TMeta>;
|
|
160
169
|
resolveItem?: KeepItemResolver<TMeta>;
|
|
170
|
+
autoRevalidation?: KeepAutoRevalidationOptions<TMeta>;
|
|
171
|
+
undoTimeoutMs?: number;
|
|
161
172
|
}>;
|
|
162
173
|
type KeepStoreAccess<TMeta> = {
|
|
163
174
|
store: KeepStore<TMeta>;
|
|
164
175
|
actions: KeepStoreActions<TMeta>;
|
|
165
176
|
};
|
|
166
|
-
declare function KeepProvider<TMeta = Record<string, unknown>>({ storage, initialItems, onSave, onRemove, onNoteUpdate, onTagsUpdate, onChange, onError, plugins, schemaVersion, schema, invalidItemPolicy, onInvalidItem, migrateMeta, fallback, onBoundaryError, boundaryResetKey, validateItem, resolveItem, children, }: KeepProviderProps<TMeta>): react.JSX.Element;
|
|
177
|
+
declare function KeepProvider<TMeta = Record<string, unknown>>({ storage, initialItems, onSave, onRemove, onNoteUpdate, onTagsUpdate, onChange, onUndo, onError, plugins, schemaVersion, schema, invalidItemPolicy, onInvalidItem, migrateMeta, fallback, onBoundaryError, boundaryResetKey, validateItem, resolveItem, autoRevalidation, undoTimeoutMs, children, }: KeepProviderProps<TMeta>): react.JSX.Element;
|
|
167
178
|
declare function useKeepContext<TMeta = Record<string, unknown>>(): KeepContextValue<TMeta>;
|
|
168
179
|
declare function useKeepStore<TMeta = Record<string, unknown>>(): KeepStoreAccess<TMeta>;
|
|
169
180
|
|
|
@@ -179,4 +190,4 @@ type KeepKit<TMeta> = {
|
|
|
179
190
|
/** Create an app-specific, fully typed set of KeepKit components and hooks. */
|
|
180
191
|
declare function createKeepKit<TMeta = Record<string, unknown>>(options?: CreateKeepKitOptions<TMeta>): KeepKit<TMeta>;
|
|
181
192
|
|
|
182
|
-
export { type CreateKeepKitOptions, KeepButton, type KeepButtonItem, type KeepButtonProps, type KeepButtonState, type KeepContextValue, KeepErrorBoundary, type KeepErrorBoundaryProps, KeepItemMetadataRefresher, KeepItemResolver, KeepItemRevalidationSummary, KeepItemRevalidator, type KeepKit, KeepListQuery, KeepProvider, type KeepProviderProps, type KeepShortcutModifier, type KeepShortcutOptions, RevalidateKeepItemsOptions, type UseKeepItemResult, type UseKeepListResult, createKeepKit, useKeepContext, useKeepItem, useKeepList, useKeepShortcut, useKeepStore };
|
|
193
|
+
export { type CreateKeepKitOptions, KeepAutoRevalidationOptions, KeepButton, type KeepButtonItem, type KeepButtonProps, type KeepButtonState, type KeepContextValue, KeepErrorBoundary, type KeepErrorBoundaryProps, KeepItemMetadataRefresher, KeepItemResolver, KeepItemRevalidationSummary, KeepItemRevalidator, type KeepKit, KeepListQuery, KeepProvider, type KeepProviderProps, type KeepShortcutModifier, type KeepShortcutOptions, KeepUndoState, RevalidateKeepItemsOptions, type UseKeepItemResult, type UseKeepListResult, createKeepKit, useKeepContext, useKeepItem, useKeepList, useKeepShortcut, useKeepStore };
|
package/dist/react.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
isKeepItemMetadataStale,
|
|
7
7
|
queryKeepItems,
|
|
8
8
|
revalidateKeepItems
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-MDTL5L64.js";
|
|
10
10
|
import {
|
|
11
11
|
parseKeepMeta
|
|
12
12
|
} from "./chunk-THZ3ACR2.js";
|
|
@@ -14,7 +14,7 @@ import "./chunk-5QSZP6MT.js";
|
|
|
14
14
|
import {
|
|
15
15
|
createBrowserStorageAdapter,
|
|
16
16
|
normalizeKeepTags
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-36YIELZE.js";
|
|
18
18
|
|
|
19
19
|
// src/hooks/useKeepItem.ts
|
|
20
20
|
import { useCallback as useCallback3 } from "react";
|
|
@@ -69,6 +69,7 @@ function KeepProvider({
|
|
|
69
69
|
onNoteUpdate,
|
|
70
70
|
onTagsUpdate,
|
|
71
71
|
onChange,
|
|
72
|
+
onUndo,
|
|
72
73
|
onError,
|
|
73
74
|
plugins = [],
|
|
74
75
|
schemaVersion,
|
|
@@ -81,6 +82,8 @@ function KeepProvider({
|
|
|
81
82
|
boundaryResetKey,
|
|
82
83
|
validateItem,
|
|
83
84
|
resolveItem,
|
|
85
|
+
autoRevalidation,
|
|
86
|
+
undoTimeoutMs,
|
|
84
87
|
children
|
|
85
88
|
}) {
|
|
86
89
|
const content = /* @__PURE__ */ jsx(
|
|
@@ -93,6 +96,7 @@ function KeepProvider({
|
|
|
93
96
|
onNoteUpdate,
|
|
94
97
|
onTagsUpdate,
|
|
95
98
|
onChange,
|
|
99
|
+
onUndo,
|
|
96
100
|
onError,
|
|
97
101
|
plugins,
|
|
98
102
|
schemaVersion,
|
|
@@ -102,6 +106,8 @@ function KeepProvider({
|
|
|
102
106
|
migrateMeta,
|
|
103
107
|
validateItem,
|
|
104
108
|
resolveItem,
|
|
109
|
+
autoRevalidation,
|
|
110
|
+
undoTimeoutMs,
|
|
105
111
|
children
|
|
106
112
|
}
|
|
107
113
|
);
|
|
@@ -116,6 +122,7 @@ function KeepProviderContent({
|
|
|
116
122
|
onNoteUpdate,
|
|
117
123
|
onTagsUpdate,
|
|
118
124
|
onChange,
|
|
125
|
+
onUndo,
|
|
119
126
|
onError,
|
|
120
127
|
plugins = [],
|
|
121
128
|
schemaVersion,
|
|
@@ -125,6 +132,8 @@ function KeepProviderContent({
|
|
|
125
132
|
migrateMeta,
|
|
126
133
|
validateItem,
|
|
127
134
|
resolveItem,
|
|
135
|
+
autoRevalidation,
|
|
136
|
+
undoTimeoutMs = 5e3,
|
|
128
137
|
children
|
|
129
138
|
}) {
|
|
130
139
|
const storeRef = useRef(null);
|
|
@@ -135,17 +144,19 @@ function KeepProviderContent({
|
|
|
135
144
|
isHydrated: false,
|
|
136
145
|
isMutating: false,
|
|
137
146
|
error: null,
|
|
138
|
-
lastChange: void 0
|
|
147
|
+
lastChange: void 0,
|
|
148
|
+
undo: { canUndo: false, ids: [] }
|
|
139
149
|
});
|
|
140
150
|
}
|
|
141
151
|
const store = storeRef.current;
|
|
142
152
|
const state = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
143
|
-
const { items, isLoading, isHydrated, isMutating, error, lastChange } = state;
|
|
153
|
+
const { items, isLoading, isHydrated, isMutating, error, lastChange, undo: storedUndo } = state;
|
|
154
|
+
const undo = storedUndo ?? EMPTY_UNDO_STATE;
|
|
144
155
|
const itemsRef = useRef(items);
|
|
145
156
|
const pluginsRef = useRef(plugins);
|
|
146
157
|
pluginsRef.current = plugins;
|
|
147
|
-
const handlersRef = useRef({ onSave, onRemove, onNoteUpdate, onTagsUpdate, onChange, onError });
|
|
148
|
-
handlersRef.current = { onSave, onRemove, onNoteUpdate, onTagsUpdate, onChange, onError };
|
|
158
|
+
const handlersRef = useRef({ onSave, onRemove, onNoteUpdate, onTagsUpdate, onChange, onUndo, onError });
|
|
159
|
+
handlersRef.current = { onSave, onRemove, onNoteUpdate, onTagsUpdate, onChange, onUndo, onError };
|
|
149
160
|
const migrationRef = useRef({
|
|
150
161
|
schemaVersion,
|
|
151
162
|
migrateMeta,
|
|
@@ -157,6 +168,10 @@ function KeepProviderContent({
|
|
|
157
168
|
const operationTailRef = useRef(Promise.resolve());
|
|
158
169
|
const pendingRefreshesRef = useRef(0);
|
|
159
170
|
const pendingMutationsRef = useRef(0);
|
|
171
|
+
const undoRef = useRef(void 0);
|
|
172
|
+
const autoRevalidationRef = useRef(autoRevalidation);
|
|
173
|
+
autoRevalidationRef.current = autoRevalidation;
|
|
174
|
+
const didMountRevalidateRef = useRef(false);
|
|
160
175
|
const syncStorage = isSyncCapableStorage(storage) ? storage : void 0;
|
|
161
176
|
const getSyncState = useCallback(() => syncStorage?.getSyncState() ?? IDLE_SYNC_STATE, [syncStorage]);
|
|
162
177
|
const subscribeSync = useCallback(
|
|
@@ -474,6 +489,69 @@ function KeepProviderContent({
|
|
|
474
489
|
},
|
|
475
490
|
[runMutation, storage]
|
|
476
491
|
);
|
|
492
|
+
const rememberUndo = useCallback(
|
|
493
|
+
(removedItems) => {
|
|
494
|
+
undoRef.current?.timer && clearTimeout(undoRef.current.timer);
|
|
495
|
+
const expiresAt = Date.now() + Math.max(0, undoTimeoutMs);
|
|
496
|
+
const timer = setTimeout(
|
|
497
|
+
() => {
|
|
498
|
+
undoRef.current = void 0;
|
|
499
|
+
store.setState({ undo: { canUndo: false, ids: [] } });
|
|
500
|
+
},
|
|
501
|
+
Math.max(0, undoTimeoutMs)
|
|
502
|
+
);
|
|
503
|
+
undoRef.current = { items: removedItems, expiresAt, timer };
|
|
504
|
+
store.setState({ undo: { canUndo: true, ids: removedItems.map((item) => item.id), expiresAt } });
|
|
505
|
+
},
|
|
506
|
+
[store, undoTimeoutMs]
|
|
507
|
+
);
|
|
508
|
+
const removeItemWithUndo = useCallback(
|
|
509
|
+
async (id) => {
|
|
510
|
+
const item = itemsRef.current.find((current) => current.id === id);
|
|
511
|
+
await removeItem(id);
|
|
512
|
+
if (item) rememberUndo([item]);
|
|
513
|
+
},
|
|
514
|
+
[rememberUndo, removeItem]
|
|
515
|
+
);
|
|
516
|
+
const removeItemsWithUndo = useCallback(
|
|
517
|
+
async (ids) => {
|
|
518
|
+
const idSet = new Set(ids);
|
|
519
|
+
const removedItems = itemsRef.current.filter((item) => idSet.has(item.id));
|
|
520
|
+
await removeItems(ids);
|
|
521
|
+
if (removedItems.length > 0) rememberUndo(removedItems);
|
|
522
|
+
},
|
|
523
|
+
[rememberUndo, removeItems]
|
|
524
|
+
);
|
|
525
|
+
const undoLastRemoval = useCallback(async () => {
|
|
526
|
+
const pending = undoRef.current;
|
|
527
|
+
if (!pending || pending.expiresAt < Date.now()) {
|
|
528
|
+
undoRef.current = void 0;
|
|
529
|
+
store.setState({ undo: { canUndo: false, ids: [] } });
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
if (pending.timer) clearTimeout(pending.timer);
|
|
533
|
+
undoRef.current = void 0;
|
|
534
|
+
store.setState({ undo: { canUndo: false, ids: [] } });
|
|
535
|
+
await runMutation("undo", void 0, (previous) => {
|
|
536
|
+
const restored = new Map(pending.items.map((item) => [item.id, item]));
|
|
537
|
+
const next = [...previous.filter((item) => !restored.has(item.id)), ...pending.items].sort(
|
|
538
|
+
(a, b) => b.updatedAt - a.updatedAt
|
|
539
|
+
);
|
|
540
|
+
return {
|
|
541
|
+
next,
|
|
542
|
+
persist: async () => {
|
|
543
|
+
if (storage.setMany) await storage.setMany(pending.items);
|
|
544
|
+
else for (const item of pending.items) await storage.set(item);
|
|
545
|
+
},
|
|
546
|
+
onSuccess: () => handlersRef.current.onUndo?.(pending.items),
|
|
547
|
+
pluginContext: { action: "undo", items: pending.items }
|
|
548
|
+
};
|
|
549
|
+
});
|
|
550
|
+
}, [runMutation, storage, store]);
|
|
551
|
+
useEffect(() => {
|
|
552
|
+
if (syncState.status !== "error" || !undoRef.current) return;
|
|
553
|
+
void undoLastRemoval();
|
|
554
|
+
}, [syncState.status, undoLastRemoval]);
|
|
477
555
|
const clear = useCallback(
|
|
478
556
|
() => runMutation("clear", void 0, (_previous) => ({
|
|
479
557
|
next: [],
|
|
@@ -544,6 +622,27 @@ function KeepProviderContent({
|
|
|
544
622
|
validateItem
|
|
545
623
|
]
|
|
546
624
|
);
|
|
625
|
+
useEffect(() => {
|
|
626
|
+
const settings = autoRevalidationRef.current;
|
|
627
|
+
const activeRevalidator = settings?.revalidator ?? validateItem;
|
|
628
|
+
if (!settings || !activeRevalidator) return;
|
|
629
|
+
const run = () => void revalidateItems(activeRevalidator, { removeStatuses: settings.removeStatuses }).catch(() => void 0);
|
|
630
|
+
if (isHydrated && settings.onMount !== false && !didMountRevalidateRef.current) {
|
|
631
|
+
didMountRevalidateRef.current = true;
|
|
632
|
+
run();
|
|
633
|
+
}
|
|
634
|
+
const interval = settings.intervalMs && settings.intervalMs > 0 ? setInterval(run, settings.intervalMs) : void 0;
|
|
635
|
+
const onOnline = () => {
|
|
636
|
+
if (settings.onReconnect !== false) run();
|
|
637
|
+
};
|
|
638
|
+
if (typeof window !== "undefined" && settings.onReconnect !== false) {
|
|
639
|
+
window.addEventListener("online", onOnline);
|
|
640
|
+
}
|
|
641
|
+
return () => {
|
|
642
|
+
if (interval) clearInterval(interval);
|
|
643
|
+
if (typeof window !== "undefined") window.removeEventListener("online", onOnline);
|
|
644
|
+
};
|
|
645
|
+
}, [isHydrated, revalidateItems, validateItem]);
|
|
547
646
|
const refreshItemMetadata = useCallback(
|
|
548
647
|
async (id, refresh2) => {
|
|
549
648
|
if (!itemsRef.current.some((item) => item.id === id)) {
|
|
@@ -594,6 +693,7 @@ function KeepProviderContent({
|
|
|
594
693
|
error,
|
|
595
694
|
lastChange,
|
|
596
695
|
syncState,
|
|
696
|
+
undo,
|
|
597
697
|
saveItem,
|
|
598
698
|
updateNote,
|
|
599
699
|
updateTags,
|
|
@@ -602,6 +702,9 @@ function KeepProviderContent({
|
|
|
602
702
|
removeTagsBatch,
|
|
603
703
|
removeItem,
|
|
604
704
|
removeItems,
|
|
705
|
+
removeItemWithUndo,
|
|
706
|
+
removeItemsWithUndo,
|
|
707
|
+
undoLastRemoval,
|
|
605
708
|
clear,
|
|
606
709
|
refresh,
|
|
607
710
|
flushSync,
|
|
@@ -620,9 +723,13 @@ function KeepProviderContent({
|
|
|
620
723
|
isMutating,
|
|
621
724
|
items,
|
|
622
725
|
syncState,
|
|
726
|
+
undo,
|
|
623
727
|
refresh,
|
|
624
728
|
removeItem,
|
|
625
729
|
saveItem,
|
|
730
|
+
removeItemWithUndo,
|
|
731
|
+
removeItemsWithUndo,
|
|
732
|
+
undoLastRemoval,
|
|
626
733
|
updateNote,
|
|
627
734
|
updateTags,
|
|
628
735
|
updateTagsBatch,
|
|
@@ -645,6 +752,9 @@ function KeepProviderContent({
|
|
|
645
752
|
removeTagsBatch,
|
|
646
753
|
removeItem,
|
|
647
754
|
removeItems,
|
|
755
|
+
removeItemWithUndo,
|
|
756
|
+
removeItemsWithUndo,
|
|
757
|
+
undoLastRemoval,
|
|
648
758
|
clear,
|
|
649
759
|
refresh,
|
|
650
760
|
refreshItemMetadata,
|
|
@@ -662,7 +772,10 @@ function KeepProviderContent({
|
|
|
662
772
|
updateTags,
|
|
663
773
|
updateTagsBatch,
|
|
664
774
|
refreshItemMetadata,
|
|
665
|
-
revalidateItems
|
|
775
|
+
revalidateItems,
|
|
776
|
+
removeItemWithUndo,
|
|
777
|
+
removeItemsWithUndo,
|
|
778
|
+
undoLastRemoval
|
|
666
779
|
]
|
|
667
780
|
);
|
|
668
781
|
const storeAccess = useMemo(() => ({ store, actions }), [actions, store]);
|
|
@@ -673,6 +786,7 @@ var IDLE_SYNC_STATE = Object.freeze({
|
|
|
673
786
|
pendingCount: 0,
|
|
674
787
|
conflictIds: []
|
|
675
788
|
});
|
|
789
|
+
var EMPTY_UNDO_STATE = Object.freeze({ canUndo: false, ids: [] });
|
|
676
790
|
function isSyncCapableStorage(storage) {
|
|
677
791
|
return "getSyncState" in storage && typeof storage.getSyncState === "function" && "subscribeSync" in storage && typeof storage.subscribeSync === "function" && "flushSync" in storage && typeof storage.flushSync === "function";
|
|
678
792
|
}
|
|
@@ -745,6 +859,7 @@ function useKeepItem(input) {
|
|
|
745
859
|
});
|
|
746
860
|
}, [actions, input, item?.savedAt]);
|
|
747
861
|
const remove = useCallback3(() => actions.removeItem(id), [actions, id]);
|
|
862
|
+
const removeWithUndo = useCallback3(() => actions.removeItemWithUndo(id), [actions, id]);
|
|
748
863
|
const toggle = useCallback3(() => item ? remove() : save(), [item, remove, save]);
|
|
749
864
|
const updateNote = useCallback3((note) => actions.updateNote(id, note), [actions, id]);
|
|
750
865
|
const updateTags = useCallback3((tags) => actions.updateTags(id, tags), [actions, id]);
|
|
@@ -760,6 +875,8 @@ function useKeepItem(input) {
|
|
|
760
875
|
error,
|
|
761
876
|
save,
|
|
762
877
|
remove,
|
|
878
|
+
removeWithUndo,
|
|
879
|
+
undo: actions.undoLastRemoval,
|
|
763
880
|
toggle,
|
|
764
881
|
updateNote,
|
|
765
882
|
updateTags,
|
|
@@ -814,6 +931,8 @@ function useKeepList(query = {}) {
|
|
|
814
931
|
const allTags = useKeepStoreSelector(store, tagsSelector);
|
|
815
932
|
const remove = useCallback4((id) => actions.removeItem(id), [actions]);
|
|
816
933
|
const removeBatch = useCallback4((ids) => actions.removeItems(ids), [actions]);
|
|
934
|
+
const removeWithUndo = useCallback4((id) => actions.removeItemWithUndo(id), [actions]);
|
|
935
|
+
const removeBatchWithUndo = useCallback4((ids) => actions.removeItemsWithUndo(ids), [actions]);
|
|
817
936
|
const updateTagsBatch = useCallback4(
|
|
818
937
|
(ids, nextTags) => actions.updateTagsBatch(ids, nextTags),
|
|
819
938
|
[actions]
|
|
@@ -841,6 +960,8 @@ function useKeepList(query = {}) {
|
|
|
841
960
|
error,
|
|
842
961
|
remove,
|
|
843
962
|
removeBatch,
|
|
963
|
+
removeWithUndo,
|
|
964
|
+
removeBatchWithUndo,
|
|
844
965
|
updateTagsBatch,
|
|
845
966
|
addTagsBatch,
|
|
846
967
|
removeTagsBatch,
|