@keepkit/core 0.19.0 → 0.21.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 +10 -2
- package/dist/{chunk-62I2YZYI.js → chunk-RSXYXT5D.js} +5 -4
- package/dist/chunk-RSXYXT5D.js.map +1 -0
- package/dist/{chunk-PNP7OALR.js → chunk-XUHRDJD6.js} +2 -2
- package/dist/chunk-XUHRDJD6.js.map +1 -0
- package/dist/core.d.ts +5 -5
- package/dist/core.js +17 -4
- package/dist/core.js.map +1 -1
- package/dist/react.d.ts +29 -7
- package/dist/react.js +136 -7
- package/dist/react.js.map +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/{scope-Dk5FTVz8.d.ts → scope-kVcPskvM.d.ts} +1 -1
- package/dist/storage.d.ts +3 -3
- package/dist/storage.js +1 -1
- package/dist/{store-Cm35R_ho.d.ts → store-CPc-CUd2.d.ts} +14 -2
- package/dist/{types-Aoc0Eyvk.d.ts → types-6ex9EBjM.d.ts} +10 -1
- package/package.json +1 -1
- package/dist/chunk-62I2YZYI.js.map +0 -1
- package/dist/chunk-PNP7OALR.js.map +0 -1
package/dist/core.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/features/items/presets.ts","../src/features/items/url.ts","../src/features/sync/integrations.ts","../src/features/sync/templates/auth-sync.ts"],"sourcesContent":["import { createBrowserStorageAdapter } from \"../../storage/index\";\nimport { SyncStorageAdapter } from \"../../storage/sync\";\nimport { exportItems } from \"../persistence/backup\";\nimport { createScopedStorageAdapter, type KeepScope } from \"../persistence/scope\";\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","import type { KeepPlugin, KeepPluginContext } from \"../items/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 { type BrowserStorageAdapterOptions, createBrowserStorageAdapter } from \"../../../storage\";\nimport { SyncStorageAdapter, type SyncStorageAdapterOptions } from \"../../../storage/sync\";\nimport type {\n KeepItem,\n KeepSyncAuthError,\n KeepSyncAuthStatus,\n KeepSyncState,\n RemoteSyncDriver,\n RemoteSyncResult,\n StorageAdapter,\n SyncCapableStorageAdapter,\n SyncOperation,\n SyncScope,\n} from \"../../items/types\";\nimport { KeepSyncAuthError as KeepSyncAuthErrorClass } from \"../../items/types\";\nimport { exportItems } from \"../../persistence/backup\";\nimport {\n createScopedStorageAdapter,\n getKeepScopeKey,\n isSameKeepScope,\n ScopedSyncQueueAdapter,\n} from \"../../persistence/scope\";\n\nexport type AuthenticatedSyncRequestContext<TMeta = Record<string, unknown>> = {\n token: string | null;\n scope?: SyncScope;\n operation?: SyncOperation<TMeta>;\n};\n\n/** Transport boundary for auth-aware requests; cookies and bearer tokens remain host concerns. */\nexport type AuthenticatedSyncTransport<TMeta = Record<string, unknown>> = {\n push: (\n operation: SyncOperation<TMeta>,\n context: AuthenticatedSyncRequestContext<TMeta>,\n ) => Promise<RemoteSyncResult<TMeta>>;\n pull?: (context: AuthenticatedSyncRequestContext<TMeta>) => Promise<KeepItem<TMeta>[]>;\n};\n\nexport type AuthenticatedSyncAuthContext<TMeta = Record<string, unknown>> = {\n operation?: SyncOperation<TMeta>;\n scope?: SyncScope;\n};\n\nexport type AuthenticatedSyncKitOptions<TMeta = Record<string, unknown>> = Omit<\n SyncStorageAdapterOptions<TMeta>,\n \"local\" | \"remote\" | \"scope\"\n> & {\n /** Optional custom local adapter. Browser storage is used when omitted. */\n local?: StorageAdapter<TMeta>;\n key?: BrowserStorageAdapterOptions[\"key\"];\n databaseName?: BrowserStorageAdapterOptions[\"databaseName\"];\n scope?: SyncScope;\n /** Resolve the active account or tenant before storage operations. */\n getScope?: () => SyncScope | undefined | Promise<SyncScope | undefined>;\n getAuthToken: () => Promise<string | null>;\n transport: AuthenticatedSyncTransport<TMeta>;\n onAuthError?: (error: KeepSyncAuthError<TMeta>, context: AuthenticatedSyncAuthContext<TMeta>) => void | Promise<void>;\n onReauthenticate?: (\n error: KeepSyncAuthError<TMeta>,\n context: AuthenticatedSyncAuthContext<TMeta>,\n ) => void | Promise<void>;\n onScopeChange?: (next: SyncScope | undefined, previous: SyncScope | undefined) => void | Promise<void>;\n};\n\nexport type AuthenticatedSyncKit<TMeta = Record<string, unknown>> = {\n readonly mode: \"sync\";\n readonly storage: SyncCapableStorageAdapter<TMeta>;\n readonly scope?: SyncScope;\n readonly scopeKey: string;\n getScope(): SyncScope | undefined;\n setScope(scope?: SyncScope): Promise<void>;\n subscribeScope(listener: () => void): () => void;\n exportBackup(): Promise<string>;\n dispose(): void;\n};\n\n/** Creates auth-independent sync wiring with per-request tokens and isolated account scopes. */\nexport function createAuthenticatedSyncKit<TMeta = Record<string, unknown>>(\n options: AuthenticatedSyncKitOptions<TMeta>,\n): AuthenticatedSyncKit<TMeta> {\n const controller = new AuthenticatedSyncStorageController(options);\n return {\n mode: \"sync\",\n storage: controller,\n get scope() {\n return controller.scope;\n },\n get scopeKey() {\n return controller.scopeKey;\n },\n getScope: () => controller.scope,\n setScope: (scope) => controller.setScope(scope),\n subscribeScope: (listener) => controller.subscribeScope(listener),\n exportBackup: () => controller.exportBackup(),\n dispose: () => controller.dispose(),\n };\n}\n\nclass AuthenticatedSyncStorageController<TMeta = Record<string, unknown>> implements SyncCapableStorageAdapter<TMeta> {\n private readonly options: AuthenticatedSyncKitOptions<TMeta>;\n private currentScope: SyncScope | undefined;\n private current: SyncStorageAdapter<TMeta>;\n private readonly scopeListeners = new Set<() => void>();\n private readonly dataListeners = new Set<() => void>();\n private readonly syncListeners = new Set<() => void>();\n private unsubscribeData: () => void = () => undefined;\n private unsubscribeSync: () => void = () => undefined;\n private transition = Promise.resolve();\n private disposed = false;\n\n constructor(options: AuthenticatedSyncKitOptions<TMeta>) {\n this.options = options;\n this.currentScope = options.scope;\n this.current = this.createAdapter(this.currentScope);\n this.attach(this.current);\n }\n\n get storageKey(): string | undefined {\n return this.current.storageKey;\n }\n\n get scope(): SyncScope | undefined {\n return this.currentScope;\n }\n\n get scopeKey(): string {\n return getKeepScopeKey(this.currentScope);\n }\n\n async getAll(): Promise<KeepItem<TMeta>[]> {\n await this.ensureScope();\n return this.current.getAll();\n }\n\n async set(item: KeepItem<TMeta>): Promise<void> {\n await this.ensureScope();\n return this.current.set(item);\n }\n\n async setMany(items: KeepItem<TMeta>[]): Promise<void> {\n await this.ensureScope();\n return this.current.setMany(items);\n }\n\n async remove(id: string): Promise<void> {\n await this.ensureScope();\n return this.current.remove(id);\n }\n\n async removeMany(ids: string[]): Promise<void> {\n await this.ensureScope();\n return this.current.removeMany(ids);\n }\n\n async clear(): Promise<void> {\n await this.ensureScope();\n return this.current.clear();\n }\n\n async merge(items: KeepItem<TMeta>[]): Promise<KeepItem<TMeta>[]> {\n await this.ensureScope();\n return this.current.merge(items);\n }\n\n subscribe(listener: () => void): () => void {\n this.dataListeners.add(listener);\n return () => this.dataListeners.delete(listener);\n }\n\n getSyncState(): KeepSyncState<TMeta> {\n return this.current.getSyncState();\n }\n\n subscribeSync(listener: () => void): () => void {\n this.syncListeners.add(listener);\n return () => this.syncListeners.delete(listener);\n }\n\n async flushSync(): Promise<void> {\n await this.ensureScope();\n return this.current.flushSync();\n }\n\n async retrySync(): Promise<void> {\n await this.ensureScope();\n return this.current.retrySync?.() ?? this.current.flushSync();\n }\n\n async resolveSyncConflict(\n id: string,\n resolution: \"local\" | \"remote\" | \"manual\",\n item?: KeepItem<TMeta>,\n ): Promise<void> {\n await this.ensureScope();\n if (!this.current.resolveSyncConflict) {\n throw new Error(\"The authenticated sync adapter does not support conflict resolution.\");\n }\n return this.current.resolveSyncConflict(id, resolution, item);\n }\n\n async setScope(nextScope?: SyncScope): Promise<void> {\n const run = this.transition.then(async () => {\n if (isSameKeepScope(this.currentScope, nextScope)) return;\n if (this.disposed) throw new Error(\"AuthenticatedSyncKit has been disposed.\");\n const previousScope = this.currentScope;\n this.unsubscribeData();\n this.unsubscribeSync();\n this.current.dispose?.();\n this.currentScope = nextScope;\n this.current = this.createAdapter(nextScope);\n this.attach(this.current);\n await this.options.onScopeChange?.(nextScope, previousScope);\n this.notify(this.scopeListeners);\n this.notify(this.dataListeners);\n this.notify(this.syncListeners);\n });\n this.transition = run.catch(() => undefined);\n return run;\n }\n\n subscribeScope(listener: () => void): () => void {\n this.scopeListeners.add(listener);\n return () => this.scopeListeners.delete(listener);\n }\n\n async exportBackup(): Promise<string> {\n await this.ensureScope();\n return exportItems(this.current);\n }\n\n dispose(): void {\n this.disposed = true;\n this.unsubscribeData();\n this.unsubscribeSync();\n this.current.dispose?.();\n this.scopeListeners.clear();\n this.dataListeners.clear();\n this.syncListeners.clear();\n }\n\n private createAdapter(scope: SyncScope | undefined): SyncStorageAdapter<TMeta> {\n const local = this.options.local\n ? scope\n ? createScopedStorageAdapter(this.options.local, scope)\n : this.options.local\n : createBrowserStorageAdapter<TMeta>({ key: this.options.key, databaseName: this.options.databaseName, scope });\n const queue =\n this.options.queue && scope ? new ScopedSyncQueueAdapter(this.options.queue, scope) : this.options.queue;\n const remote = createAuthenticatedRemote(this.options, scope);\n return new SyncStorageAdapter<TMeta>({\n ...this.options,\n local,\n remote,\n queue,\n scope,\n });\n }\n\n private attach(adapter: SyncStorageAdapter<TMeta>): void {\n this.unsubscribeData = adapter.subscribe?.(() => this.notify(this.dataListeners)) ?? (() => undefined);\n this.unsubscribeSync = adapter.subscribeSync(() => this.notify(this.syncListeners));\n }\n\n private async ensureScope(): Promise<void> {\n if (!this.options.getScope) return;\n await this.setScope(await this.options.getScope());\n }\n\n private notify(listeners: Set<() => void>): void {\n for (const listener of listeners) listener();\n }\n}\n\nfunction createAuthenticatedRemote<TMeta>(\n options: AuthenticatedSyncKitOptions<TMeta>,\n scope: SyncScope | undefined,\n): RemoteSyncDriver<TMeta> {\n const pull = options.transport.pull;\n return {\n push: async (operation) => {\n try {\n const token = await options.getAuthToken();\n return await options.transport.push(operation, { token, scope, operation });\n } catch (cause) {\n return handleAuthFailure(cause, options, { operation, scope });\n }\n },\n pull: pull\n ? async () => {\n try {\n const token = await options.getAuthToken();\n return await pull({ token, scope });\n } catch (cause) {\n return handleAuthFailure(cause, options, { scope });\n }\n }\n : undefined,\n };\n}\n\nasync function handleAuthFailure<TMeta>(\n cause: unknown,\n options: AuthenticatedSyncKitOptions<TMeta>,\n context: AuthenticatedSyncAuthContext<TMeta>,\n): Promise<never> {\n const status = getAuthStatus(cause);\n if (!status) throw cause;\n const error =\n cause instanceof KeepSyncAuthErrorClass\n ? cause\n : new KeepSyncAuthErrorClass(status, { operation: context.operation, scope: context.scope, cause });\n await options.onAuthError?.(error, context);\n await options.onReauthenticate?.(error, context);\n throw error;\n}\n\nfunction getAuthStatus(error: unknown): KeepSyncAuthStatus | undefined {\n if (error instanceof KeepSyncAuthErrorClass) return error.status;\n if (!error || typeof error !== \"object\") return undefined;\n const candidate = error as { status?: unknown; response?: { status?: unknown }; cause?: unknown };\n if (candidate.status === 401 || candidate.status === 403) return candidate.status;\n if (candidate.response?.status === 401 || candidate.response?.status === 403) return candidate.response.status;\n return candidate.cause ? getAuthStatus(candidate.cause) : undefined;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/features/items/presets.ts","../src/features/items/url.ts","../src/features/sync/integrations.ts","../src/features/sync/templates/auth-sync.ts"],"sourcesContent":["import { createBrowserStorageAdapter } from \"../../storage/index\";\nimport { SyncStorageAdapter } from \"../../storage/sync\";\nimport { exportItems } from \"../persistence/backup\";\nimport { createScopedStorageAdapter, type KeepScope } from \"../persistence/scope\";\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 archived: string;\n collection: string;\n pinnedFirst: 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 archived: \"archived\",\n collection: \"collection\",\n pinnedFirst: \"pinned\",\n};\n\nexport type KeepUrlState = Pick<\n KeepListQuery,\n \"search\" | \"tags\" | \"sort\" | \"pagination\" | \"archived\" | \"collectionId\" | \"pinnedFirst\"\n>;\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 if (query.archived !== undefined) result.set(params.archived, query.archived ? \"true\" : \"false\");\n if (query.collectionId) result.set(params.collection, query.collectionId);\n if (query.pinnedFirst) result.set(params.pinnedFirst, \"true\");\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 const archivedValue = searchParams.get(params.archived);\n const archived = archivedValue === \"true\" ? true : archivedValue === \"false\" ? false : undefined;\n const collectionId = searchParams.get(params.collection)?.trim() || undefined;\n const pinnedFirst = searchParams.get(params.pinnedFirst) === \"true\" ? true : undefined;\n return {\n ...(search ? { search: { query: search } } : {}),\n ...(tags.length > 0 ? { tags } : {}),\n ...(sort ? { sort } : {}),\n ...(page ? { pagination: { page } } : {}),\n ...(archived === undefined ? {} : { archived }),\n ...(collectionId ? { collectionId } : {}),\n ...(pinnedFirst ? { pinnedFirst } : {}),\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","import type { KeepPlugin, KeepPluginContext } from \"../items/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 { type BrowserStorageAdapterOptions, createBrowserStorageAdapter } from \"../../../storage\";\nimport { SyncStorageAdapter, type SyncStorageAdapterOptions } from \"../../../storage/sync\";\nimport type {\n KeepItem,\n KeepSyncAuthError,\n KeepSyncAuthStatus,\n KeepSyncState,\n RemoteSyncDriver,\n RemoteSyncResult,\n StorageAdapter,\n SyncCapableStorageAdapter,\n SyncOperation,\n SyncScope,\n} from \"../../items/types\";\nimport { KeepSyncAuthError as KeepSyncAuthErrorClass } from \"../../items/types\";\nimport { exportItems } from \"../../persistence/backup\";\nimport {\n createScopedStorageAdapter,\n getKeepScopeKey,\n isSameKeepScope,\n ScopedSyncQueueAdapter,\n} from \"../../persistence/scope\";\n\nexport type AuthenticatedSyncRequestContext<TMeta = Record<string, unknown>> = {\n token: string | null;\n scope?: SyncScope;\n operation?: SyncOperation<TMeta>;\n};\n\n/** Transport boundary for auth-aware requests; cookies and bearer tokens remain host concerns. */\nexport type AuthenticatedSyncTransport<TMeta = Record<string, unknown>> = {\n push: (\n operation: SyncOperation<TMeta>,\n context: AuthenticatedSyncRequestContext<TMeta>,\n ) => Promise<RemoteSyncResult<TMeta>>;\n pull?: (context: AuthenticatedSyncRequestContext<TMeta>) => Promise<KeepItem<TMeta>[]>;\n};\n\nexport type AuthenticatedSyncAuthContext<TMeta = Record<string, unknown>> = {\n operation?: SyncOperation<TMeta>;\n scope?: SyncScope;\n};\n\nexport type AuthenticatedSyncKitOptions<TMeta = Record<string, unknown>> = Omit<\n SyncStorageAdapterOptions<TMeta>,\n \"local\" | \"remote\" | \"scope\"\n> & {\n /** Optional custom local adapter. Browser storage is used when omitted. */\n local?: StorageAdapter<TMeta>;\n key?: BrowserStorageAdapterOptions[\"key\"];\n databaseName?: BrowserStorageAdapterOptions[\"databaseName\"];\n scope?: SyncScope;\n /** Resolve the active account or tenant before storage operations. */\n getScope?: () => SyncScope | undefined | Promise<SyncScope | undefined>;\n getAuthToken: () => Promise<string | null>;\n transport: AuthenticatedSyncTransport<TMeta>;\n onAuthError?: (error: KeepSyncAuthError<TMeta>, context: AuthenticatedSyncAuthContext<TMeta>) => void | Promise<void>;\n onReauthenticate?: (\n error: KeepSyncAuthError<TMeta>,\n context: AuthenticatedSyncAuthContext<TMeta>,\n ) => void | Promise<void>;\n onScopeChange?: (next: SyncScope | undefined, previous: SyncScope | undefined) => void | Promise<void>;\n};\n\nexport type AuthenticatedSyncKit<TMeta = Record<string, unknown>> = {\n readonly mode: \"sync\";\n readonly storage: SyncCapableStorageAdapter<TMeta>;\n readonly scope?: SyncScope;\n readonly scopeKey: string;\n getScope(): SyncScope | undefined;\n setScope(scope?: SyncScope): Promise<void>;\n subscribeScope(listener: () => void): () => void;\n exportBackup(): Promise<string>;\n dispose(): void;\n};\n\n/** Creates auth-independent sync wiring with per-request tokens and isolated account scopes. */\nexport function createAuthenticatedSyncKit<TMeta = Record<string, unknown>>(\n options: AuthenticatedSyncKitOptions<TMeta>,\n): AuthenticatedSyncKit<TMeta> {\n const controller = new AuthenticatedSyncStorageController(options);\n return {\n mode: \"sync\",\n storage: controller,\n get scope() {\n return controller.scope;\n },\n get scopeKey() {\n return controller.scopeKey;\n },\n getScope: () => controller.scope,\n setScope: (scope) => controller.setScope(scope),\n subscribeScope: (listener) => controller.subscribeScope(listener),\n exportBackup: () => controller.exportBackup(),\n dispose: () => controller.dispose(),\n };\n}\n\nclass AuthenticatedSyncStorageController<TMeta = Record<string, unknown>> implements SyncCapableStorageAdapter<TMeta> {\n private readonly options: AuthenticatedSyncKitOptions<TMeta>;\n private currentScope: SyncScope | undefined;\n private current: SyncStorageAdapter<TMeta>;\n private readonly scopeListeners = new Set<() => void>();\n private readonly dataListeners = new Set<() => void>();\n private readonly syncListeners = new Set<() => void>();\n private unsubscribeData: () => void = () => undefined;\n private unsubscribeSync: () => void = () => undefined;\n private transition = Promise.resolve();\n private disposed = false;\n\n constructor(options: AuthenticatedSyncKitOptions<TMeta>) {\n this.options = options;\n this.currentScope = options.scope;\n this.current = this.createAdapter(this.currentScope);\n this.attach(this.current);\n }\n\n get storageKey(): string | undefined {\n return this.current.storageKey;\n }\n\n get scope(): SyncScope | undefined {\n return this.currentScope;\n }\n\n get scopeKey(): string {\n return getKeepScopeKey(this.currentScope);\n }\n\n async getAll(): Promise<KeepItem<TMeta>[]> {\n await this.ensureScope();\n return this.current.getAll();\n }\n\n async set(item: KeepItem<TMeta>): Promise<void> {\n await this.ensureScope();\n return this.current.set(item);\n }\n\n async setMany(items: KeepItem<TMeta>[]): Promise<void> {\n await this.ensureScope();\n return this.current.setMany(items);\n }\n\n async remove(id: string): Promise<void> {\n await this.ensureScope();\n return this.current.remove(id);\n }\n\n async removeMany(ids: string[]): Promise<void> {\n await this.ensureScope();\n return this.current.removeMany(ids);\n }\n\n async clear(): Promise<void> {\n await this.ensureScope();\n return this.current.clear();\n }\n\n async merge(items: KeepItem<TMeta>[]): Promise<KeepItem<TMeta>[]> {\n await this.ensureScope();\n return this.current.merge(items);\n }\n\n subscribe(listener: () => void): () => void {\n this.dataListeners.add(listener);\n return () => this.dataListeners.delete(listener);\n }\n\n getSyncState(): KeepSyncState<TMeta> {\n return this.current.getSyncState();\n }\n\n subscribeSync(listener: () => void): () => void {\n this.syncListeners.add(listener);\n return () => this.syncListeners.delete(listener);\n }\n\n async flushSync(): Promise<void> {\n await this.ensureScope();\n return this.current.flushSync();\n }\n\n async retrySync(): Promise<void> {\n await this.ensureScope();\n return this.current.retrySync?.() ?? this.current.flushSync();\n }\n\n async resolveSyncConflict(\n id: string,\n resolution: \"local\" | \"remote\" | \"manual\",\n item?: KeepItem<TMeta>,\n ): Promise<void> {\n await this.ensureScope();\n if (!this.current.resolveSyncConflict) {\n throw new Error(\"The authenticated sync adapter does not support conflict resolution.\");\n }\n return this.current.resolveSyncConflict(id, resolution, item);\n }\n\n async setScope(nextScope?: SyncScope): Promise<void> {\n const run = this.transition.then(async () => {\n if (isSameKeepScope(this.currentScope, nextScope)) return;\n if (this.disposed) throw new Error(\"AuthenticatedSyncKit has been disposed.\");\n const previousScope = this.currentScope;\n this.unsubscribeData();\n this.unsubscribeSync();\n this.current.dispose?.();\n this.currentScope = nextScope;\n this.current = this.createAdapter(nextScope);\n this.attach(this.current);\n await this.options.onScopeChange?.(nextScope, previousScope);\n this.notify(this.scopeListeners);\n this.notify(this.dataListeners);\n this.notify(this.syncListeners);\n });\n this.transition = run.catch(() => undefined);\n return run;\n }\n\n subscribeScope(listener: () => void): () => void {\n this.scopeListeners.add(listener);\n return () => this.scopeListeners.delete(listener);\n }\n\n async exportBackup(): Promise<string> {\n await this.ensureScope();\n return exportItems(this.current);\n }\n\n dispose(): void {\n this.disposed = true;\n this.unsubscribeData();\n this.unsubscribeSync();\n this.current.dispose?.();\n this.scopeListeners.clear();\n this.dataListeners.clear();\n this.syncListeners.clear();\n }\n\n private createAdapter(scope: SyncScope | undefined): SyncStorageAdapter<TMeta> {\n const local = this.options.local\n ? scope\n ? createScopedStorageAdapter(this.options.local, scope)\n : this.options.local\n : createBrowserStorageAdapter<TMeta>({ key: this.options.key, databaseName: this.options.databaseName, scope });\n const queue =\n this.options.queue && scope ? new ScopedSyncQueueAdapter(this.options.queue, scope) : this.options.queue;\n const remote = createAuthenticatedRemote(this.options, scope);\n return new SyncStorageAdapter<TMeta>({\n ...this.options,\n local,\n remote,\n queue,\n scope,\n });\n }\n\n private attach(adapter: SyncStorageAdapter<TMeta>): void {\n this.unsubscribeData = adapter.subscribe?.(() => this.notify(this.dataListeners)) ?? (() => undefined);\n this.unsubscribeSync = adapter.subscribeSync(() => this.notify(this.syncListeners));\n }\n\n private async ensureScope(): Promise<void> {\n if (!this.options.getScope) return;\n await this.setScope(await this.options.getScope());\n }\n\n private notify(listeners: Set<() => void>): void {\n for (const listener of listeners) listener();\n }\n}\n\nfunction createAuthenticatedRemote<TMeta>(\n options: AuthenticatedSyncKitOptions<TMeta>,\n scope: SyncScope | undefined,\n): RemoteSyncDriver<TMeta> {\n const pull = options.transport.pull;\n return {\n push: async (operation) => {\n try {\n const token = await options.getAuthToken();\n return await options.transport.push(operation, { token, scope, operation });\n } catch (cause) {\n return handleAuthFailure(cause, options, { operation, scope });\n }\n },\n pull: pull\n ? async () => {\n try {\n const token = await options.getAuthToken();\n return await pull({ token, scope });\n } catch (cause) {\n return handleAuthFailure(cause, options, { scope });\n }\n }\n : undefined,\n };\n}\n\nasync function handleAuthFailure<TMeta>(\n cause: unknown,\n options: AuthenticatedSyncKitOptions<TMeta>,\n context: AuthenticatedSyncAuthContext<TMeta>,\n): Promise<never> {\n const status = getAuthStatus(cause);\n if (!status) throw cause;\n const error =\n cause instanceof KeepSyncAuthErrorClass\n ? cause\n : new KeepSyncAuthErrorClass(status, { operation: context.operation, scope: context.scope, cause });\n await options.onAuthError?.(error, context);\n await options.onReauthenticate?.(error, context);\n throw error;\n}\n\nfunction getAuthStatus(error: unknown): KeepSyncAuthStatus | undefined {\n if (error instanceof KeepSyncAuthErrorClass) return error.status;\n if (!error || typeof error !== \"object\") return undefined;\n const candidate = error as { status?: unknown; response?: { status?: unknown }; cause?: unknown };\n if (candidate.status === 401 || candidate.status === 403) return candidate.status;\n if (candidate.response?.status === 401 || candidate.response?.status === 403) return candidate.response.status;\n return candidate.cause ? getAuthStatus(candidate.cause) : undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BO,SAAS,oBACd,UAAuC,CAAC,GACnB;AACrB,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,QAAQ,QAAQ,UAClB,QAAQ,QACN,2BAA2B,QAAQ,SAAS,QAAQ,KAAK,IACzD,QAAQ,UACV,4BAAmC,EAAE,KAAK,QAAQ,KAAK,OAAO,QAAQ,MAAM,CAAC;AACjF,MAAI,SAAS,UAAU,CAAC,QAAQ,QAAQ;AACtC,UAAM,IAAI,MAAM,iEAAiE;AAAA,EACnF;AACA,MAAI,UAAiC;AACrC,MAAI,SAAS,QAAQ;AACnB,UAAM,SAAS,QAAQ;AACvB,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,iEAAiE;AAC9F,cAAU,IAAI,mBAA0B;AAAA,MACtC;AAAA,MACA;AAAA,MACA,QAAQ,QAAQ,OAAO;AAAA,MACvB,UAAU,QAAQ,OAAO;AAAA,IAC3B,CAAC;AAAA,EACH;AACA,SAAO;AAAA,IACL;AAAA,IACA,OAAO,QAAQ;AAAA,IACf;AAAA,IACA,cAAc,MAAM,YAAY,OAAO;AAAA,EACzC;AACF;AAEO,IAAM,qBAAqB;;;ACrC3B,IAAM,0BAA6C;AAAA,EACxD,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,aAAa;AACf;AAQO,SAAS,oBACd,QAA8B,CAAC,GAC/B,UAA8C,CAAC,GAC9B;AACjB,QAAM,SAAS,EAAE,GAAG,yBAAyB,GAAG,QAAQ,OAAO;AAC/D,QAAM,SAAS,IAAI,gBAAgB;AACnC,QAAM,SAAS,MAAM,QAAQ,OAAO,KAAK;AACzC,MAAI,OAAQ,QAAO,IAAI,OAAO,QAAQ,MAAM;AAC5C,aAAW,OAAO,MAAM,QAAQ,CAAC,GAAG;AAClC,UAAM,aAAa,IAAI,KAAK;AAC5B,QAAI,WAAY,QAAO,OAAO,OAAO,MAAM,UAAU;AAAA,EACvD;AACA,MAAI,MAAM,MAAM,GAAI,QAAO,IAAI,OAAO,MAAM,GAAG,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK,aAAa,MAAM,EAAE;AAChG,QAAM,OAAO,MAAM,YAAY;AAC/B,MAAI,SAAS,UAAa,OAAO,SAAS,IAAI,KAAK,OAAO,EAAG,QAAO,IAAI,OAAO,MAAM,OAAO,KAAK,MAAM,IAAI,CAAC,CAAC;AAC7G,MAAI,MAAM,aAAa,OAAW,QAAO,IAAI,OAAO,UAAU,MAAM,WAAW,SAAS,OAAO;AAC/F,MAAI,MAAM,aAAc,QAAO,IAAI,OAAO,YAAY,MAAM,YAAY;AACxE,MAAI,MAAM,YAAa,QAAO,IAAI,OAAO,aAAa,MAAM;AAC5D,SAAO;AACT;AAGO,SAAS,oBACd,OACA,UAA8C,CAAC,GACjC;AACd,QAAM,SAAS,EAAE,GAAG,yBAAyB,GAAG,QAAQ,OAAO;AAC/D,QAAM,eAAe,iBAAiB,kBAAkB,QAAQ,IAAI,IAAI,OAAO,wBAAwB,EAAE;AACzG,QAAM,SAAS,aAAa,IAAI,OAAO,MAAM,GAAG,KAAK;AACrD,QAAM,OAAO;AAAA,IACX,GAAG,IAAI;AAAA,MACL,aACG,OAAO,OAAO,IAAI,EAClB,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,EACvB,OAAO,OAAO;AAAA,IACnB;AAAA,EACF;AACA,QAAM,YAAY,aAAa,IAAI,OAAO,IAAI,GAAG,MAAM,GAAG;AAC1D,QAAM,OACJ,YAAY,CAAC,MAAM,aAAa,YAAY,CAAC,MAAM,cAC/C;AAAA,IACE,IAAI,UAAU,CAAC;AAAA,IACf,WAAW,UAAU,CAAC,MAAM,QAAS,QAAmB;AAAA,EAC1D,IACA;AACN,QAAM,UAAU,OAAO,aAAa,IAAI,OAAO,IAAI,CAAC;AACpD,QAAM,OAAO,OAAO,UAAU,OAAO,KAAK,UAAU,IAAI,UAAU;AAClE,QAAM,gBAAgB,aAAa,IAAI,OAAO,QAAQ;AACtD,QAAM,WAAW,kBAAkB,SAAS,OAAO,kBAAkB,UAAU,QAAQ;AACvF,QAAM,eAAe,aAAa,IAAI,OAAO,UAAU,GAAG,KAAK,KAAK;AACpE,QAAM,cAAc,aAAa,IAAI,OAAO,WAAW,MAAM,SAAS,OAAO;AAC7E,SAAO;AAAA,IACL,GAAI,SAAS,EAAE,QAAQ,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC;AAAA,IAC9C,GAAI,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,IAClC,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IACvB,GAAI,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,IAAI,CAAC;AAAA,IACvC,GAAI,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS;AAAA,IAC7C,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,IACvC,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,EACvC;AACF;AAEO,SAAS,uBACd,QAA8B,CAAC,GAC/B,UAA8C,CAAC,GACvC;AACR,QAAM,QAAQ,oBAAoB,OAAO,OAAO,EAAE,SAAS;AAC3D,SAAO,QAAQ,IAAI,KAAK,KAAK;AAC/B;AAEO,SAAS,0BACd,OACA,OACA,UAA8C,CAAC,GACzB;AACtB,QAAM,UAAU,oBAAoB,OAAO,OAAO;AAClD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG;AAAA,IACH,QAAQ,QAAQ,UAAU,MAAM;AAAA,IAChC,MAAM,QAAQ,QAAQ,MAAM;AAAA,IAC5B,MAAM,QAAQ,QAAQ,MAAM;AAAA,IAC5B,YAAY,QAAQ,aAAa,EAAE,GAAG,MAAM,YAAY,GAAG,QAAQ,WAAW,IAAI,MAAM;AAAA,EAC1F;AACF;;;AC9GO,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;;;ACwDO,SAAS,2BACd,SAC6B;AAC7B,QAAM,aAAa,IAAI,mCAAmC,OAAO;AACjE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,IAAI,QAAQ;AACV,aAAO,WAAW;AAAA,IACpB;AAAA,IACA,IAAI,WAAW;AACb,aAAO,WAAW;AAAA,IACpB;AAAA,IACA,UAAU,MAAM,WAAW;AAAA,IAC3B,UAAU,CAAC,UAAU,WAAW,SAAS,KAAK;AAAA,IAC9C,gBAAgB,CAAC,aAAa,WAAW,eAAe,QAAQ;AAAA,IAChE,cAAc,MAAM,WAAW,aAAa;AAAA,IAC5C,SAAS,MAAM,WAAW,QAAQ;AAAA,EACpC;AACF;AAEA,IAAM,qCAAN,MAAsH;AAAA,EAYpH,YAAY,SAA6C;AARzD,SAAiB,iBAAiB,oBAAI,IAAgB;AACtD,SAAiB,gBAAgB,oBAAI,IAAgB;AACrD,SAAiB,gBAAgB,oBAAI,IAAgB;AACrD,SAAQ,kBAA8B,MAAM;AAC5C,SAAQ,kBAA8B,MAAM;AAC5C,SAAQ,aAAa,QAAQ,QAAQ;AACrC,SAAQ,WAAW;AAGjB,SAAK,UAAU;AACf,SAAK,eAAe,QAAQ;AAC5B,SAAK,UAAU,KAAK,cAAc,KAAK,YAAY;AACnD,SAAK,OAAO,KAAK,OAAO;AAAA,EAC1B;AAAA,EAEA,IAAI,aAAiC;AACnC,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA,EAEA,IAAI,QAA+B;AACjC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,WAAmB;AACrB,WAAO,gBAAgB,KAAK,YAAY;AAAA,EAC1C;AAAA,EAEA,MAAM,SAAqC;AACzC,UAAM,KAAK,YAAY;AACvB,WAAO,KAAK,QAAQ,OAAO;AAAA,EAC7B;AAAA,EAEA,MAAM,IAAI,MAAsC;AAC9C,UAAM,KAAK,YAAY;AACvB,WAAO,KAAK,QAAQ,IAAI,IAAI;AAAA,EAC9B;AAAA,EAEA,MAAM,QAAQ,OAAyC;AACrD,UAAM,KAAK,YAAY;AACvB,WAAO,KAAK,QAAQ,QAAQ,KAAK;AAAA,EACnC;AAAA,EAEA,MAAM,OAAO,IAA2B;AACtC,UAAM,KAAK,YAAY;AACvB,WAAO,KAAK,QAAQ,OAAO,EAAE;AAAA,EAC/B;AAAA,EAEA,MAAM,WAAW,KAA8B;AAC7C,UAAM,KAAK,YAAY;AACvB,WAAO,KAAK,QAAQ,WAAW,GAAG;AAAA,EACpC;AAAA,EAEA,MAAM,QAAuB;AAC3B,UAAM,KAAK,YAAY;AACvB,WAAO,KAAK,QAAQ,MAAM;AAAA,EAC5B;AAAA,EAEA,MAAM,MAAM,OAAsD;AAChE,UAAM,KAAK,YAAY;AACvB,WAAO,KAAK,QAAQ,MAAM,KAAK;AAAA,EACjC;AAAA,EAEA,UAAU,UAAkC;AAC1C,SAAK,cAAc,IAAI,QAAQ;AAC/B,WAAO,MAAM,KAAK,cAAc,OAAO,QAAQ;AAAA,EACjD;AAAA,EAEA,eAAqC;AACnC,WAAO,KAAK,QAAQ,aAAa;AAAA,EACnC;AAAA,EAEA,cAAc,UAAkC;AAC9C,SAAK,cAAc,IAAI,QAAQ;AAC/B,WAAO,MAAM,KAAK,cAAc,OAAO,QAAQ;AAAA,EACjD;AAAA,EAEA,MAAM,YAA2B;AAC/B,UAAM,KAAK,YAAY;AACvB,WAAO,KAAK,QAAQ,UAAU;AAAA,EAChC;AAAA,EAEA,MAAM,YAA2B;AAC/B,UAAM,KAAK,YAAY;AACvB,WAAO,KAAK,QAAQ,YAAY,KAAK,KAAK,QAAQ,UAAU;AAAA,EAC9D;AAAA,EAEA,MAAM,oBACJ,IACA,YACA,MACe;AACf,UAAM,KAAK,YAAY;AACvB,QAAI,CAAC,KAAK,QAAQ,qBAAqB;AACrC,YAAM,IAAI,MAAM,sEAAsE;AAAA,IACxF;AACA,WAAO,KAAK,QAAQ,oBAAoB,IAAI,YAAY,IAAI;AAAA,EAC9D;AAAA,EAEA,MAAM,SAAS,WAAsC;AACnD,UAAM,MAAM,KAAK,WAAW,KAAK,YAAY;AAC3C,UAAI,gBAAgB,KAAK,cAAc,SAAS,EAAG;AACnD,UAAI,KAAK,SAAU,OAAM,IAAI,MAAM,yCAAyC;AAC5E,YAAM,gBAAgB,KAAK;AAC3B,WAAK,gBAAgB;AACrB,WAAK,gBAAgB;AACrB,WAAK,QAAQ,UAAU;AACvB,WAAK,eAAe;AACpB,WAAK,UAAU,KAAK,cAAc,SAAS;AAC3C,WAAK,OAAO,KAAK,OAAO;AACxB,YAAM,KAAK,QAAQ,gBAAgB,WAAW,aAAa;AAC3D,WAAK,OAAO,KAAK,cAAc;AAC/B,WAAK,OAAO,KAAK,aAAa;AAC9B,WAAK,OAAO,KAAK,aAAa;AAAA,IAChC,CAAC;AACD,SAAK,aAAa,IAAI,MAAM,MAAM,MAAS;AAC3C,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,UAAkC;AAC/C,SAAK,eAAe,IAAI,QAAQ;AAChC,WAAO,MAAM,KAAK,eAAe,OAAO,QAAQ;AAAA,EAClD;AAAA,EAEA,MAAM,eAAgC;AACpC,UAAM,KAAK,YAAY;AACvB,WAAO,YAAY,KAAK,OAAO;AAAA,EACjC;AAAA,EAEA,UAAgB;AACd,SAAK,WAAW;AAChB,SAAK,gBAAgB;AACrB,SAAK,gBAAgB;AACrB,SAAK,QAAQ,UAAU;AACvB,SAAK,eAAe,MAAM;AAC1B,SAAK,cAAc,MAAM;AACzB,SAAK,cAAc,MAAM;AAAA,EAC3B;AAAA,EAEQ,cAAc,OAAyD;AAC7E,UAAM,QAAQ,KAAK,QAAQ,QACvB,QACE,2BAA2B,KAAK,QAAQ,OAAO,KAAK,IACpD,KAAK,QAAQ,QACf,4BAAmC,EAAE,KAAK,KAAK,QAAQ,KAAK,cAAc,KAAK,QAAQ,cAAc,MAAM,CAAC;AAChH,UAAM,QACJ,KAAK,QAAQ,SAAS,QAAQ,IAAI,uBAAuB,KAAK,QAAQ,OAAO,KAAK,IAAI,KAAK,QAAQ;AACrG,UAAM,SAAS,0BAA0B,KAAK,SAAS,KAAK;AAC5D,WAAO,IAAI,mBAA0B;AAAA,MACnC,GAAG,KAAK;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,OAAO,SAA0C;AACvD,SAAK,kBAAkB,QAAQ,YAAY,MAAM,KAAK,OAAO,KAAK,aAAa,CAAC,MAAM,MAAM;AAC5F,SAAK,kBAAkB,QAAQ,cAAc,MAAM,KAAK,OAAO,KAAK,aAAa,CAAC;AAAA,EACpF;AAAA,EAEA,MAAc,cAA6B;AACzC,QAAI,CAAC,KAAK,QAAQ,SAAU;AAC5B,UAAM,KAAK,SAAS,MAAM,KAAK,QAAQ,SAAS,CAAC;AAAA,EACnD;AAAA,EAEQ,OAAO,WAAkC;AAC/C,eAAW,YAAY,UAAW,UAAS;AAAA,EAC7C;AACF;AAEA,SAAS,0BACP,SACA,OACyB;AACzB,QAAM,OAAO,QAAQ,UAAU;AAC/B,SAAO;AAAA,IACL,MAAM,OAAO,cAAc;AACzB,UAAI;AACF,cAAM,QAAQ,MAAM,QAAQ,aAAa;AACzC,eAAO,MAAM,QAAQ,UAAU,KAAK,WAAW,EAAE,OAAO,OAAO,UAAU,CAAC;AAAA,MAC5E,SAAS,OAAO;AACd,eAAO,kBAAkB,OAAO,SAAS,EAAE,WAAW,MAAM,CAAC;AAAA,MAC/D;AAAA,IACF;AAAA,IACA,MAAM,OACF,YAAY;AACV,UAAI;AACF,cAAM,QAAQ,MAAM,QAAQ,aAAa;AACzC,eAAO,MAAM,KAAK,EAAE,OAAO,MAAM,CAAC;AAAA,MACpC,SAAS,OAAO;AACd,eAAO,kBAAkB,OAAO,SAAS,EAAE,MAAM,CAAC;AAAA,MACpD;AAAA,IACF,IACA;AAAA,EACN;AACF;AAEA,eAAe,kBACb,OACA,SACA,SACgB;AAChB,QAAM,SAAS,cAAc,KAAK;AAClC,MAAI,CAAC,OAAQ,OAAM;AACnB,QAAM,QACJ,iBAAiB,oBACb,QACA,IAAI,kBAAuB,QAAQ,EAAE,WAAW,QAAQ,WAAW,OAAO,QAAQ,OAAO,MAAM,CAAC;AACtG,QAAM,QAAQ,cAAc,OAAO,OAAO;AAC1C,QAAM,QAAQ,mBAAmB,OAAO,OAAO;AAC/C,QAAM;AACR;AAEA,SAAS,cAAc,OAAgD;AACrE,MAAI,iBAAiB,kBAAwB,QAAO,MAAM;AAC1D,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,YAAY;AAClB,MAAI,UAAU,WAAW,OAAO,UAAU,WAAW,IAAK,QAAO,UAAU;AAC3E,MAAI,UAAU,UAAU,WAAW,OAAO,UAAU,UAAU,WAAW,IAAK,QAAO,UAAU,SAAS;AACxG,SAAO,UAAU,QAAQ,cAAc,UAAU,KAAK,IAAI;AAC5D;","names":[]}
|
package/dist/react.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { g as KeepItemMetadataRefresher, l as KeepItemRevalidator, h as KeepItemResolver, c as KeepAutoRevalidationOptions, R as RevalidateKeepItemsOptions, k as KeepItemRevalidationSummary, I as ImportItemsOptions, a as ImportItemsResult, o as KeepStore, p as KeepStoreActions, m as KeepListQuery, n as KeepNavigationState } from './store-
|
|
2
|
-
export { j as KeepItemRevalidationResult, r as KeepUrlParamNames, s as KeepUrlState, t as KeepUrlSyncOptions, A as isKeepItemMetadataStale } from './store-
|
|
3
|
-
import { r as KeepItemInput, K as KeepItem, p as KeepEventHandlers, a as StorageAdapter, e as KeepPlugin, t as KeepSchema, q as KeepInvalidItemPolicy, j as KeepChangeContext, D as KeepSyncState, F as KeepUndoState } from './types-
|
|
4
|
-
export { s as KeepItemStatus } from './types-
|
|
5
|
-
export { K as KeepScope, S as ScopedStorageAdapter } from './scope-
|
|
1
|
+
import { g as KeepItemMetadataRefresher, l as KeepItemRevalidator, h as KeepItemResolver, c as KeepAutoRevalidationOptions, R as RevalidateKeepItemsOptions, k as KeepItemRevalidationSummary, I as ImportItemsOptions, a as ImportItemsResult, o as KeepStore, p as KeepStoreActions, m as KeepListQuery, n as KeepNavigationState } from './store-CPc-CUd2.js';
|
|
2
|
+
export { j as KeepItemRevalidationResult, r as KeepUrlParamNames, s as KeepUrlState, t as KeepUrlSyncOptions, A as isKeepItemMetadataStale } from './store-CPc-CUd2.js';
|
|
3
|
+
import { r as KeepItemInput, K as KeepItem, p as KeepEventHandlers, a as StorageAdapter, e as KeepPlugin, t as KeepSchema, q as KeepInvalidItemPolicy, j as KeepChangeContext, D as KeepSyncState, F as KeepUndoState } from './types-6ex9EBjM.js';
|
|
4
|
+
export { s as KeepItemStatus } from './types-6ex9EBjM.js';
|
|
5
|
+
export { K as KeepScope, S as ScopedStorageAdapter } from './scope-kVcPskvM.js';
|
|
6
6
|
import * as react from 'react';
|
|
7
|
-
import { ReactNode, ButtonHTMLAttributes, MouseEvent, HTMLAttributes, ReactElement, ErrorInfo, Component, PropsWithChildren, ComponentType } from 'react';
|
|
7
|
+
import { ReactNode, Ref, ButtonHTMLAttributes, MouseEvent, HTMLAttributes, ReactElement, ErrorInfo, Component, PropsWithChildren, ComponentType } from 'react';
|
|
8
8
|
|
|
9
9
|
type UseKeepItemResult<TMeta = Record<string, unknown>> = {
|
|
10
10
|
item: KeepItem<TMeta> | undefined;
|
|
@@ -19,6 +19,13 @@ type UseKeepItemResult<TMeta = Record<string, unknown>> = {
|
|
|
19
19
|
toggle: () => Promise<void>;
|
|
20
20
|
updateNote: (note?: string) => Promise<void>;
|
|
21
21
|
updateTags: (tags?: string[]) => Promise<void>;
|
|
22
|
+
toggleArchive: () => Promise<void>;
|
|
23
|
+
archiveItem: () => Promise<void>;
|
|
24
|
+
unarchiveItem: () => Promise<void>;
|
|
25
|
+
archive: () => Promise<void>;
|
|
26
|
+
unarchive: () => Promise<void>;
|
|
27
|
+
togglePin: () => Promise<void>;
|
|
28
|
+
moveToCollection: (collectionId?: string) => Promise<void>;
|
|
22
29
|
refreshMetadata: (refresh: KeepItemMetadataRefresher<TMeta>) => Promise<void>;
|
|
23
30
|
};
|
|
24
31
|
/** Read and mutate one saved item from its complete minimal input description. */
|
|
@@ -35,6 +42,9 @@ type KeepButtonSharedProps<TMeta> = {
|
|
|
35
42
|
getAriaLabel?: (state: KeepButtonState<TMeta>) => string;
|
|
36
43
|
disabled?: boolean;
|
|
37
44
|
onToggleError?: (error: unknown) => void;
|
|
45
|
+
ref?: Ref<HTMLElement> | {
|
|
46
|
+
readonly current: unknown;
|
|
47
|
+
};
|
|
38
48
|
};
|
|
39
49
|
type KeepButtonProps<TMeta = Record<string, unknown>> = KeepButtonSharedProps<TMeta> & ((Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children" | "onClick" | "aria-pressed"> & {
|
|
40
50
|
asChild?: false;
|
|
@@ -57,7 +67,7 @@ type KeepButtonState<TMeta = Record<string, unknown>> = {
|
|
|
57
67
|
updateTags: (tags?: string[]) => Promise<void>;
|
|
58
68
|
};
|
|
59
69
|
/** A style-free accessible save toggle. Consumers provide all visual styling. */
|
|
60
|
-
declare function KeepButton<TMeta = Record<string, unknown>>({ item, children, savedLabel, unsavedLabel, savedAriaLabel, unsavedAriaLabel, getAriaLabel, asChild, onToggleError, onClick, disabled, ...buttonProps }: KeepButtonProps<TMeta>): react.JSX.Element;
|
|
70
|
+
declare function KeepButton<TMeta = Record<string, unknown>>({ item, children, savedLabel, unsavedLabel, savedAriaLabel, unsavedAriaLabel, getAriaLabel, asChild, onToggleError, onClick, disabled, ref: providedRef, ...buttonProps }: KeepButtonProps<TMeta>): react.JSX.Element;
|
|
61
71
|
|
|
62
72
|
type KeepErrorBoundaryProps = {
|
|
63
73
|
children?: ReactNode;
|
|
@@ -90,6 +100,11 @@ type KeepContextValue<TMeta = Record<string, unknown>> = {
|
|
|
90
100
|
saveItem: (item: KeepItem<TMeta>) => Promise<void>;
|
|
91
101
|
updateNote: (id: string, note?: string) => Promise<void>;
|
|
92
102
|
updateTags: (id: string, tags?: string[]) => Promise<void>;
|
|
103
|
+
toggleArchive: (id: string) => Promise<void>;
|
|
104
|
+
archiveItem: (id: string) => Promise<void>;
|
|
105
|
+
unarchiveItem: (id: string) => Promise<void>;
|
|
106
|
+
togglePin: (id: string) => Promise<void>;
|
|
107
|
+
moveToCollection: (id: string, collectionId?: string) => Promise<void>;
|
|
93
108
|
updateTagsBatch: (ids: string[], tags?: string[]) => Promise<void>;
|
|
94
109
|
addTagsBatch: (ids: string[], tags: string[]) => Promise<void>;
|
|
95
110
|
removeTagsBatch: (ids: string[], tags: string[]) => Promise<void>;
|
|
@@ -158,6 +173,13 @@ type UseKeepListResult<TMeta = Record<string, unknown>> = {
|
|
|
158
173
|
removeWithUndo: (id: string) => Promise<void>;
|
|
159
174
|
removeBatchWithUndo: (ids: string[]) => Promise<void>;
|
|
160
175
|
updateTagsBatch: (ids: string[], tags?: string[]) => Promise<void>;
|
|
176
|
+
toggleArchive: (id: string) => Promise<void>;
|
|
177
|
+
archiveItem: (id: string) => Promise<void>;
|
|
178
|
+
unarchiveItem: (id: string) => Promise<void>;
|
|
179
|
+
archive: (id: string) => Promise<void>;
|
|
180
|
+
unarchive: (id: string) => Promise<void>;
|
|
181
|
+
togglePin: (id: string) => Promise<void>;
|
|
182
|
+
moveToCollection: (id: string, collectionId?: string) => Promise<void>;
|
|
161
183
|
addTagsBatch: (ids: string[], tags: string[]) => Promise<void>;
|
|
162
184
|
removeTagsBatch: (ids: string[], tags: string[]) => Promise<void>;
|
|
163
185
|
reorder: (orderedIds: string[]) => Promise<void>;
|
package/dist/react.js
CHANGED
|
@@ -10,14 +10,14 @@ import {
|
|
|
10
10
|
queryKeepItems,
|
|
11
11
|
reorderKeepItems,
|
|
12
12
|
revalidateKeepItems
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-RSXYXT5D.js";
|
|
14
14
|
import {
|
|
15
15
|
parseKeepMeta
|
|
16
16
|
} from "./chunk-5W4QSJHV.js";
|
|
17
17
|
import {
|
|
18
18
|
createBrowserStorageAdapter,
|
|
19
19
|
normalizeKeepTags
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-XUHRDJD6.js";
|
|
21
21
|
|
|
22
22
|
// src/react/components/KeepButton.tsx
|
|
23
23
|
import {
|
|
@@ -447,6 +447,66 @@ function KeepProviderContent({
|
|
|
447
447
|
},
|
|
448
448
|
[runMutation, storage]
|
|
449
449
|
);
|
|
450
|
+
const setArchive = useCallback(
|
|
451
|
+
async (id, archived) => {
|
|
452
|
+
await runMutation("archive", id, (previous) => {
|
|
453
|
+
const current = previous.find((item) => item.id === id);
|
|
454
|
+
if (!current) return void 0;
|
|
455
|
+
const next = { ...current, archived, updatedAt: Date.now() };
|
|
456
|
+
return {
|
|
457
|
+
next: previous.map((item) => item.id === id ? next : item),
|
|
458
|
+
persist: () => storage.set(next),
|
|
459
|
+
pluginContext: { action: "archive", id, item: next }
|
|
460
|
+
};
|
|
461
|
+
});
|
|
462
|
+
},
|
|
463
|
+
[runMutation, storage]
|
|
464
|
+
);
|
|
465
|
+
const toggleArchive = useCallback(
|
|
466
|
+
(id) => {
|
|
467
|
+
const item = itemsRef.current.find((current) => current.id === id);
|
|
468
|
+
return setArchive(id, item?.archived !== true);
|
|
469
|
+
},
|
|
470
|
+
[setArchive]
|
|
471
|
+
);
|
|
472
|
+
const archiveItem = useCallback((id) => setArchive(id, true), [setArchive]);
|
|
473
|
+
const unarchiveItem = useCallback((id) => setArchive(id, false), [setArchive]);
|
|
474
|
+
const togglePin = useCallback(
|
|
475
|
+
async (id) => {
|
|
476
|
+
await runMutation("pin", id, (previous) => {
|
|
477
|
+
const current = previous.find((item) => item.id === id);
|
|
478
|
+
if (!current) return void 0;
|
|
479
|
+
const next = { ...current, pinned: current.pinned !== true, updatedAt: Date.now() };
|
|
480
|
+
return {
|
|
481
|
+
next: previous.map((item) => item.id === id ? next : item),
|
|
482
|
+
persist: () => storage.set(next),
|
|
483
|
+
pluginContext: { action: "pin", id, item: next }
|
|
484
|
+
};
|
|
485
|
+
});
|
|
486
|
+
},
|
|
487
|
+
[runMutation, storage]
|
|
488
|
+
);
|
|
489
|
+
const moveToCollection = useCallback(
|
|
490
|
+
async (id, collectionId) => {
|
|
491
|
+
const nextCollectionId = collectionId?.trim() || void 0;
|
|
492
|
+
await runMutation("collection", id, (previous) => {
|
|
493
|
+
const current = previous.find((item) => item.id === id);
|
|
494
|
+
if (!current) return void 0;
|
|
495
|
+
const { collectionId: _oldCollectionId, ...withoutCollection } = current;
|
|
496
|
+
const next = {
|
|
497
|
+
...withoutCollection,
|
|
498
|
+
...nextCollectionId ? { collectionId: nextCollectionId } : {},
|
|
499
|
+
updatedAt: Date.now()
|
|
500
|
+
};
|
|
501
|
+
return {
|
|
502
|
+
next: previous.map((item) => item.id === id ? next : item),
|
|
503
|
+
persist: () => storage.set(next),
|
|
504
|
+
pluginContext: { action: "collection", id, item: next }
|
|
505
|
+
};
|
|
506
|
+
});
|
|
507
|
+
},
|
|
508
|
+
[runMutation, storage]
|
|
509
|
+
);
|
|
450
510
|
const updateTagsBatch = useCallback(
|
|
451
511
|
async (ids, tags) => {
|
|
452
512
|
const idSet = new Set(ids);
|
|
@@ -787,6 +847,11 @@ function KeepProviderContent({
|
|
|
787
847
|
saveItem,
|
|
788
848
|
updateNote,
|
|
789
849
|
updateTags,
|
|
850
|
+
toggleArchive,
|
|
851
|
+
archiveItem,
|
|
852
|
+
unarchiveItem,
|
|
853
|
+
togglePin,
|
|
854
|
+
moveToCollection,
|
|
790
855
|
updateTagsBatch,
|
|
791
856
|
addTagsBatch,
|
|
792
857
|
removeTagsBatch,
|
|
@@ -826,6 +891,11 @@ function KeepProviderContent({
|
|
|
826
891
|
undoLastRemoval,
|
|
827
892
|
updateNote,
|
|
828
893
|
updateTags,
|
|
894
|
+
toggleArchive,
|
|
895
|
+
archiveItem,
|
|
896
|
+
unarchiveItem,
|
|
897
|
+
togglePin,
|
|
898
|
+
moveToCollection,
|
|
829
899
|
updateTagsBatch,
|
|
830
900
|
addTagsBatch,
|
|
831
901
|
removeTagsBatch,
|
|
@@ -843,6 +913,11 @@ function KeepProviderContent({
|
|
|
843
913
|
saveItem,
|
|
844
914
|
updateNote,
|
|
845
915
|
updateTags,
|
|
916
|
+
toggleArchive,
|
|
917
|
+
archiveItem,
|
|
918
|
+
unarchiveItem,
|
|
919
|
+
togglePin,
|
|
920
|
+
moveToCollection,
|
|
846
921
|
updateTagsBatch,
|
|
847
922
|
addTagsBatch,
|
|
848
923
|
removeTagsBatch,
|
|
@@ -868,6 +943,11 @@ function KeepProviderContent({
|
|
|
868
943
|
saveItem,
|
|
869
944
|
updateNote,
|
|
870
945
|
updateTags,
|
|
946
|
+
toggleArchive,
|
|
947
|
+
archiveItem,
|
|
948
|
+
unarchiveItem,
|
|
949
|
+
togglePin,
|
|
950
|
+
moveToCollection,
|
|
871
951
|
updateTagsBatch,
|
|
872
952
|
refreshItemMetadata,
|
|
873
953
|
revalidateItems,
|
|
@@ -969,6 +1049,14 @@ function useKeepItem(input) {
|
|
|
969
1049
|
const toggle = useCallback3(() => item ? remove() : save(), [item, remove, save]);
|
|
970
1050
|
const updateNote = useCallback3((note) => actions.updateNote(id, note), [actions, id]);
|
|
971
1051
|
const updateTags = useCallback3((tags) => actions.updateTags(id, tags), [actions, id]);
|
|
1052
|
+
const toggleArchive = useCallback3(() => actions.toggleArchive(id), [actions, id]);
|
|
1053
|
+
const archive = useCallback3(() => actions.archiveItem(id), [actions, id]);
|
|
1054
|
+
const unarchive = useCallback3(() => actions.unarchiveItem(id), [actions, id]);
|
|
1055
|
+
const togglePin = useCallback3(() => actions.togglePin(id), [actions, id]);
|
|
1056
|
+
const moveToCollection = useCallback3(
|
|
1057
|
+
(collectionId) => actions.moveToCollection(id, collectionId),
|
|
1058
|
+
[actions, id]
|
|
1059
|
+
);
|
|
972
1060
|
const refreshMetadata = useCallback3(
|
|
973
1061
|
(refresh) => actions.refreshItemMetadata(id, refresh),
|
|
974
1062
|
[actions, id]
|
|
@@ -986,6 +1074,13 @@ function useKeepItem(input) {
|
|
|
986
1074
|
toggle,
|
|
987
1075
|
updateNote,
|
|
988
1076
|
updateTags,
|
|
1077
|
+
toggleArchive,
|
|
1078
|
+
archiveItem: archive,
|
|
1079
|
+
unarchiveItem: unarchive,
|
|
1080
|
+
archive,
|
|
1081
|
+
unarchive,
|
|
1082
|
+
togglePin,
|
|
1083
|
+
moveToCollection,
|
|
989
1084
|
refreshMetadata
|
|
990
1085
|
};
|
|
991
1086
|
}
|
|
@@ -1004,6 +1099,7 @@ function KeepButton({
|
|
|
1004
1099
|
onToggleError,
|
|
1005
1100
|
onClick,
|
|
1006
1101
|
disabled,
|
|
1102
|
+
ref: providedRef,
|
|
1007
1103
|
...buttonProps
|
|
1008
1104
|
}) {
|
|
1009
1105
|
const state = useKeepItem(item);
|
|
@@ -1047,6 +1143,7 @@ function KeepButton({
|
|
|
1047
1143
|
if (asChild && !isValidElement(child)) {
|
|
1048
1144
|
throw new Error("KeepButton with asChild requires a single React element child.");
|
|
1049
1145
|
}
|
|
1146
|
+
const childRef = asChild && isValidElement(child) ? child.props.ref : void 0;
|
|
1050
1147
|
const commonProps = {
|
|
1051
1148
|
...buttonProps,
|
|
1052
1149
|
"aria-pressed": isSaved,
|
|
@@ -1060,12 +1157,29 @@ function KeepButton({
|
|
|
1060
1157
|
tabIndex: isDisabled ? -1 : buttonProps.tabIndex ?? 0
|
|
1061
1158
|
} : { disabled: isDisabled },
|
|
1062
1159
|
onClick: handleElementClick,
|
|
1063
|
-
onKeyDown: handleKeyDown
|
|
1160
|
+
onKeyDown: handleKeyDown,
|
|
1161
|
+
...asChild ? { ref: composeRefs(childRef, providedRef) } : {}
|
|
1064
1162
|
};
|
|
1065
1163
|
if (asChild) {
|
|
1066
1164
|
return cloneElement(child, commonProps);
|
|
1067
1165
|
}
|
|
1068
|
-
return /* @__PURE__ */ jsx2(
|
|
1166
|
+
return /* @__PURE__ */ jsx2(
|
|
1167
|
+
"button",
|
|
1168
|
+
{
|
|
1169
|
+
...commonProps,
|
|
1170
|
+
ref: providedRef,
|
|
1171
|
+
type: "type" in buttonProps ? buttonProps.type ?? "button" : "button",
|
|
1172
|
+
children: content
|
|
1173
|
+
}
|
|
1174
|
+
);
|
|
1175
|
+
}
|
|
1176
|
+
function composeRefs(...refs) {
|
|
1177
|
+
return (value) => {
|
|
1178
|
+
for (const ref of refs) {
|
|
1179
|
+
if (typeof ref === "function") ref(value);
|
|
1180
|
+
else if (ref) ref.current = value;
|
|
1181
|
+
}
|
|
1182
|
+
};
|
|
1069
1183
|
}
|
|
1070
1184
|
function getAccessibleLabel(isSaved, item, asChild) {
|
|
1071
1185
|
if (!asChild) return isSaved ? "Remove saved item" : "Save item";
|
|
@@ -1083,10 +1197,10 @@ function getMetaTitle(meta) {
|
|
|
1083
1197
|
import { useCallback as useCallback4, useMemo as useMemo2 } from "react";
|
|
1084
1198
|
function useKeepList(query = {}) {
|
|
1085
1199
|
const { store, actions } = useKeepStore();
|
|
1086
|
-
const { filter, pagination, savedBetween, search, sort, tags, targetType } = query;
|
|
1200
|
+
const { archived, collectionId, filter, pagination, pinnedFirst, savedBetween, search, sort, tags, targetType } = query;
|
|
1087
1201
|
const queryOptions = useMemo2(
|
|
1088
|
-
() => ({ filter, pagination, savedBetween, search, sort, tags, targetType }),
|
|
1089
|
-
[filter, pagination, savedBetween, search, sort, tags, targetType]
|
|
1202
|
+
() => ({ archived, collectionId, filter, pagination, pinnedFirst, savedBetween, search, sort, tags, targetType }),
|
|
1203
|
+
[archived, collectionId, filter, pagination, pinnedFirst, savedBetween, search, sort, tags, targetType]
|
|
1090
1204
|
);
|
|
1091
1205
|
const selector = useMemo2(() => {
|
|
1092
1206
|
let previousResult;
|
|
@@ -1140,6 +1254,14 @@ function useKeepList(query = {}) {
|
|
|
1140
1254
|
(ids, nextTags) => actions.removeTagsBatch(ids, nextTags),
|
|
1141
1255
|
[actions]
|
|
1142
1256
|
);
|
|
1257
|
+
const toggleArchive = useCallback4((id) => actions.toggleArchive(id), [actions]);
|
|
1258
|
+
const archive = useCallback4((id) => actions.archiveItem(id), [actions]);
|
|
1259
|
+
const unarchive = useCallback4((id) => actions.unarchiveItem(id), [actions]);
|
|
1260
|
+
const togglePin = useCallback4((id) => actions.togglePin(id), [actions]);
|
|
1261
|
+
const moveToCollection = useCallback4(
|
|
1262
|
+
(id, collectionId2) => actions.moveToCollection(id, collectionId2),
|
|
1263
|
+
[actions]
|
|
1264
|
+
);
|
|
1143
1265
|
return {
|
|
1144
1266
|
items: result.items,
|
|
1145
1267
|
totalCount: result.totalCount,
|
|
@@ -1160,6 +1282,13 @@ function useKeepList(query = {}) {
|
|
|
1160
1282
|
updateTagsBatch,
|
|
1161
1283
|
addTagsBatch,
|
|
1162
1284
|
removeTagsBatch,
|
|
1285
|
+
toggleArchive,
|
|
1286
|
+
archiveItem: archive,
|
|
1287
|
+
unarchiveItem: unarchive,
|
|
1288
|
+
archive,
|
|
1289
|
+
unarchive,
|
|
1290
|
+
togglePin,
|
|
1291
|
+
moveToCollection,
|
|
1163
1292
|
reorder: actions.reorderItems,
|
|
1164
1293
|
move: actions.moveItem,
|
|
1165
1294
|
clear: actions.clear,
|