@marktiderman/genesis-core 1.8.0 → 1.10.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 +236 -0
- package/dist/chunk-52T2EYXH.js +52 -0
- package/dist/chunk-52T2EYXH.js.map +1 -0
- package/dist/chunk-5ORRAXIV.js +30 -0
- package/dist/chunk-5ORRAXIV.js.map +1 -0
- package/dist/{chunk-ZKMAU6NN.js → chunk-BGTXN2E6.js} +5 -4
- package/dist/chunk-BGTXN2E6.js.map +1 -0
- package/dist/chunk-DF2UWEEB.js +38 -0
- package/dist/chunk-DF2UWEEB.js.map +1 -0
- package/dist/{chunk-XKLYDAT5.js → chunk-EF5BKT4B.js} +98 -21
- package/dist/chunk-EF5BKT4B.js.map +1 -0
- package/dist/chunk-HBAPYA5K.js +257 -0
- package/dist/chunk-HBAPYA5K.js.map +1 -0
- package/dist/{chunk-QFR6YJ3R.js → chunk-NMFABW4Y.js} +6 -5
- package/dist/chunk-NMFABW4Y.js.map +1 -0
- package/dist/{chunk-ADD2RIGA.js → chunk-NZPJI7FC.js} +4 -3
- package/dist/chunk-NZPJI7FC.js.map +1 -0
- package/dist/{chunk-SQR4GFRM.js → chunk-OSPLIKSH.js} +7 -7
- package/dist/{chunk-SQR4GFRM.js.map → chunk-OSPLIKSH.js.map} +1 -1
- package/dist/chunk-RCAP3Q4T.js +75 -0
- package/dist/chunk-RCAP3Q4T.js.map +1 -0
- package/dist/{chunk-OBUBP4BY.js → chunk-S2ZXUNXB.js} +30 -6
- package/dist/chunk-S2ZXUNXB.js.map +1 -0
- package/dist/dates.d.ts +84 -0
- package/dist/dates.js +117 -0
- package/dist/dates.js.map +1 -0
- package/dist/hooks/draft-controller.d.ts +158 -0
- package/dist/hooks/draft-controller.js +4 -0
- package/dist/hooks/draft-controller.js.map +1 -0
- package/dist/hooks/index.d.ts +45 -3
- package/dist/hooks/index.js +15 -11
- package/dist/hooks/mutation-mode.d.ts +14 -2
- package/dist/hooks/mutation-mode.js +2 -1
- package/dist/hooks/related-keys.d.ts +1 -1
- package/dist/hooks/use-draft.d.ts +33 -0
- package/dist/hooks/use-draft.js +5 -0
- package/dist/hooks/use-draft.js.map +1 -0
- package/dist/hooks/use-infinite-resource.d.ts +1 -1
- package/dist/hooks/use-infinite-resource.js +2 -1
- package/dist/hooks/use-live.d.ts +1 -1
- package/dist/hooks/use-one.d.ts +1 -1
- package/dist/hooks/use-one.js +2 -1
- package/dist/hooks/use-resource-form.d.ts +1 -1
- package/dist/hooks/use-resource-form.js +8 -7
- package/dist/hooks/use-resource.d.ts +1 -1
- package/dist/hooks/use-resource.js +5 -4
- package/dist/hooks/use-write.d.ts +45 -0
- package/dist/hooks/use-write.js +4 -0
- package/dist/hooks/use-write.js.map +1 -0
- package/dist/index.d.ts +78 -5
- package/dist/index.js +17 -13
- package/dist/provider/index.d.ts +85 -5
- package/dist/provider/index.js +3 -3
- package/dist/read-outcome-BnboMYOV.d.ts +30 -0
- package/dist/schema/index.d.ts +3 -2
- package/dist/testing/index.d.ts +102 -0
- package/dist/testing/index.js +210 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/{types-CS9UpxQS.d.ts → types-B9DDfvWa.d.ts} +1 -1
- package/dist/{read-outcome-B6nACXZ7.d.ts → write-outcome-B2fE29yZ.d.ts} +1 -30
- package/package.json +14 -1
- package/dist/chunk-ADD2RIGA.js.map +0 -1
- package/dist/chunk-OBUBP4BY.js.map +0 -1
- package/dist/chunk-QFR6YJ3R.js.map +0 -1
- package/dist/chunk-V3GDAELU.js +0 -3
- package/dist/chunk-V3GDAELU.js.map +0 -1
- package/dist/chunk-XKLYDAT5.js.map +0 -1
- package/dist/chunk-ZKMAU6NN.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/mutation-mode.ts"],"names":["rows"],"mappings":"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","file":"chunk-S2ZXUNXB.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Mutation modes — when a write reaches the cache, and when the provider.\n//\n// - `pessimistic` (default): wait for the provider, then refetch. Today's\n// behaviour.\n// - `optimistic`: patch the TanStack Query cache at once, send the write, and\n// put the cache back (and report the error) if it fails.\n// - `undoable`: patch the cache at once and offer an undo (`onUndoable`);\n// the write is sent after a delay unless undone. A provider that serves\n// `undo` (capabilities `undo: true`) gets the write at once instead, and\n// the undo asks the provider to reverse it.\n//\n// Core has no UI: the undo toast is the caller's (`onUndoable`). genesis-ui's\n// ResourceForm and ResourcePage show a sonner toast.\n//\n// Pending writes belong to the QueryClient, not to the hook that started\n// them: a form that closes on success can still be undone from its toast.\n// ---------------------------------------------------------------------------\n\nimport type { QueryClient, QueryKey } from \"@tanstack/react-query\";\nimport type { BaseRecord, DataProvider, Identifier, ListResult } from \"../provider/types\";\nimport type { AuditEntry, ProviderCapabilities } from \"../schema/types\";\nimport { capabilitiesQueryKey } from \"./use-capabilities\";\nimport { resourceKeys } from \"../query-keys\";\n\nexport type MutationMode = \"pessimistic\" | \"optimistic\" | \"undoable\";\n\n/** How long an `undoable` write waits for an undo before it is sent. */\nexport const DEFAULT_UNDO_DELAY_MS = 5000;\n\n/** An undoable write, as handed to `onUndoable` so a UI can offer the undo. */\nexport interface UndoableWrite {\n resource: string;\n kind: \"create\" | \"update\" | \"delete\";\n /** The record's id; absent for a create (it has none until it is sent). */\n id?: Identifier;\n /**\n * - `delay`: the write has not been sent. `undo()` discards it; `commit()`\n * sends it now instead of waiting.\n * - `provider`: the write was sent at once, because the provider serves\n * `undo`. `undo()` asks the provider to reverse it; `commit()` does\n * nothing.\n */\n strategy: \"delay\" | \"provider\";\n /** How long the undo is offered, in ms (the toast's duration). */\n delayMs: number;\n /**\n * Take the write back. Resolves true when it was undone (or will never be\n * sent), false when it could not be: already sent under `delay` (the\n * window closed, it was committed, a later write on the same record sent\n * it first, or the page unloaded), already undone, or the provider's undo\n * failed (reported through `onError`). Works after the hook that made the\n * write has unmounted. Safe to call more than once.\n */\n undo: () => Promise<boolean>;\n /** Send a `delay` write now. */\n commit: () => void;\n}\n\nexport interface MutationModeOptions {\n /** Default `\"pessimistic\"`. */\n mutationMode?: MutationMode;\n /** How long an `undoable` write waits, in ms. Default 5000. */\n undoDelayMs?: number;\n /** Called with every `undoable` write, to show an undo control. */\n onUndoable?: (write: UndoableWrite) => void;\n}\n\n// ---------------------------------------------------------------------------\n// Small helpers\n// ---------------------------------------------------------------------------\n\nfunction sameId(a: unknown, b: unknown): boolean {\n return a != null && b != null && String(a) === String(b);\n}\n\nfunction isListResult(value: unknown): value is ListResult<BaseRecord> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n Array.isArray((value as { data?: unknown }).data)\n );\n}\n\n/** TanStack infinite-query data whose pages are list results. */\ninterface InfiniteLists {\n pages: unknown[];\n pageParams: unknown[];\n}\n\nfunction isInfiniteLists(value: unknown): value is InfiniteLists {\n return (\n typeof value === \"object\" &&\n value !== null &&\n Array.isArray((value as { pages?: unknown }).pages) &&\n Array.isArray((value as { pageParams?: unknown }).pageParams)\n );\n}\n\n/**\n * Runs `fn` on every list a cache entry holds: a `[resource, \"list\", …]`\n * entry is one list (keyed by its query hash); a `[resource, \"infinite\",\n * …]` entry (useInfiniteResource) is one list per loaded page (keyed\n * `hash#page`). Returns the entry rebuilt, or the same object when `fn`\n * changed nothing. Rows added or removed change every page's `total`,\n * since each page reports the whole list's count.\n */\nfunction mapLists(\n key: QueryKey,\n hash: string,\n value: unknown,\n fn: (list: ListResult<BaseRecord>, hash: string) => ListResult<BaseRecord>,\n): unknown {\n if (key[1] === \"list\") return isListResult(value) ? fn(value, hash) : value;\n if (key[1] !== \"infinite\" || !isInfiniteLists(value)) return value;\n let changed = false;\n // Rows added or removed across pages, applied to every page's count: a\n // page after the first may report -1 (not counted), so its own total\n // can't carry the change.\n let rowDelta = 0;\n const pages = value.pages.map((page, i) => {\n if (!isListResult(page)) return page;\n const next = fn(page, `${hash}#${i}`);\n if (next !== page) {\n changed = true;\n rowDelta += next.data.length - page.data.length;\n }\n return next;\n });\n if (!changed) return value;\n const withTotals = value.pages.map((orig, i) => {\n const page = pages[i];\n if (!isListResult(page) || !isListResult(orig) || typeof orig.total !== \"number\") return page;\n return { ...page, total: orig.total < 0 ? orig.total : Math.max(0, orig.total + rowDelta) };\n });\n return { ...value, pages: withTotals };\n}\n\n/** Every list result a cache entry holds (see `mapLists`). */\nfunction listsIn(key: QueryKey, value: unknown): ListResult<BaseRecord>[] {\n if (key[1] === \"list\") return isListResult(value) ? [value] : [];\n if (key[1] === \"infinite\" && isInfiniteLists(value)) return value.pages.filter(isListResult);\n return [];\n}\n\nfunction isDetailKeyFor(key: QueryKey, resource: string, id: Identifier): boolean {\n return key[0] === resource && key[1] === \"detail\" && sameId(key[2], id);\n}\n\n/** Structural equality for row values (JSON-like data, Dates). */\nexport function sameValue(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();\n if (typeof a !== \"object\" || typeof b !== \"object\" || a === null || b === null) return false;\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n if (Array.isArray(a)) {\n const other = b as unknown[];\n return a.length === other.length && a.every((item, i) => sameValue(item, other[i]));\n }\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every(\n (k) => Object.prototype.hasOwnProperty.call(b, k) &&\n sameValue((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]),\n );\n}\n\nfunction asError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\n/** The record as the cache has it now, from a detail entry or any list. */\nexport function cachedRecord(\n queryClient: QueryClient,\n resource: string,\n id: Identifier,\n): BaseRecord | undefined {\n for (const [key, value] of queryClient.getQueriesData<unknown>({ queryKey: resourceKeys(resource).details })) {\n if (isDetailKeyFor(key, resource, id) && value && typeof value === \"object\") return value as BaseRecord;\n }\n for (const [key, value] of queryClient.getQueriesData<unknown>({ queryKey: [resource] })) {\n for (const list of listsIn(key, value)) {\n const found = list.data.find((row) => sameId(row.id, id));\n if (found) return found;\n }\n }\n return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// The registry — one per QueryClient\n//\n// Holds every optimistic/undoable write not yet settled, and the cache\n// patches they made. Patches are re-applied to any `[resource, \"list\" |\n// \"infinite\" | \"detail\", …]` data that arrives while they are pending (a refetch, a new\n// page, filter or search), so a deleted row stays gone and an edit stays\n// shown until the write settles. Because of that, refetching is always safe\n// and nothing waits for pending writes before invalidating.\n// ---------------------------------------------------------------------------\n\n/** One record's change, kept applied to the cache while its write is pending. */\ninterface Patch {\n resource: string;\n id: Identifier;\n kind: \"update\" | \"delete\";\n /** An update's values; the same object its write sends, so a rebase changes both. */\n data?: Record<string, unknown>;\n /** Per cache entry (query hash): the row just before this patch, and its list index. */\n before: Map<string, { row: BaseRecord; index: number }>;\n}\n\n/** One optimistic or undoable write that has not settled. */\ninterface Tracked {\n seq: number;\n queryClient: QueryClient;\n provider: DataProvider;\n resource: string;\n kind: \"create\" | \"update\" | \"delete\";\n /** `resource` + id: writes on the same record are sent in order. */\n rowKey?: string;\n patch?: Patch;\n /** Row-shaped values it will send (update); undefined when not row-shaped. */\n data?: Record<string, unknown>;\n /** The cached row just before this write's patch. */\n baseline?: BaseRecord;\n /**\n * - waiting: an undoable write in its delay\n * - queued: to be sent, behind earlier writes on the same record\n * - sending / done\n */\n state: \"waiting\" | \"queued\" | \"sending\" | \"done\";\n /** Sent with `keepalive` (because the page was unloading). */\n keepalive: boolean;\n /** Set when it was dropped because an earlier write it built on was taken back. */\n dropped: boolean;\n /** Send now: a waiting write skips its delay; `unloading` also skips the row queue. */\n flush: (unloading?: boolean) => void;\n /** Drop a waiting or queued write (see `dropped`). */\n drop: () => void;\n /** Drop a waiting or queued write without a word: its viewer is gone. */\n discard: () => void;\n /** Settles once the write was sent, failed or dropped. */\n sent: Promise<unknown>;\n}\n\ninterface Registry {\n pending: Map<string, number>;\n patches: Patch[];\n writes: Tracked[];\n rowTails: Map<string, Promise<void>>;\n /** Cache data this module wrote, so the cache listener does not re-patch it. */\n produced: WeakSet<object>;\n /** True while this module is writing to the cache. */\n writing: boolean;\n unsubscribe?: () => void;\n}\n\nconst registries = new WeakMap<QueryClient, Registry>();\nlet nextSeq = 0;\n\nfunction registryFor(queryClient: QueryClient): Registry {\n let reg = registries.get(queryClient);\n if (!reg) {\n reg = {\n pending: new Map(),\n patches: [],\n writes: [],\n rowTails: new Map(),\n produced: new WeakSet(),\n writing: false,\n };\n registries.set(queryClient, reg);\n }\n return reg;\n}\n\n/**\n * Sends every optimistic or undoable write still waiting on this client now,\n * and resolves once all have settled. Call it while the session that made\n * them still holds (a sign-out action, before signing out).\n */\nexport async function flushPendingWrites(queryClient: QueryClient): Promise<void> {\n const reg = registries.get(queryClient);\n if (!reg) return;\n for (const write of [...reg.writes].sort((a, b) => a.seq - b.seq)) {\n if (write.state === \"waiting\") write.flush();\n }\n await Promise.allSettled(reg.writes.map((write) => write.sent));\n}\n\n/**\n * Drops every write on this client not yet sent, without reporting them: the\n * viewer who made them is gone, so they must never be sent (or re-applied)\n * under the next one. Writes already sending finish under the old session.\n */\nexport function dropPendingWrites(queryClient: QueryClient): void {\n const reg = registries.get(queryClient);\n if (!reg) return;\n for (const write of [...reg.writes].sort((a, b) => b.seq - a.seq)) write.discard();\n}\n\n/** Optimistic or undoable writes on `resource` not yet settled. */\nexport function pendingWriteCount(queryClient: QueryClient, resource: string): number {\n return registries.get(queryClient)?.pending.get(resource) ?? 0;\n}\n\nfunction beginPending(reg: Registry, resource: string): void {\n reg.pending.set(resource, (reg.pending.get(resource) ?? 0) + 1);\n}\n\nfunction endPending(reg: Registry, resource: string): void {\n const left = Math.max(0, (reg.pending.get(resource) ?? 0) - 1);\n if (left === 0) reg.pending.delete(resource);\n else reg.pending.set(resource, left);\n}\n\n/**\n * Invalidate `[resource]`. Safe while optimistic/undoable writes on it are\n * pending: their patches are re-applied to whatever the refetch brings.\n */\nexport function invalidateResource(queryClient: QueryClient, resource: string): Promise<void> {\n return queryClient.invalidateQueries({ queryKey: resourceKeys(resource).all });\n}\n\nfunction setProduced(reg: Registry, queryClient: QueryClient, key: QueryKey, value: unknown): void {\n const wasWriting = reg.writing;\n reg.writing = true;\n try {\n queryClient.setQueryData(key, value);\n } finally {\n reg.writing = wasWriting;\n }\n // Structural sharing may store a different object than `value`.\n const stored: unknown = queryClient.getQueryData(key);\n if (stored && typeof stored === \"object\") reg.produced.add(stored);\n}\n\nfunction applyUpdate(row: BaseRecord, data: Record<string, unknown>): BaseRecord {\n return { ...row, ...data, id: row.id };\n}\n\n/** `row` with `data`'s fields put back to what they were in `before`. */\nfunction revertFields(row: BaseRecord, data: Record<string, unknown>, before: BaseRecord): BaseRecord {\n const out: Record<string, unknown> = { ...row };\n for (const k of Object.keys(data)) {\n if (k === \"id\") continue;\n if (k in before) out[k] = before[k];\n else delete out[k];\n }\n return out as BaseRecord;\n}\n\n/**\n * Applies `patches`, in order, to one cache entry's data, recording each\n * patch's before-row for that entry. Returns the same object when nothing\n * applied.\n */\nfunction applyPatches(key: QueryKey, hash: string, value: unknown, patches: Patch[]): unknown {\n if (key[1] === \"list\" || key[1] === \"infinite\") {\n return mapLists(key, hash, value, (list, listHash) => {\n let rows = list.data;\n let total = list.total;\n let changed = false;\n for (const p of patches) {\n const index = rows.findIndex((row) => sameId(row.id, p.id));\n if (index < 0) continue;\n p.before.set(listHash, { row: rows[index]!, index });\n if (p.kind === \"update\") {\n rows = rows.slice();\n rows[index] = applyUpdate(rows[index]!, p.data ?? {});\n } else {\n rows = rows.filter((_, i) => i !== index);\n if (typeof total === \"number\" && total >= 0) total = Math.max(0, total - 1);\n }\n changed = true;\n }\n if (!changed) return list;\n return typeof total === \"number\" ? { ...list, data: rows, total } : { ...list, data: rows };\n });\n }\n if (key[1] === \"detail\" && value && typeof value === \"object\") {\n let row = value as BaseRecord;\n let changed = false;\n for (const p of patches) {\n if (p.kind !== \"update\" || !sameId(key[2], p.id)) continue;\n p.before.set(hash, { row, index: -1 });\n row = applyUpdate(row, p.data ?? {});\n changed = true;\n }\n return changed ? row : value;\n }\n return value;\n}\n\n/** Re-applies pending patches to data that just landed in the cache. */\nfunction ensureListener(reg: Registry, queryClient: QueryClient): void {\n if (reg.unsubscribe) return;\n reg.unsubscribe = queryClient.getQueryCache().subscribe((event) => {\n if (reg.writing || event.type !== \"updated\" || event.action.type !== \"success\") return;\n const { queryKey: key, queryHash: hash } = event.query;\n const resource = key[0];\n if (typeof resource !== \"string\") return;\n const data: unknown = event.query.state.data;\n if (!data || typeof data !== \"object\" || reg.produced.has(data)) return;\n const patches = reg.patches.filter((p) => p.resource === resource);\n if (patches.length === 0) return;\n const next = applyPatches(key, hash, data, patches);\n if (next !== data) setProduced(reg, queryClient, key, next);\n });\n}\n\nfunction addPatch(reg: Registry, queryClient: QueryClient, patch: Patch): void {\n reg.patches.push(patch);\n ensureListener(reg, queryClient);\n for (const query of queryClient.getQueryCache().findAll({ queryKey: [patch.resource] })) {\n const value: unknown = query.state.data;\n const next = applyPatches(query.queryKey, query.queryHash, value, [patch]);\n if (next !== value) setProduced(reg, queryClient, query.queryKey, next);\n }\n}\n\nfunction dropPatchRecord(reg: Registry, patch: Patch): number {\n const index = reg.patches.indexOf(patch);\n if (index >= 0) reg.patches.splice(index, 1);\n if (reg.patches.length === 0 && reg.unsubscribe) {\n reg.unsubscribe();\n reg.unsubscribe = undefined;\n }\n return index;\n}\n\nfunction firstBefore(patch: Patch): { row: BaseRecord; index: number } | undefined {\n for (const value of patch.before.values()) return value;\n return undefined;\n}\n\n/**\n * Takes a patch back out of the cache, keeping every other pending patch on\n * the same record applied (field by field, not by restoring a whole saved\n * row).\n */\nfunction retractPatch(reg: Registry, queryClient: QueryClient, patch: Patch): void {\n const index = dropPatchRecord(reg, patch);\n if (index < 0) return;\n const onRow = (p: Patch) => p.resource === patch.resource && sameId(p.id, patch.id);\n const remaining = reg.patches.filter(onRow);\n\n // Later patches on the record recorded their before-rows on top of this\n // one: take its values out of them too.\n if (patch.kind === \"update\" && patch.data) {\n for (const later of reg.patches.slice(index).filter(onRow)) {\n for (const [hash, b] of later.before) {\n const src = patch.before.get(hash) ?? firstBefore(patch);\n if (src) later.before.set(hash, { ...b, row: revertFields(b.row, patch.data, src.row) });\n }\n }\n }\n\n const reapply = (row: BaseRecord) =>\n remaining.reduce((r, p) => (p.kind === \"update\" ? applyUpdate(r, p.data ?? {}) : r), row);\n\n for (const query of queryClient.getQueryCache().findAll({ queryKey: [patch.resource] })) {\n const key = query.queryKey;\n const value: unknown = query.state.data;\n let next: unknown = value;\n if (key[1] === \"list\" || key[1] === \"infinite\") {\n next = mapLists(key, query.queryHash, value, (list, listHash) => {\n const b = patch.before.get(listHash);\n const at = list.data.findIndex((row) => sameId(row.id, patch.id));\n if (patch.kind === \"update\") {\n const src = b ?? firstBefore(patch);\n if (at < 0 || !src || !patch.data) return list;\n const rows = list.data.slice();\n rows[at] = reapply(revertFields(rows[at]!, patch.data, src.row));\n return { ...list, data: rows };\n }\n // A delete puts the row back where it was, unless a later delete of\n // the same record still hides it.\n if (at >= 0 || !b || remaining.some((p) => p.kind === \"delete\")) return list;\n const rows = list.data.slice();\n rows.splice(Math.min(b.index, rows.length), 0, reapply(b.row));\n return {\n ...list,\n data: rows,\n ...(typeof list.total === \"number\" && list.total >= 0 ? { total: list.total + 1 } : {}),\n };\n });\n } else if (\n key[1] === \"detail\" &&\n patch.kind === \"update\" &&\n patch.data &&\n sameId(key[2], patch.id) &&\n value &&\n typeof value === \"object\"\n ) {\n const src = patch.before.get(query.queryHash) ?? firstBefore(patch);\n if (!src) continue;\n next = reapply(revertFields(value as BaseRecord, patch.data, src.row));\n }\n if (next !== value) setProduced(reg, queryClient, key, next);\n }\n}\n\n/**\n * A write was taken back (undone, or it failed): retract its patch, and fix\n * the later writes on the same record that have not been sent. A later\n * update that kept this write's values unchanged (its form opened from the\n * patched cache) gets them put back to what they were before; one whose\n * values are not row-shaped cannot be fixed, so it is dropped.\n */\nfunction takeBack(reg: Registry, write: Tracked): void {\n if (write.patch) retractPatch(reg, write.queryClient, write.patch);\n if (!write.rowKey || write.kind !== \"update\" || !write.patch?.data) return;\n const undone = write.patch.data;\n const before = write.baseline ?? firstBefore(write.patch)?.row ?? ({} as BaseRecord);\n const later = reg.writes.filter(\n (w) =>\n w.seq > write.seq &&\n w.rowKey === write.rowKey &&\n w.kind === \"update\" &&\n (w.state === \"waiting\" || w.state === \"queued\"),\n );\n for (const w of later) {\n if (!w.data) {\n w.drop();\n continue;\n }\n const rebased: Record<string, unknown> = {};\n const removed: string[] = [];\n for (const k of Object.keys(undone)) {\n if (k === \"id\" || !(k in w.data)) continue;\n const kept = sameValue(w.data[k], undone[k]) && w.baseline != null && sameValue(w.baseline[k], undone[k]);\n if (!kept) continue;\n if (k in before) rebased[k] = before[k];\n else removed.push(k);\n }\n if (Object.keys(rebased).length === 0 && removed.length === 0) continue;\n // w.data is also w.patch.data: rebase it in place, then show it.\n Object.assign(w.data, rebased);\n for (const k of removed) delete w.data[k];\n if (w.baseline) w.baseline = revertFields(w.baseline, undone, before);\n if (w.patch) refreshFields(reg, w.queryClient, w.patch, [...Object.keys(rebased), ...removed]);\n }\n}\n\n/**\n * After a patch's values changed in place: shows its new values for `keys`\n * in every cached copy of the record, except where a later patch on the\n * record sets the same field.\n */\nfunction refreshFields(reg: Registry, queryClient: QueryClient, patch: Patch, keys: string[]): void {\n const index = reg.patches.indexOf(patch);\n if (index < 0 || !patch.data) return;\n const data = patch.data;\n const overridden = new Set<string>();\n for (const p of reg.patches.slice(index + 1)) {\n if (p.resource === patch.resource && sameId(p.id, patch.id) && p.data) {\n for (const k of Object.keys(p.data)) overridden.add(k);\n }\n }\n const fields = keys.filter((k) => !overridden.has(k));\n if (fields.length === 0) return;\n const fix = (row: BaseRecord, hash: string): BaseRecord => {\n const out: Record<string, unknown> = { ...row };\n const before = (patch.before.get(hash) ?? firstBefore(patch))?.row;\n for (const k of fields) {\n if (k in data) out[k] = data[k];\n else if (before && k in before) out[k] = before[k];\n else delete out[k];\n }\n return out as BaseRecord;\n };\n for (const query of queryClient.getQueryCache().findAll({ queryKey: [patch.resource] })) {\n const key = query.queryKey;\n const value: unknown = query.state.data;\n let next: unknown = value;\n if (key[1] === \"list\" || key[1] === \"infinite\") {\n next = mapLists(key, query.queryHash, value, (list, listHash) => {\n const at = list.data.findIndex((row) => sameId(row.id, patch.id));\n if (at < 0) return list;\n const rows = list.data.slice();\n rows[at] = fix(rows[at]!, listHash);\n return { ...list, data: rows };\n });\n } else if (key[1] === \"detail\" && sameId(key[2], patch.id) && value && typeof value === \"object\") {\n next = fix(value as BaseRecord, query.queryHash);\n }\n if (next !== value) setProduced(reg, queryClient, key, next);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Page unload\n//\n// Waiting writes are sent when the page goes away (`beforeunload`, and\n// `pagehide` for mobile tab kills and bfcache), with `keepalive: true` in\n// their params so a fetch-based provider can let them outlive the page. The\n// \"Leave site?\" prompt shows only while a write is being sent without that\n// guarantee: its provider does not report `keepaliveWrites`, or it was\n// already on its way without keepalive.\n// ---------------------------------------------------------------------------\n\nconst allWrites = new Set<Tracked>();\n\nfunction servesKeepalive(write: Tracked): boolean {\n const caps = write.queryClient.getQueryData<ProviderCapabilities>(\n capabilitiesQueryKey(write.provider, write.resource),\n );\n return caps?.keepaliveWrites === true;\n}\n\nfunction flushForUnload(): void {\n const writes = [...allWrites].sort((a, b) => a.seq - b.seq);\n for (const write of writes) {\n if (write.state === \"waiting\" || write.state === \"queued\") write.flush(true);\n }\n}\n\nfunction onBeforeUnload(event: BeforeUnloadEvent): void {\n flushForUnload();\n const atRisk = [...allWrites].some((w) => w.state === \"sending\" && !(w.keepalive && servesKeepalive(w)));\n if (!atRisk) return;\n event.preventDefault();\n // Older browsers need returnValue set to show the prompt.\n event.returnValue = \"\";\n}\n\nfunction onPageHide(): void {\n flushForUnload();\n}\n\nfunction track(write: Tracked): void {\n allWrites.add(write);\n if (allWrites.size === 1 && typeof window !== \"undefined\") {\n window.addEventListener(\"beforeunload\", onBeforeUnload);\n window.addEventListener(\"pagehide\", onPageHide);\n }\n}\n\nfunction untrack(write: Tracked): void {\n if (!allWrites.delete(write)) return;\n if (allWrites.size === 0 && typeof window !== \"undefined\") {\n window.removeEventListener(\"beforeunload\", onBeforeUnload);\n window.removeEventListener(\"pagehide\", onPageHide);\n }\n}\n\n// ---------------------------------------------------------------------------\n// The engine\n// ---------------------------------------------------------------------------\n\n/** What `send` is given when the write goes out. */\nexport interface SendContext {\n /**\n * The row-shaped values to send, when `data` was given. They can differ\n * from `data`: an earlier write on the record that this one built on was\n * taken back, and its values were put back. Send these.\n */\n data?: Record<string, unknown>;\n /** The page is unloading: pass `keepalive: true` to the provider. */\n keepalive: boolean;\n}\n\nexport interface ExecuteWriteArgs<R extends BaseRecord | void> {\n queryClient: QueryClient;\n provider: DataProvider;\n resource: string;\n kind: \"create\" | \"update\" | \"delete\";\n id?: Identifier;\n /**\n * The values to merge into the cached row (update). Leave out to patch\n * nothing, e.g. when the values are form-shaped and the row is not.\n */\n data?: Record<string, unknown>;\n mode: MutationMode;\n undoDelayMs?: number;\n onUndoable?: (write: UndoableWrite) => void;\n /** Sends the write. */\n send: (context: SendContext) => Promise<{ record: R; audit?: AuditEntry }>;\n /** After the write committed. Invalidates and calls success callbacks. */\n committed: (record: R) => Promise<void> | void;\n /** A write that failed (or was dropped) after the caller was told it went through. */\n failedLater: (error: Error) => void;\n}\n\nexport type ExecuteWriteResult<R> =\n | { status: \"committed\"; record: R }\n | { status: \"applied\" };\n\nconst CAPABILITIES_QUERY = (provider: DataProvider, resource: string) => ({\n // The same key as useCapabilities, so the answer is shared.\n queryKey: capabilitiesQueryKey(provider, resource),\n queryFn: () => provider.capabilities!(resource),\n staleTime: Infinity,\n // A write may wait on this answer; an app's default retries would hold\n // it for seconds.\n retry: false as const,\n});\n\n/**\n * Whether `provider` serves `undo` for `resource`, from its capabilities\n * (useCapabilities' key, so the answer is shared, and scoped to this\n * provider: a swapped-out provider's capabilities never offer undo).\n * @internal Exported for tests.\n */\nexport async function providerServesUndo(\n queryClient: QueryClient,\n provider: DataProvider,\n resource: string,\n): Promise<boolean> {\n if (!provider.undo || !provider.capabilities) return false;\n try {\n const caps = await queryClient.fetchQuery<ProviderCapabilities>(CAPABILITIES_QUERY(provider, resource));\n return caps?.undo === true;\n } catch {\n return false;\n }\n}\n\n/** A later write that built on one that was taken back. */\nexport const DROPPED_WRITE_MESSAGE =\n \"This change was not saved: it was made on top of an earlier change that was undone or failed. Please make it again.\";\n\n/**\n * Runs one write in the given mode.\n *\n * - `pessimistic`: sends it and waits; a failure rejects.\n * - `optimistic` / `undoable`: resolves `{ status: \"applied\" }` as soon as\n * the cache is patched. A later failure rolls the patch back and goes to\n * `failedLater`, never to the returned promise.\n *\n * Writes on the same record are sent one after another, in the order they\n * were made; sending one first sends the earlier ones still waiting.\n */\nexport async function executeWrite<R extends BaseRecord | void>(\n args: ExecuteWriteArgs<R>,\n): Promise<ExecuteWriteResult<R>> {\n const { queryClient, provider, resource, kind, id, mode, send, committed, failedLater } = args;\n\n if (mode === \"pessimistic\") {\n const { record } = await send({ data: args.data, keepalive: false });\n await committed(record);\n return { status: \"committed\", record };\n }\n\n const viaProviderUndo = mode === \"undoable\" && (await providerServesUndo(queryClient, provider, resource));\n // Warm the capabilities answer, so the unload handler can tell (without\n // waiting) whether this provider keeps writes alive.\n if (provider.capabilities && !queryClient.getQueryData(capabilitiesQueryKey(provider, resource))) {\n void queryClient.prefetchQuery(CAPABILITIES_QUERY(provider, resource));\n }\n\n const reg = registryFor(queryClient);\n const hasRow = kind !== \"create\" && id != null;\n const data = args.data ? { ...args.data } : undefined;\n let patch: Patch | undefined;\n if (hasRow && kind === \"update\" && data) patch = { resource, id: id!, kind: \"update\", data, before: new Map() };\n else if (hasRow && kind === \"delete\") patch = { resource, id: id!, kind: \"delete\", before: new Map() };\n // A create has no cache entry yet: its id and its place in each sorted,\n // filtered list are the server's to say.\n\n const delayMs = Math.max(0, args.undoDelayMs ?? DEFAULT_UNDO_DELAY_MS);\n let timer: ReturnType<typeof setTimeout> | undefined;\n let resolveSent: (result: { record: R; audit?: AuditEntry } | undefined) => void = () => {};\n const sent = new Promise<{ record: R; audit?: AuditEntry } | undefined>((resolve) => {\n resolveSent = resolve;\n });\n\n const write: Tracked = {\n seq: ++nextSeq,\n queryClient,\n provider,\n resource,\n kind,\n rowKey: hasRow ? `${resource}\\u0000${String(id)}` : undefined,\n patch,\n data: kind === \"update\" ? data : undefined,\n baseline: hasRow ? cachedRecord(queryClient, resource, id!) : undefined,\n state: \"queued\",\n keepalive: false,\n dropped: false,\n flush: () => {},\n drop: () => {},\n discard: () => {},\n sent,\n };\n\n const settle = () => {\n write.state = \"done\";\n clearTimeout(timer);\n const at = reg.writes.indexOf(write);\n if (at >= 0) reg.writes.splice(at, 1);\n untrack(write);\n endPending(reg, resource);\n };\n\n const sendNow = async (keepalive: boolean): Promise<void> => {\n if (write.state !== \"queued\") return;\n write.state = \"sending\";\n write.keepalive = keepalive;\n let result: { record: R; audit?: AuditEntry };\n try {\n result = await send({ data: write.data, keepalive });\n } catch (error) {\n settle();\n takeBack(reg, write);\n void invalidateResource(queryClient, resource);\n failedLater(asError(error));\n resolveSent(undefined);\n return;\n }\n // The server has it now; the refetch `committed` starts replaces the patch.\n if (patch) dropPatchRecord(reg, patch);\n settle();\n try {\n await committed(result.record);\n } catch (error) {\n // The write did commit; only a callback failed.\n console.error(`[genesis] after-write callback failed for \"${resource}\":`, error);\n }\n resolveSent(result);\n };\n\n const enqueue = () => {\n if (!write.rowKey) {\n void sendNow(false);\n return;\n }\n const key = write.rowKey;\n const previous = reg.rowTails.get(key);\n const run = () => sendNow(false);\n const next = previous ? previous.then(run, run) : run();\n reg.rowTails.set(key, next);\n void next.finally(() => {\n if (reg.rowTails.get(key) === next) reg.rowTails.delete(key);\n });\n };\n\n write.flush = (unloading = false) => {\n if (write.state === \"waiting\") {\n clearTimeout(timer);\n // Earlier writes on the record go first, so the server sees them in order.\n if (!unloading) {\n for (const earlier of reg.writes) {\n if (earlier.seq < write.seq && earlier.rowKey === write.rowKey && earlier.rowKey && earlier.state === \"waiting\") {\n earlier.flush();\n }\n }\n }\n write.state = \"queued\";\n if (unloading) void sendNow(true);\n else enqueue();\n } else if (write.state === \"queued\" && unloading) {\n // Behind an earlier write on the record; the page will not wait for it.\n void sendNow(true);\n }\n };\n\n write.drop = () => {\n if (write.state !== \"waiting\" && write.state !== \"queued\") return;\n write.dropped = true;\n settle();\n takeBack(reg, write);\n void invalidateResource(queryClient, resource);\n failedLater(new Error(DROPPED_WRITE_MESSAGE));\n resolveSent(undefined);\n };\n\n write.discard = () => {\n if (write.state !== \"waiting\" && write.state !== \"queued\") return;\n write.dropped = true;\n settle();\n // The cache is being emptied: forget the patch rather than put values back.\n if (patch) dropPatchRecord(reg, patch);\n resolveSent(undefined);\n };\n\n beginPending(reg, resource);\n reg.writes.push(write);\n track(write);\n if (patch) addPatch(reg, queryClient, patch);\n\n if (mode === \"optimistic\") {\n enqueue();\n return { status: \"applied\" };\n }\n\n if (viaProviderUndo) {\n enqueue();\n void sent.then((result) => {\n const auditId = result?.audit?.id;\n if (!result || !args.onUndoable) return;\n if (!auditId) {\n console.warn(\n `[genesis] \"${resource}\" serves undo, but its ${kind} returned no audit entry; no undo offered.`,\n );\n return;\n }\n let undone = false;\n args.onUndoable({\n resource,\n kind,\n id: id ?? (result.record as BaseRecord | undefined)?.id,\n strategy: \"provider\",\n delayMs,\n commit: () => {},\n undo: async () => {\n if (undone) return false;\n undone = true;\n let ok = true;\n try {\n await provider.undo!(resource, { auditId });\n } catch (error) {\n ok = false;\n failedLater(asError(error));\n }\n await invalidateResource(queryClient, resource);\n return ok;\n },\n });\n });\n return { status: \"applied\" };\n }\n\n // Delayed: wait, then send unless undone or flushed first.\n write.state = \"waiting\";\n timer = setTimeout(() => write.flush(), delayMs);\n\n args.onUndoable?.({\n resource,\n kind,\n id,\n strategy: \"delay\",\n delayMs,\n commit: () => write.flush(),\n undo: async () => {\n if (write.dropped) return true;\n if (write.state !== \"waiting\") return false;\n settle();\n takeBack(reg, write);\n void invalidateResource(queryClient, resource);\n resolveSent(undefined);\n return true;\n },\n });\n\n return { status: \"applied\" };\n}\n"]}
|
package/dist/dates.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@marktiderman/genesis-core/dates`: calendar days on a person's clock.
|
|
3
|
+
*
|
|
4
|
+
* A "day" here is a `YYYY-MM-DD` string: the date on some time zone's wall
|
|
5
|
+
* clock. Which zone is the whole question. `new Date().toISOString().slice(0, 10)`
|
|
6
|
+
* is the day in UTC, which is tomorrow for an evening in the Americas and
|
|
7
|
+
* yesterday for a morning in Asia. The browser's zone is the device's, not
|
|
8
|
+
* necessarily the person's, and a server's is usually UTC. So every function
|
|
9
|
+
* here takes the zone, and `personDay` picks it in one order everywhere: the
|
|
10
|
+
* person's saved zone, then the device's, then UTC.
|
|
11
|
+
*
|
|
12
|
+
* No dependencies: `Intl.DateTimeFormat` does the zone arithmetic, so daylight
|
|
13
|
+
* saving is right wherever the runtime's time zone data is.
|
|
14
|
+
*
|
|
15
|
+
* @packageDocumentation
|
|
16
|
+
*/
|
|
17
|
+
/** `YYYY-MM-DD`. */
|
|
18
|
+
type Day = string;
|
|
19
|
+
/** Whether `value` is a real `YYYY-MM-DD` day (not `2026-02-30`). @stability Beta */
|
|
20
|
+
declare function isDay(value: unknown): value is Day;
|
|
21
|
+
/** Whether the runtime knows `zone` (`"America/Denver"`). @stability Beta */
|
|
22
|
+
declare function isTimeZone(zone: unknown): zone is string;
|
|
23
|
+
/** The device's (or server's) zone, `"UTC"` when the runtime can't say. @stability Beta */
|
|
24
|
+
declare function deviceTimeZone(): string;
|
|
25
|
+
/** The wall clock in a zone at one instant. `weekday` is 0 for Sunday. @stability Beta */
|
|
26
|
+
interface WallClock {
|
|
27
|
+
year: number;
|
|
28
|
+
month: number;
|
|
29
|
+
day: number;
|
|
30
|
+
hour: number;
|
|
31
|
+
minute: number;
|
|
32
|
+
second: number;
|
|
33
|
+
weekday: number;
|
|
34
|
+
}
|
|
35
|
+
/** What the clock on the wall in `zone` says at `at`. @stability Beta */
|
|
36
|
+
declare function wallClock(zone: string, at?: Date): WallClock;
|
|
37
|
+
/** The day on `zone`'s clock at `at` (default now). @stability Beta */
|
|
38
|
+
declare function dayIn(zone: string, at?: Date): Day;
|
|
39
|
+
/** Someone whose days are counted: their saved zone, when they have one. */
|
|
40
|
+
interface PersonClock {
|
|
41
|
+
timeZone?: string | null | undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The zone a person's days are counted in: their saved zone if the runtime
|
|
45
|
+
* knows it, else the device's, else UTC. On a server, pass the person's zone:
|
|
46
|
+
* the server's own is rarely theirs.
|
|
47
|
+
*
|
|
48
|
+
* @stability Beta
|
|
49
|
+
*/
|
|
50
|
+
declare function personTimeZone(person?: PersonClock | null): string;
|
|
51
|
+
/**
|
|
52
|
+
* Today (or the day at `at`) for this person: `dayIn(personTimeZone(person), at)`.
|
|
53
|
+
*
|
|
54
|
+
* ```ts
|
|
55
|
+
* const today = personDay(profile); // "2026-10-26" on their clock
|
|
56
|
+
* const dueToday = tasks.filter((t) => t.due_on === today);
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @stability Beta
|
|
60
|
+
*/
|
|
61
|
+
declare function personDay(person?: PersonClock | null, at?: Date): Day;
|
|
62
|
+
/** `day` moved by `days` (negative goes back). Calendar arithmetic: no zone, no daylight saving. @stability Beta */
|
|
63
|
+
declare function addDays(day: Day, days: number): Day;
|
|
64
|
+
/** Whole days from `from` to `to` (`to` − `from`; negative when `to` is earlier). @stability Beta */
|
|
65
|
+
declare function daysBetween(from: Day, to: Day): number;
|
|
66
|
+
/** The weekday of a day, 0 for Sunday. @stability Beta */
|
|
67
|
+
declare function weekdayOf(day: Day): number;
|
|
68
|
+
/** The first day of `day`'s week, with weeks starting on `weekStartsOn` (0 Sunday … 6 Saturday; default 1, Monday). @stability Beta */
|
|
69
|
+
declare function startOfWeek(day: Day, weekStartsOn?: number): Day;
|
|
70
|
+
/**
|
|
71
|
+
* The instant `day` starts on `zone`'s clock: what to compare `created_at`
|
|
72
|
+
* with for "since midnight". Where midnight doesn't exist (a daylight-saving
|
|
73
|
+
* jump at 00:00), it's the first instant of the day that does.
|
|
74
|
+
*
|
|
75
|
+
* @stability Beta
|
|
76
|
+
*/
|
|
77
|
+
declare function startOfDayIn(day: Day, zone: string): Date;
|
|
78
|
+
/** The `[start, end)` instants of `day` on `zone`'s clock (23 or 25 hours on daylight-saving days). @stability Beta */
|
|
79
|
+
declare function dayRangeIn(day: Day, zone: string): {
|
|
80
|
+
start: Date;
|
|
81
|
+
end: Date;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export { type Day, type PersonClock, type WallClock, addDays, dayIn, dayRangeIn, daysBetween, deviceTimeZone, isDay, isTimeZone, personDay, personTimeZone, startOfDayIn, startOfWeek, wallClock, weekdayOf };
|
package/dist/dates.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// src/dates.ts
|
|
2
|
+
var DAY = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
3
|
+
function isDay(value) {
|
|
4
|
+
if (typeof value !== "string") return false;
|
|
5
|
+
const m = DAY.exec(value);
|
|
6
|
+
if (!m) return false;
|
|
7
|
+
const d = new Date(Date.UTC(Number(m[1]), Number(m[2]) - 1, Number(m[3])));
|
|
8
|
+
return d.getUTCFullYear() === Number(m[1]) && d.getUTCMonth() === Number(m[2]) - 1 && d.getUTCDate() === Number(m[3]);
|
|
9
|
+
}
|
|
10
|
+
function assertDay(day, where) {
|
|
11
|
+
if (!isDay(day)) throw new RangeError(`${where}: "${String(day)}" is not a YYYY-MM-DD day`);
|
|
12
|
+
const m = DAY.exec(day);
|
|
13
|
+
return [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
14
|
+
}
|
|
15
|
+
var formatters = /* @__PURE__ */ new Map();
|
|
16
|
+
function isTimeZone(zone) {
|
|
17
|
+
if (typeof zone !== "string" || !zone) return false;
|
|
18
|
+
if (formatters.has(zone)) return true;
|
|
19
|
+
try {
|
|
20
|
+
new Intl.DateTimeFormat("en-US", { timeZone: zone });
|
|
21
|
+
return true;
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function deviceTimeZone() {
|
|
27
|
+
try {
|
|
28
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
29
|
+
} catch {
|
|
30
|
+
return "UTC";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function partsFormatter(zone) {
|
|
34
|
+
let f = formatters.get(zone);
|
|
35
|
+
if (!f) {
|
|
36
|
+
f = new Intl.DateTimeFormat("en-US", {
|
|
37
|
+
timeZone: zone,
|
|
38
|
+
hourCycle: "h23",
|
|
39
|
+
year: "numeric",
|
|
40
|
+
month: "2-digit",
|
|
41
|
+
day: "2-digit",
|
|
42
|
+
hour: "2-digit",
|
|
43
|
+
minute: "2-digit",
|
|
44
|
+
second: "2-digit",
|
|
45
|
+
weekday: "short"
|
|
46
|
+
});
|
|
47
|
+
formatters.set(zone, f);
|
|
48
|
+
}
|
|
49
|
+
return f;
|
|
50
|
+
}
|
|
51
|
+
var WEEKDAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
52
|
+
function wallClock(zone, at = /* @__PURE__ */ new Date()) {
|
|
53
|
+
if (!isTimeZone(zone)) throw new RangeError(`wallClock: unknown time zone "${zone}"`);
|
|
54
|
+
const parts = {};
|
|
55
|
+
for (const p of partsFormatter(zone).formatToParts(at)) parts[p.type] = p.value;
|
|
56
|
+
return {
|
|
57
|
+
year: Number(parts["year"]),
|
|
58
|
+
month: Number(parts["month"]),
|
|
59
|
+
day: Number(parts["day"]),
|
|
60
|
+
hour: Number(parts["hour"]),
|
|
61
|
+
minute: Number(parts["minute"]),
|
|
62
|
+
second: Number(parts["second"]),
|
|
63
|
+
weekday: WEEKDAYS.indexOf(parts["weekday"] ?? "")
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
var pad = (n, width = 2) => String(n).padStart(width, "0");
|
|
67
|
+
var dayOf = (y, m, d) => `${pad(y, 4)}-${pad(m)}-${pad(d)}`;
|
|
68
|
+
function dayIn(zone, at = /* @__PURE__ */ new Date()) {
|
|
69
|
+
const c = wallClock(zone, at);
|
|
70
|
+
return dayOf(c.year, c.month, c.day);
|
|
71
|
+
}
|
|
72
|
+
function personTimeZone(person) {
|
|
73
|
+
const saved = person?.timeZone;
|
|
74
|
+
return saved && isTimeZone(saved) ? saved : deviceTimeZone();
|
|
75
|
+
}
|
|
76
|
+
function personDay(person, at = /* @__PURE__ */ new Date()) {
|
|
77
|
+
return dayIn(personTimeZone(person), at);
|
|
78
|
+
}
|
|
79
|
+
function addDays(day, days) {
|
|
80
|
+
const [y, m, d] = assertDay(day, "addDays");
|
|
81
|
+
if (!Number.isInteger(days)) throw new RangeError(`addDays: ${days} is not a whole number of days`);
|
|
82
|
+
const t = new Date(Date.UTC(y, m - 1, d + days));
|
|
83
|
+
return dayOf(t.getUTCFullYear(), t.getUTCMonth() + 1, t.getUTCDate());
|
|
84
|
+
}
|
|
85
|
+
function daysBetween(from, to) {
|
|
86
|
+
const [y1, m1, d1] = assertDay(from, "daysBetween");
|
|
87
|
+
const [y2, m2, d2] = assertDay(to, "daysBetween");
|
|
88
|
+
return Math.round((Date.UTC(y2, m2 - 1, d2) - Date.UTC(y1, m1 - 1, d1)) / 864e5);
|
|
89
|
+
}
|
|
90
|
+
function weekdayOf(day) {
|
|
91
|
+
const [y, m, d] = assertDay(day, "weekdayOf");
|
|
92
|
+
return new Date(Date.UTC(y, m - 1, d)).getUTCDay();
|
|
93
|
+
}
|
|
94
|
+
function startOfWeek(day, weekStartsOn = 1) {
|
|
95
|
+
if (!Number.isInteger(weekStartsOn) || weekStartsOn < 0 || weekStartsOn > 6) throw new RangeError("startOfWeek: weekStartsOn is 0 to 6");
|
|
96
|
+
return addDays(day, -((weekdayOf(day) - weekStartsOn + 7) % 7));
|
|
97
|
+
}
|
|
98
|
+
function startOfDayIn(day, zone) {
|
|
99
|
+
const [y, m, d] = assertDay(day, "startOfDayIn");
|
|
100
|
+
const target = Date.UTC(y, m - 1, d);
|
|
101
|
+
let at = target;
|
|
102
|
+
for (let i = 0; i < 2; i++) {
|
|
103
|
+
const c = wallClock(zone, new Date(at));
|
|
104
|
+
const shown = Date.UTC(c.year, c.month - 1, c.day, c.hour, c.minute, c.second);
|
|
105
|
+
at -= shown - target;
|
|
106
|
+
}
|
|
107
|
+
while (dayIn(zone, new Date(at)) < day) at += 15 * 6e4;
|
|
108
|
+
while (dayIn(zone, new Date(at - 1)) === day) at -= 15 * 6e4;
|
|
109
|
+
return new Date(at);
|
|
110
|
+
}
|
|
111
|
+
function dayRangeIn(day, zone) {
|
|
112
|
+
return { start: startOfDayIn(day, zone), end: startOfDayIn(addDays(day, 1), zone) };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export { addDays, dayIn, dayRangeIn, daysBetween, deviceTimeZone, isDay, isTimeZone, personDay, personTimeZone, startOfDayIn, startOfWeek, wallClock, weekdayOf };
|
|
116
|
+
//# sourceMappingURL=dates.js.map
|
|
117
|
+
//# sourceMappingURL=dates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dates.ts"],"names":[],"mappings":"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","file":"dates.js","sourcesContent":["/**\n * `@marktiderman/genesis-core/dates`: calendar days on a person's clock.\n *\n * A \"day\" here is a `YYYY-MM-DD` string: the date on some time zone's wall\n * clock. Which zone is the whole question. `new Date().toISOString().slice(0, 10)`\n * is the day in UTC, which is tomorrow for an evening in the Americas and\n * yesterday for a morning in Asia. The browser's zone is the device's, not\n * necessarily the person's, and a server's is usually UTC. So every function\n * here takes the zone, and `personDay` picks it in one order everywhere: the\n * person's saved zone, then the device's, then UTC.\n *\n * No dependencies: `Intl.DateTimeFormat` does the zone arithmetic, so daylight\n * saving is right wherever the runtime's time zone data is.\n *\n * @packageDocumentation\n */\n\n/** `YYYY-MM-DD`. */\nexport type Day = string;\n\nconst DAY = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/** Whether `value` is a real `YYYY-MM-DD` day (not `2026-02-30`). @stability Beta */\nexport function isDay(value: unknown): value is Day {\n if (typeof value !== \"string\") return false;\n const m = DAY.exec(value);\n if (!m) return false;\n const d = new Date(Date.UTC(Number(m[1]), Number(m[2]) - 1, Number(m[3])));\n return d.getUTCFullYear() === Number(m[1]) && d.getUTCMonth() === Number(m[2]) - 1 && d.getUTCDate() === Number(m[3]);\n}\n\nfunction assertDay(day: Day, where: string): [number, number, number] {\n if (!isDay(day)) throw new RangeError(`${where}: \"${String(day)}\" is not a YYYY-MM-DD day`);\n const m = DAY.exec(day)!;\n return [Number(m[1]), Number(m[2]), Number(m[3])];\n}\n\n// One formatter per zone, made once: building an Intl.DateTimeFormat is the slow part.\nconst formatters = new Map<string, Intl.DateTimeFormat>();\n\n/** Whether the runtime knows `zone` (`\"America/Denver\"`). @stability Beta */\nexport function isTimeZone(zone: unknown): zone is string {\n if (typeof zone !== \"string\" || !zone) return false;\n if (formatters.has(zone)) return true;\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: zone });\n return true;\n } catch {\n return false;\n }\n}\n\n/** The device's (or server's) zone, `\"UTC\"` when the runtime can't say. @stability Beta */\nexport function deviceTimeZone(): string {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone || \"UTC\";\n } catch {\n return \"UTC\";\n }\n}\n\nfunction partsFormatter(zone: string): Intl.DateTimeFormat {\n let f = formatters.get(zone);\n if (!f) {\n f = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: zone,\n hourCycle: \"h23\",\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n weekday: \"short\",\n });\n formatters.set(zone, f);\n }\n return f;\n}\n\nconst WEEKDAYS = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n\n/** The wall clock in a zone at one instant. `weekday` is 0 for Sunday. @stability Beta */\nexport interface WallClock {\n year: number;\n month: number;\n day: number;\n hour: number;\n minute: number;\n second: number;\n weekday: number;\n}\n\n/** What the clock on the wall in `zone` says at `at`. @stability Beta */\nexport function wallClock(zone: string, at: Date = new Date()): WallClock {\n if (!isTimeZone(zone)) throw new RangeError(`wallClock: unknown time zone \"${zone}\"`);\n const parts: Record<string, string> = {};\n for (const p of partsFormatter(zone).formatToParts(at)) parts[p.type] = p.value;\n return {\n year: Number(parts[\"year\"]),\n month: Number(parts[\"month\"]),\n day: Number(parts[\"day\"]),\n hour: Number(parts[\"hour\"]),\n minute: Number(parts[\"minute\"]),\n second: Number(parts[\"second\"]),\n weekday: WEEKDAYS.indexOf(parts[\"weekday\"] ?? \"\"),\n };\n}\n\nconst pad = (n: number, width = 2) => String(n).padStart(width, \"0\");\nconst dayOf = (y: number, m: number, d: number): Day => `${pad(y, 4)}-${pad(m)}-${pad(d)}`;\n\n/** The day on `zone`'s clock at `at` (default now). @stability Beta */\nexport function dayIn(zone: string, at: Date = new Date()): Day {\n const c = wallClock(zone, at);\n return dayOf(c.year, c.month, c.day);\n}\n\n/** Someone whose days are counted: their saved zone, when they have one. */\nexport interface PersonClock {\n timeZone?: string | null | undefined;\n}\n\n/**\n * The zone a person's days are counted in: their saved zone if the runtime\n * knows it, else the device's, else UTC. On a server, pass the person's zone:\n * the server's own is rarely theirs.\n *\n * @stability Beta\n */\nexport function personTimeZone(person?: PersonClock | null): string {\n const saved = person?.timeZone;\n return saved && isTimeZone(saved) ? saved : deviceTimeZone();\n}\n\n/**\n * Today (or the day at `at`) for this person: `dayIn(personTimeZone(person), at)`.\n *\n * ```ts\n * const today = personDay(profile); // \"2026-10-26\" on their clock\n * const dueToday = tasks.filter((t) => t.due_on === today);\n * ```\n *\n * @stability Beta\n */\nexport function personDay(person?: PersonClock | null, at: Date = new Date()): Day {\n return dayIn(personTimeZone(person), at);\n}\n\n/** `day` moved by `days` (negative goes back). Calendar arithmetic: no zone, no daylight saving. @stability Beta */\nexport function addDays(day: Day, days: number): Day {\n const [y, m, d] = assertDay(day, \"addDays\");\n if (!Number.isInteger(days)) throw new RangeError(`addDays: ${days} is not a whole number of days`);\n const t = new Date(Date.UTC(y, m - 1, d + days));\n return dayOf(t.getUTCFullYear(), t.getUTCMonth() + 1, t.getUTCDate());\n}\n\n/** Whole days from `from` to `to` (`to` − `from`; negative when `to` is earlier). @stability Beta */\nexport function daysBetween(from: Day, to: Day): number {\n const [y1, m1, d1] = assertDay(from, \"daysBetween\");\n const [y2, m2, d2] = assertDay(to, \"daysBetween\");\n return Math.round((Date.UTC(y2, m2 - 1, d2) - Date.UTC(y1, m1 - 1, d1)) / 86_400_000);\n}\n\n/** The weekday of a day, 0 for Sunday. @stability Beta */\nexport function weekdayOf(day: Day): number {\n const [y, m, d] = assertDay(day, \"weekdayOf\");\n return new Date(Date.UTC(y, m - 1, d)).getUTCDay();\n}\n\n/** The first day of `day`'s week, with weeks starting on `weekStartsOn` (0 Sunday … 6 Saturday; default 1, Monday). @stability Beta */\nexport function startOfWeek(day: Day, weekStartsOn = 1): Day {\n if (!Number.isInteger(weekStartsOn) || weekStartsOn < 0 || weekStartsOn > 6) throw new RangeError(\"startOfWeek: weekStartsOn is 0 to 6\");\n return addDays(day, -((weekdayOf(day) - weekStartsOn + 7) % 7));\n}\n\n/**\n * The instant `day` starts on `zone`'s clock: what to compare `created_at`\n * with for \"since midnight\". Where midnight doesn't exist (a daylight-saving\n * jump at 00:00), it's the first instant of the day that does.\n *\n * @stability Beta\n */\nexport function startOfDayIn(day: Day, zone: string): Date {\n const [y, m, d] = assertDay(day, \"startOfDayIn\");\n const target = Date.UTC(y, m - 1, d);\n // Guess the instant as if the zone were UTC, then correct by the zone's offset there, twice\n // (the second pass settles a guess that landed across a transition).\n let at = target;\n for (let i = 0; i < 2; i++) {\n const c = wallClock(zone, new Date(at));\n const shown = Date.UTC(c.year, c.month - 1, c.day, c.hour, c.minute, c.second);\n at -= shown - target;\n }\n // Midnight skipped by a transition: step forward to the first instant on that day.\n while (dayIn(zone, new Date(at)) < day) at += 15 * 60_000;\n while (dayIn(zone, new Date(at - 1)) === day) at -= 15 * 60_000;\n return new Date(at);\n}\n\n/** The `[start, end)` instants of `day` on `zone`'s clock (23 or 25 hours on daylight-saving days). @stability Beta */\nexport function dayRangeIn(day: Day, zone: string): { start: Date; end: Date } {\n return { start: startOfDayIn(day, zone), end: startOfDayIn(addDays(day, 1), zone) };\n}\n"]}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/** A draft's value: a flat map of fields (a table or a list is one field). */
|
|
2
|
+
type DraftValue = Record<string, unknown>;
|
|
3
|
+
type DraftStatus = "idle" | "saving" | "saved" | "error" | "stopped";
|
|
4
|
+
interface DraftSeed<V extends DraftValue, R> {
|
|
5
|
+
/** The row as the server has it, or null before the first save. */
|
|
6
|
+
row: R | null;
|
|
7
|
+
/** The value to start from: the row's, or a blank one. */
|
|
8
|
+
value: V;
|
|
9
|
+
}
|
|
10
|
+
/** What `adopt` found: the row it merged into, or a row already finished elsewhere. */
|
|
11
|
+
type DraftAdoption<R> = {
|
|
12
|
+
row: R;
|
|
13
|
+
} | {
|
|
14
|
+
final: R;
|
|
15
|
+
};
|
|
16
|
+
interface DraftOptions<V extends DraftValue, R> {
|
|
17
|
+
seed: DraftSeed<V, R>;
|
|
18
|
+
/**
|
|
19
|
+
* Changes when the server's copy changes in a way that wins over edits here
|
|
20
|
+
* (it was sent from another tab, a reviewer returned it). The draft then
|
|
21
|
+
* starts again from the new `seed`; see `onRevision`.
|
|
22
|
+
*/
|
|
23
|
+
revision?: string | undefined;
|
|
24
|
+
/** The first write: add the row. `keepalive` is set for the save made as the page closes. */
|
|
25
|
+
create: (value: V, hints: {
|
|
26
|
+
keepalive: boolean;
|
|
27
|
+
}) => Promise<R>;
|
|
28
|
+
/** Later writes. `keepalive` is set for the save made as the page closes. */
|
|
29
|
+
update: (row: R, value: V, hints: {
|
|
30
|
+
keepalive: boolean;
|
|
31
|
+
}) => Promise<R>;
|
|
32
|
+
/** The value a saved row holds. */
|
|
33
|
+
toValue: (row: R) => V;
|
|
34
|
+
/** A row's identity, to tell the same row from another. Default: its `id`. */
|
|
35
|
+
idOf?: ((row: R) => unknown) | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* The first write found a row already there (another tab started it): merge
|
|
38
|
+
* into it, or report that it is already finished. `dirty` names the fields
|
|
39
|
+
* changed here since the draft started; only those should be written over
|
|
40
|
+
* the existing row's. Without `adopt`, the duplicate is an error.
|
|
41
|
+
*/
|
|
42
|
+
adopt?: ((value: V, dirty: ReadonlySet<string>) => Promise<DraftAdoption<R>>) | undefined;
|
|
43
|
+
/** Whether a failed `create` means "a row is already there". Default: a `duplicate` write outcome. */
|
|
44
|
+
isDuplicate?: ((error: unknown) => boolean) | undefined;
|
|
45
|
+
/** Never add a row for this value. Default: no field has anything in it. */
|
|
46
|
+
isEmpty?: ((value: V) => boolean) | undefined;
|
|
47
|
+
/** Default: the same JSON, whatever the order of object keys. */
|
|
48
|
+
equal?: ((a: V, b: V) => boolean) | undefined;
|
|
49
|
+
/** How long after the last change to save. Default 800 ms. */
|
|
50
|
+
delayMs?: number | undefined;
|
|
51
|
+
/** False: nothing is written (someone else's draft, or one already sent). Default true. */
|
|
52
|
+
enabled?: boolean | undefined;
|
|
53
|
+
/** After each save, with the row as saved: write it into the app's cache here. */
|
|
54
|
+
onSaved?: ((row: R) => void) | undefined;
|
|
55
|
+
/** `adopt` found the row finished elsewhere: nothing more is saved. */
|
|
56
|
+
onFinal?: ((row: R) => void) | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* `revision` changed with edits not yet saved: return the value to keep (a
|
|
59
|
+
* merge), or null to drop the edits for the server's. Default: drop them.
|
|
60
|
+
*/
|
|
61
|
+
onRevision?: ((pending: V, next: DraftSeed<V, R>) => V | null) | undefined;
|
|
62
|
+
/** Whether a failed write is worth trying again. Default: network failures only, never refusals. */
|
|
63
|
+
isRetryable?: ((error: unknown) => boolean) | undefined;
|
|
64
|
+
/** Tries after the first, on a retryable failure. Default 3. */
|
|
65
|
+
retries?: number | undefined;
|
|
66
|
+
/** The first retry's wait; each later one doubles it. Default 500 ms. */
|
|
67
|
+
retryDelayMs?: number | undefined;
|
|
68
|
+
/** The words shown for a failed save. Default: the write error's own plain message. */
|
|
69
|
+
messageOf?: ((error: unknown) => string) | undefined;
|
|
70
|
+
}
|
|
71
|
+
interface DraftState<V extends DraftValue, R> {
|
|
72
|
+
value: V;
|
|
73
|
+
row: R | null;
|
|
74
|
+
status: DraftStatus;
|
|
75
|
+
/** Why the last save failed, in plain words; null once one succeeds. */
|
|
76
|
+
error: string | null;
|
|
77
|
+
/** True after a new revision replaced edits that weren't saved, so the page can say so. */
|
|
78
|
+
discarded: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Changes when the value is replaced from outside the editor (merged with
|
|
81
|
+
* another tab's row, or a new revision): remount the editor on it.
|
|
82
|
+
*/
|
|
83
|
+
key: number;
|
|
84
|
+
}
|
|
85
|
+
declare const DEFAULT_DRAFT_DELAY_MS = 800;
|
|
86
|
+
declare const DRAFT_NOT_SAVED = "Your changes weren't saved.";
|
|
87
|
+
/** JSON with object keys sorted, so values compare equal whatever order a store keeps keys in. */
|
|
88
|
+
declare function stableJson(value: unknown): string;
|
|
89
|
+
/** The default `isRetryable`: a request that never reached the store. A refusal never is. */
|
|
90
|
+
declare function isNetworkFailure(error: unknown): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* The rules of a draft, without React: one write at a time, add then change,
|
|
93
|
+
* no write when nothing changed or for an empty value, merge into a row
|
|
94
|
+
* another tab started, start again on a new revision, retry network failures,
|
|
95
|
+
* and a final write (`commit`) that ends it.
|
|
96
|
+
*/
|
|
97
|
+
declare class DraftController<V extends DraftValue, R> {
|
|
98
|
+
private readonly options;
|
|
99
|
+
private state;
|
|
100
|
+
/** The value as last saved (or as loaded): what "unchanged" compares with. */
|
|
101
|
+
private saved;
|
|
102
|
+
/** Fields changed here since the draft started (or since the last revision). */
|
|
103
|
+
private dirty;
|
|
104
|
+
private chain;
|
|
105
|
+
private timer;
|
|
106
|
+
private revision;
|
|
107
|
+
private ended;
|
|
108
|
+
/** Bumped by each new revision: a save that started before it lands on nothing. */
|
|
109
|
+
private generation;
|
|
110
|
+
/** The value of the write in flight, so a seed that is only that write coming back is known. */
|
|
111
|
+
private inflight;
|
|
112
|
+
private listeners;
|
|
113
|
+
constructor(options: () => DraftOptions<V, R>);
|
|
114
|
+
readonly subscribe: (listener: () => void) => () => void;
|
|
115
|
+
readonly getState: () => DraftState<V, R>;
|
|
116
|
+
/** Edits this draft would still save. */
|
|
117
|
+
readonly pending: () => boolean;
|
|
118
|
+
/** The editor's new value: its changed fields are noted, and it's saved a moment after the last change. */
|
|
119
|
+
readonly set: (value: V) => void;
|
|
120
|
+
/** Save now, after any write already running. Resolves once written or failed; never rejects. */
|
|
121
|
+
readonly flush: (hints?: {
|
|
122
|
+
keepalive?: boolean;
|
|
123
|
+
}) => Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* The final write (a submit), after any write in flight, given the row so far
|
|
126
|
+
* (null before the first save) and the value. On success nothing more is
|
|
127
|
+
* saved and the draft is `stopped`; on failure it is thrown to the caller and
|
|
128
|
+
* autosave carries on.
|
|
129
|
+
*/
|
|
130
|
+
readonly commit: (write: (row: R | null, value: V) => Promise<R>) => Promise<R>;
|
|
131
|
+
/**
|
|
132
|
+
* The server's seed again. Ignored unless `revision` changed. Then, in order:
|
|
133
|
+
* - the seed is this draft's own save coming back (the same row, holding what
|
|
134
|
+
* was last saved or is being saved): take its row and keep every edit;
|
|
135
|
+
* - it is another row, with edits pending here: those are saved to the row
|
|
136
|
+
* they belong to first, then the draft moves to the new one;
|
|
137
|
+
* - otherwise the server's copy wins: the draft starts again from it, keeping
|
|
138
|
+
* only what `onRevision` returns.
|
|
139
|
+
*/
|
|
140
|
+
readonly reseed: (seed: DraftSeed<V, R>, revision: string | undefined) => void;
|
|
141
|
+
/** Call when `enabled` may have changed: off stops saving; back on saves what's pending. */
|
|
142
|
+
readonly sync: () => void;
|
|
143
|
+
private startFrom;
|
|
144
|
+
private enabled;
|
|
145
|
+
private active;
|
|
146
|
+
private same;
|
|
147
|
+
private schedule;
|
|
148
|
+
private clearTimer;
|
|
149
|
+
private patch;
|
|
150
|
+
private save;
|
|
151
|
+
/**
|
|
152
|
+
* One save: change the row, or add it (merging on a duplicate), retrying network failures.
|
|
153
|
+
* The row is the one the save started with, never one a later revision brought in.
|
|
154
|
+
*/
|
|
155
|
+
private write;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export { DEFAULT_DRAFT_DELAY_MS, DRAFT_NOT_SAVED, type DraftAdoption, DraftController, type DraftOptions, type DraftSeed, type DraftState, type DraftStatus, type DraftValue, isNetworkFailure, stableJson };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"draft-controller.js"}
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -2,13 +2,55 @@ export { UseResourceOptions, UseResourceReturn, useResource } from './use-resour
|
|
|
2
2
|
export { UseOneOptions, useOne } from './use-one.js';
|
|
3
3
|
export { InfinitePageParam, UseInfiniteResourceOptions, UseInfiniteResourceReturn, useInfiniteResource } from './use-infinite-resource.js';
|
|
4
4
|
export { useCapabilities } from './use-capabilities.js';
|
|
5
|
+
export { UseWriteOptions, UseWriteReturn, WRITE_FAILED, useWrite } from './use-write.js';
|
|
6
|
+
export { UseDraftReturn, useDraft } from './use-draft.js';
|
|
7
|
+
export { DEFAULT_DRAFT_DELAY_MS, DRAFT_NOT_SAVED, DraftAdoption, DraftController, DraftOptions, DraftSeed, DraftState, DraftStatus, DraftValue, isNetworkFailure, stableJson } from './draft-controller.js';
|
|
8
|
+
import * as react from 'react';
|
|
9
|
+
import { ReactNode } from 'react';
|
|
10
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
5
11
|
export { DEFAULT_LIVE_DEBOUNCE_MS, LiveOptions } from './use-live.js';
|
|
6
12
|
export { UseResourceFormOptions, UseResourceFormReturn, buildArrayItemDefaults, useResourceForm } from './use-resource-form.js';
|
|
7
13
|
export { UseWizardReturn, WizardStep, useWizard } from './use-wizard.js';
|
|
8
|
-
export { DEFAULT_UNDO_DELAY_MS, MutationMode, MutationModeOptions, UndoableWrite, pendingWriteCount } from './mutation-mode.js';
|
|
14
|
+
export { DEFAULT_UNDO_DELAY_MS, MutationMode, MutationModeOptions, UndoableWrite, dropPendingWrites, flushPendingWrites, pendingWriteCount } from './mutation-mode.js';
|
|
9
15
|
export { DEFAULT_UNSAVED_CHANGES_MESSAGE, UseUnsavedChangesGuardOptions, UseUnsavedChangesGuardReturn, useUnsavedChangesGuard } from './use-unsaved-changes-guard.js';
|
|
10
|
-
import '
|
|
11
|
-
import '../types-CS9UpxQS.js';
|
|
16
|
+
import '../types-B9DDfvWa.js';
|
|
12
17
|
import '../types-C7FJtFXV.js';
|
|
13
18
|
import '../form-types.js';
|
|
14
19
|
import 'react-hook-form';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Empties the query cache for a new viewer: sends the old viewer's waiting
|
|
23
|
+
* undoable writes (the session is still theirs), cancels reads in flight,
|
|
24
|
+
* then removes every query. Call it in the sign-in and sign-out actions,
|
|
25
|
+
* before the session changes.
|
|
26
|
+
*/
|
|
27
|
+
declare function clearViewerCache(queryClient: QueryClient): Promise<void>;
|
|
28
|
+
interface ViewerScopeProps {
|
|
29
|
+
/** The signed-in viewer's id, null when signed out, undefined while the session loads. */
|
|
30
|
+
viewer: string | null | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* The viewer a persisted cache was saved for. When the first known viewer
|
|
33
|
+
* is this one, the restored cache is kept; otherwise it's emptied.
|
|
34
|
+
*/
|
|
35
|
+
persistedViewer?: string | null;
|
|
36
|
+
/** Shown while the session loads (and for the one render a change takes). */
|
|
37
|
+
fallback?: ReactNode;
|
|
38
|
+
children: ReactNode;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Keeps one viewer's cached data from ever showing to the next. Children
|
|
42
|
+
* render only once the viewer is known, under a key of that viewer, so a
|
|
43
|
+
* sign-out or a new person signing in unmounts every screen and its queries
|
|
44
|
+
* before the cache is emptied and the new viewer's screens mount fresh. The
|
|
45
|
+
* first known viewer empties a restored cache too, unless it's the
|
|
46
|
+
* `persistedViewer` it was saved for.
|
|
47
|
+
*
|
|
48
|
+
* ```tsx
|
|
49
|
+
* <ViewerScope viewer={session === undefined ? undefined : (session?.user.id ?? null)}>
|
|
50
|
+
* <App />
|
|
51
|
+
* </ViewerScope>
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
declare function ViewerScope({ viewer, persistedViewer, fallback, children }: ViewerScopeProps): react.JSX.Element;
|
|
55
|
+
|
|
56
|
+
export { ViewerScope, type ViewerScopeProps, clearViewerCache };
|