@fireproof/core 0.19.121 → 0.20.0-dev-preview-06

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. package/README.md +3 -2
  2. package/deno/index.d.ts +7 -0
  3. package/deno/index.js +66 -0
  4. package/deno/index.js.map +1 -0
  5. package/deno/metafile-esm.json +1 -0
  6. package/deno.json +2 -3
  7. package/index.cjs +1819 -1051
  8. package/index.cjs.map +1 -1
  9. package/index.d.cts +746 -333
  10. package/index.d.ts +746 -333
  11. package/index.js +1792 -1026
  12. package/index.js.map +1 -1
  13. package/metafile-cjs.json +1 -1
  14. package/metafile-esm.json +1 -1
  15. package/node/index.cjs +16 -293
  16. package/node/index.cjs.map +1 -1
  17. package/node/index.d.cts +4 -40
  18. package/node/index.d.ts +4 -40
  19. package/node/index.js +22 -237
  20. package/node/index.js.map +1 -1
  21. package/node/metafile-cjs.json +1 -1
  22. package/node/metafile-esm.json +1 -1
  23. package/package.json +12 -4
  24. package/react/index.cjs.map +1 -1
  25. package/react/index.js.map +1 -1
  26. package/react/metafile-cjs.json +1 -1
  27. package/react/metafile-esm.json +1 -1
  28. package/tests/blockstore/fp-envelope.test.ts-off +65 -0
  29. package/tests/blockstore/interceptor-gateway.test.ts +122 -0
  30. package/tests/blockstore/keyed-crypto-indexdb-file.test.ts +130 -0
  31. package/tests/blockstore/keyed-crypto.test.ts +73 -118
  32. package/tests/blockstore/loader.test.ts +18 -9
  33. package/tests/blockstore/store.test.ts +40 -31
  34. package/tests/blockstore/transaction.test.ts +14 -13
  35. package/tests/fireproof/all-gateway.test.ts +283 -213
  36. package/tests/fireproof/cars/bafkreidxwt2nhvbl4fnqfw3ctlt6zbrir4kqwmjo5im6rf4q5si27kgo2i.ts +324 -316
  37. package/tests/fireproof/crdt.test.ts +78 -19
  38. package/tests/fireproof/database.test.ts +225 -29
  39. package/tests/fireproof/fireproof.test.ts +92 -73
  40. package/tests/fireproof/hello.test.ts +17 -13
  41. package/tests/fireproof/indexer.test.ts +67 -43
  42. package/tests/fireproof/utils.test.ts +47 -6
  43. package/tests/gateway/file/loader-config.test.ts +307 -0
  44. package/tests/gateway/fp-envelope-serialize.test.ts +256 -0
  45. package/tests/gateway/indexdb/loader-config.test.ts +79 -0
  46. package/tests/helpers.ts +44 -17
  47. package/tests/react/useFireproof.test.tsx +1 -1
  48. package/tests/www/todo.html +24 -3
  49. package/web/index.cjs +102 -116
  50. package/web/index.cjs.map +1 -1
  51. package/web/index.d.cts +15 -29
  52. package/web/index.d.ts +15 -29
  53. package/web/index.js +91 -105
  54. package/web/index.js.map +1 -1
  55. package/web/metafile-cjs.json +1 -1
  56. package/web/metafile-esm.json +1 -1
  57. package/node/chunk-4A4RAVNS.js +0 -17
  58. package/node/chunk-4A4RAVNS.js.map +0 -1
  59. package/node/mem-filesystem-LPPT7QV5.js +0 -40
  60. package/node/mem-filesystem-LPPT7QV5.js.map +0 -1
  61. package/tests/fireproof/config.test.ts +0 -163
  62. /package/tests/blockstore/{fragment-gateway.test.ts → fragment-gateway.test.ts-off} +0 -0
  63. /package/tests/fireproof/{multiple-ledger.test.ts → multiple-database.test.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/react/useFireproof.ts","../../../src/react/useDocument.ts","../../../src/react/useLiveQuery.ts","../../../src/react/useAllDocs.ts","../../../src/react/useChanges.ts"],"sourcesContent":["import type {\n ConfigOpts,\n Database,\n DocFragment,\n DocResponse,\n DocSet,\n DocTypes,\n DocWithId,\n IndexKeyType,\n IndexRow,\n MapFn,\n QueryOpts,\n} from \"@fireproof/core\";\nimport { fireproof } from \"@fireproof/core\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport type { AllDocsQueryOpts, ChangesOptions, ClockHead } from \"@fireproof/core\";\n\nexport interface LiveQueryResult<T extends DocTypes, K extends IndexKeyType, R extends DocFragment = T> {\n readonly docs: DocWithId<T>[];\n readonly rows: IndexRow<K, T, R>[];\n}\n\nexport type UseLiveQuery = <T extends DocTypes, K extends IndexKeyType = string, R extends DocFragment = T>(\n mapFn: string | MapFn<T>,\n query?: QueryOpts<K>,\n initialRows?: IndexRow<K, T, R>[],\n) => LiveQueryResult<T, K, R>;\n\nexport interface AllDocsResult<T extends DocTypes> {\n readonly docs: DocWithId<T>[];\n}\n\nexport interface ChangesResult<T extends DocTypes> {\n readonly docs: DocWithId<T>[];\n}\n\nexport type UseAllDocs = <T extends DocTypes>(query?: AllDocsQueryOpts) => AllDocsResult<T>;\n\nexport type UseChanges = <T extends DocTypes>(since: ClockHead, opts: ChangesOptions) => ChangesResult<T>;\n\ninterface UpdateDocFnOptions {\n readonly replace?: boolean;\n readonly reset?: boolean;\n}\n\ntype UpdateDocFn<T extends DocTypes> = (newDoc?: DocSet<T>, options?: UpdateDocFnOptions) => void;\n\ntype StoreDocFn<T extends DocTypes> = (existingDoc?: DocWithId<T>) => Promise<DocResponse>;\n\ntype DeleteDocFn<T extends DocTypes> = (existingDoc?: DocWithId<T>) => Promise<DocResponse>;\n\nexport type UseDocumentResult<T extends DocTypes> = [DocWithId<T>, UpdateDocFn<T>, StoreDocFn<T>, DeleteDocFn<T>];\n\nexport type UseDocumentInitialDocOrFn<T extends DocTypes> = DocSet<T> | (() => DocSet<T>);\nexport type UseDocument = <T extends DocTypes>(initialDocOrFn: UseDocumentInitialDocOrFn<T>) => UseDocumentResult<T>;\n\nexport interface UseFireproof {\n readonly database: Database;\n /**\n * ## Summary\n *\n * React hook that provides the ability to create/update/save new Fireproof documents into your custom Fireproof database.\n * The creation occurs when you do not pass in an `_id` as part of your initial document -- the database will assign a new\n * one when you call the provided `save` handler. The hook also provides generics support so you can inline your custom type into\n * the invocation to receive type-safety and auto-complete support in your IDE.\n *\n * ## Usage\n *\n * ```tsx\n * const [todo, setTodo, saveTodo] = useDocument<Todo>({\n * text: '',\n * date: Date.now(),\n * completed: false\n * })\n *\n * const [doc, setDoc, saveDoc] = useDocument<Customer>({\n * _id: `${props.customerId}-profile`, // you can imagine `customerId` as a prop passed in\n * name: \"\",\n * company: \"\",\n * startedAt: Date.now()\n * })\n * ```\n *\n * ## Overview\n *\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useLiveQuery` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\n readonly useDocument: UseDocument;\n /**\n * ## Summary\n * React hook that provides access to live query results, enabling real-time updates in your app.\n *\n * ## Usage\n * ```tsx\n * const result = useLiveQuery(\"date\"); // using string key\n * const result = useLiveQuery('date', { limit: 10, descending: true }) // key + options\n * const result = useLiveQuery<CustomType>(\"date\"); // using generics\n * const result = useLiveQuery((doc) => doc.date)); // using map function\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useLiveQuery` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\n readonly useLiveQuery: UseLiveQuery;\n /**\n * ## Summary\n * React hook that provides access to all documents in the database, sorted by `_id`.\n *\n * ## Usage\n * ```tsx\n * const result = useAllDocs({ limit: 10, descending: true }); // with options\n * const result = useAllDocs(); // without options\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useAllDocs` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\n readonly useAllDocs: UseAllDocs;\n /**\n * ## Summary\n * React hook that provides access to all new documents in the database added since the last time the changes was called\n *\n * ## Usage\n * ```tsx\n * const result = useChanges(prevresult.clock,{limit:10}); // with options\n * const result = useChanges(); // without options\n * const database = useChanges.database; // underlying \"useFireproof\" database accessor\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useAllDocs`, `useChanges` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\n readonly useChanges: UseChanges;\n}\n\n/**\n * @deprecated Use the `useFireproof` hook instead\n */\nexport const FireproofCtx = {} as UseFireproof;\n\n/**\n *\n * ## Summary\n *\n * React hook to create a custom-named Fireproof database and provides the utility hooks to query against it.\n *\n * ## Usage\n * ```tsx\n * const { database, useLiveQuery, useDocument } = useFireproof(\"dbname\");\n * const { database, useLiveQuery, useDocument } = useFireproof(\"dbname\", { ...options });\n * ```\n *\n * ## Overview\n *\n * TL;DR: Only use this hook if you need to configure a database name other than the default `useFireproof`.\n *\n * For most applications, using the `useLiveQuery` or `useDocument` hooks exported from `use-fireproof` should\n * suffice for the majority of use-cases. Under the hood, they act against a database named `useFireproof` instantiated with\n * default configurations. However, if you need to do a custom database setup or configure a database name more to your liking\n * than the default `useFireproof`, then use `useFireproof` as it exists for that purpose. It will provide you with the\n * custom database accessor and *lexically scoped* versions of `useLiveQuery` and `useDocument` that act against said\n * custom database.\n *\n */\nexport function useFireproof(name: string | Database = \"useFireproof\", config: ConfigOpts = {}): UseFireproof {\n const database = typeof name === \"string\" ? fireproof(name, config) : name;\n\n function useDocument<T extends DocTypes>(initialDocOrFn: UseDocumentInitialDocOrFn<T>): UseDocumentResult<T> {\n let initialDoc: DocSet<T>;\n if (typeof initialDocOrFn === \"function\") {\n initialDoc = initialDocOrFn();\n } else {\n initialDoc = initialDocOrFn;\n }\n\n // We purposely refetch the docId everytime to check if it has changed\n const docId = initialDoc._id ?? \"\";\n\n // We do not want to force consumers to memoize their initial document so we do it for them.\n // We use the stringified generator function to ensure that the memoization is stable across renders.\n // const initialDoc = useMemo(initialDocFn, [initialDocFn.toString()]);\n const [doc, setDoc] = useState(initialDoc);\n\n const refreshDoc = useCallback(async () => {\n // todo add option for mvcc checks\n const doc = docId ? await database.get<T>(docId).catch(() => initialDoc) : initialDoc;\n setDoc(doc);\n }, [docId]);\n\n const saveDoc: StoreDocFn<T> = useCallback(\n async (existingDoc) => {\n const res = await database.put(existingDoc ?? doc);\n // If the document was created, then we need to update the local state with the new `_id`\n if (!existingDoc && !doc._id) setDoc((d) => ({ ...d, _id: res.id }));\n return res;\n },\n [doc],\n );\n\n const deleteDoc: DeleteDocFn<T> = useCallback(\n async (existingDoc) => {\n const id = existingDoc?._id ?? docId;\n const doc = await database.get<T>(id).catch(() => undefined);\n if (!doc) throw database.logger.Error().Str(\"id\", id).Msg(`Document not found`).AsError();\n const res = await database.del(id);\n setDoc(initialDoc);\n return res;\n },\n [docId, initialDoc],\n );\n\n const updateDoc: UpdateDocFn<T> = useCallback(\n (newDoc, opts = { replace: false, reset: false }) => {\n if (!newDoc) return void (opts.reset ? setDoc(initialDoc) : refreshDoc());\n setDoc((d) => (opts.replace ? (newDoc as DocWithId<T>) : { ...d, ...newDoc }));\n },\n [refreshDoc, initialDoc],\n );\n\n useEffect(() => {\n if (!docId) return;\n return database.subscribe((changes) => {\n if (changes.find((c) => c._id === docId)) {\n void refreshDoc(); // todo use change.value\n }\n });\n }, [docId, refreshDoc]);\n\n useEffect(() => {\n void refreshDoc();\n }, [refreshDoc]);\n\n return [{ _id: docId, ...doc }, updateDoc, saveDoc, deleteDoc];\n }\n\n function useLiveQuery<T extends DocTypes, K extends IndexKeyType = string, R extends DocFragment = T>(\n mapFn: MapFn<T> | string,\n query = {},\n initialRows: IndexRow<K, T, R>[] = [],\n ): LiveQueryResult<T, K, R> {\n const [result, setResult] = useState<LiveQueryResult<T, K, R>>(() => ({\n rows: initialRows,\n docs: initialRows.map((r) => r.doc).filter((r): r is DocWithId<T> => !!r),\n }));\n\n const queryString = useMemo(() => JSON.stringify(query), [query]);\n const mapFnString = useMemo(() => mapFn.toString(), [mapFn]);\n\n const refreshRows = useCallback(async () => {\n const res = await database.query<K, T, R>(mapFn, query);\n setResult({ ...res, docs: res.rows.map((r) => r.doc as DocWithId<T>) });\n }, [mapFnString, queryString]);\n\n useEffect(() => {\n refreshRows(); // Initial data fetch\n return database.subscribe(refreshRows);\n }, [refreshRows]);\n\n return result;\n }\n\n function useAllDocs<T extends DocTypes>(query: AllDocsQueryOpts = {}): AllDocsResult<T> {\n const [result, setResult] = useState<AllDocsResult<T>>({\n docs: [],\n });\n\n const queryString = useMemo(() => JSON.stringify(query), [query]);\n\n const refreshRows = useCallback(async () => {\n const res = await database.allDocs<T>(query);\n setResult({ ...res, docs: res.rows.map((r) => r.value as DocWithId<T>) });\n }, [queryString]);\n\n useEffect(() => {\n refreshRows(); // Initial data fetch\n return database.subscribe(refreshRows);\n }, [refreshRows]);\n\n return result;\n }\n\n function useChanges<T extends DocTypes>(since: ClockHead = [], opts: ChangesOptions = {}): ChangesResult<T> {\n const [result, setResult] = useState<ChangesResult<T>>({\n docs: [],\n });\n\n const queryString = useMemo(() => JSON.stringify(opts), [opts]);\n\n const refreshRows = useCallback(async () => {\n const res = await database.changes<T>(since, opts);\n setResult({ ...res, docs: res.rows.map((r) => r.value as DocWithId<T>) });\n }, [since, queryString]);\n\n useEffect(() => {\n refreshRows(); // Initial data fetch\n return database.subscribe(refreshRows);\n }, [refreshRows]);\n\n return result;\n }\n\n return { database, useLiveQuery, useDocument, useAllDocs, useChanges };\n}\n","import { Database, DocTypes, DocWithId } from \"@fireproof/core\";\n\nimport { UseDocument, UseDocumentResult, useFireproof } from \"./useFireproof.js\";\n\nexport interface TLUseDocument {\n <T extends DocTypes>(initialDoc: DocWithId<T>): UseDocumentResult<T>;\n database: Database;\n}\n\nfunction topLevelUseDocument(...args: Parameters<UseDocument>) {\n const { useDocument, database } = useFireproof();\n (topLevelUseDocument as TLUseDocument).database = database;\n return useDocument(...args);\n}\n\n/**\n * ## Summary\n *\n * React hook that provides the ability to create new Fireproof documents. The creation occurs when\n * you do not pass in an `_id` as part of your initial document -- the database will assign a new one when\n * you call the provided `save` handler This uses the default database named `useFireproof` under the hood which you can also\n * access via the `database` accessor.\n *\n * ## Usage\n *\n * ```tsx\n * const [todo, setTodo, saveTodo] = useDocument(() => ({\n * text: '',\n * date: Date.now(),\n * completed: false\n * }))\n *\n * const [doc, setDoc, saveDoc] = useDocument(() => ({\n * _id: `${props.customerId}-profile`, // you can imagine `customerId` as a prop passed in\n * name: \"\",\n * company: \"\",\n * startedAt: Date.now()\n * }))\n *\n * const database = useDocument.database; // underlying \"useFireproof\" database accessor\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useLiveQuery` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\nexport const useDocument = topLevelUseDocument as TLUseDocument;\n","import { Database, DocFragment, DocTypes, IndexKeyType } from \"@fireproof/core\";\n\nimport { LiveQueryResult, useFireproof, UseLiveQuery } from \"./useFireproof.js\";\n\nexport interface TLUseLiveQuery {\n <T extends DocTypes, K extends IndexKeyType, R extends DocFragment = T>(\n ...args: Parameters<UseLiveQuery>\n ): LiveQueryResult<T, K, R>;\n database: Database;\n}\n\nfunction topLevelUseLiveQuery(...args: Parameters<UseLiveQuery>) {\n const { useLiveQuery, database } = useFireproof();\n (topLevelUseLiveQuery as TLUseLiveQuery).database = database;\n return useLiveQuery(...args);\n}\n\n/**\n * ## Summary\n * React hook that provides access to live query results, enabling real-time updates in your app. This uses\n * the default database named \"useFireproof\" under the hood which you can also access via the `database` accessor.\n *\n * ## Usage\n * ```tsx\n * const results = useLiveQuery(\"date\"); // using string\n * const results = useLiveQuery((doc) => doc.date)); // using map function\n * const database = useLiveQuery.database; // underlying \"useFireproof\" database accessor\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useLiveQuery` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\nexport const useLiveQuery = topLevelUseLiveQuery as TLUseLiveQuery;\n","import { Database, DocTypes } from \"@fireproof/core\";\n\nimport { AllDocsResult, useFireproof, UseAllDocs } from \"./useFireproof.js\";\n\nexport interface TLUseAllDocs {\n <T extends DocTypes>(...args: Parameters<UseAllDocs>): AllDocsResult<T>;\n database: Database;\n}\n\nfunction topLevelUseAllDocs(...args: Parameters<UseAllDocs>) {\n const { useAllDocs, database } = useFireproof();\n (topLevelUseAllDocs as TLUseAllDocs).database = database;\n return useAllDocs(...args);\n}\n\n/**\n * ## Summary\n * React hook that provides access to all documents in the database, sorted by `_id`.\n *\n * ## Usage\n * ```tsx\n * const result = useAllDocs({ limit: 10, descending: true }); // with options\n * const result = useAllDocs(); // without options\n * const database = useAllDocs.database; // underlying \"useFireproof\" database accessor\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useAllDocs` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\nexport const useAllDocs = topLevelUseAllDocs as TLUseAllDocs;\n","import { Database, DocTypes } from \"@fireproof/core\";\n\nimport { ChangesResult, useFireproof, UseChanges } from \"./useFireproof.js\";\n\nexport interface TLUseChanges {\n <T extends DocTypes>(...args: Parameters<UseChanges>): ChangesResult<T>;\n database: Database;\n}\n\nfunction topLevelUseChanges(...args: Parameters<UseChanges>) {\n const { useChanges, database } = useFireproof();\n (topLevelUseChanges as TLUseChanges).database = database;\n return useChanges(...args);\n}\n\n/**\n * ## Summary\n * React hook that provides access to all new documents in the database added since the last time the changes was called\n *\n * ## Usage\n * ```tsx\n * const result = useChanges(prevresult.clock,{limit:10}); // with options\n * const result = useChanges(); // without options\n * const database = useChanges.database; // underlying \"useFireproof\" database accessor\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useAllDocs`, `useChanges` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\nexport const useChanges = topLevelUseChanges as TLUseChanges;\n"],"mappings":"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","names":["useDocument","doc","useLiveQuery","useAllDocs","useChanges","useDocument","useLiveQuery","useAllDocs","useChanges"]}
1
+ {"version":3,"sources":["../../../src/react/useFireproof.ts","../../../src/react/useDocument.ts","../../../src/react/useLiveQuery.ts","../../../src/react/useAllDocs.ts","../../../src/react/useChanges.ts"],"sourcesContent":["import type {\n ConfigOpts,\n DocFragment,\n DocResponse,\n DocSet,\n DocTypes,\n DocWithId,\n IndexKeyType,\n IndexRow,\n Database,\n MapFn,\n QueryOpts,\n} from \"@fireproof/core\";\nimport { fireproof } from \"@fireproof/core\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport type { AllDocsQueryOpts, ChangesOptions, ClockHead } from \"@fireproof/core\";\n\nexport interface LiveQueryResult<T extends DocTypes, K extends IndexKeyType, R extends DocFragment = T> {\n readonly docs: DocWithId<T>[];\n readonly rows: IndexRow<K, T, R>[];\n}\n\nexport type UseLiveQuery = <T extends DocTypes, K extends IndexKeyType = string, R extends DocFragment = T>(\n mapFn: string | MapFn<T>,\n query?: QueryOpts<K>,\n initialRows?: IndexRow<K, T, R>[],\n) => LiveQueryResult<T, K, R>;\n\nexport interface AllDocsResult<T extends DocTypes> {\n readonly docs: DocWithId<T>[];\n}\n\nexport interface ChangesResult<T extends DocTypes> {\n readonly docs: DocWithId<T>[];\n}\n\nexport type UseAllDocs = <T extends DocTypes>(query?: AllDocsQueryOpts) => AllDocsResult<T>;\n\nexport type UseChanges = <T extends DocTypes>(since: ClockHead, opts: ChangesOptions) => ChangesResult<T>;\n\ninterface UpdateDocFnOptions {\n readonly replace?: boolean;\n readonly reset?: boolean;\n}\n\ntype UpdateDocFn<T extends DocTypes> = (newDoc?: DocSet<T>, options?: UpdateDocFnOptions) => void;\n\ntype StoreDocFn<T extends DocTypes> = (existingDoc?: DocWithId<T>) => Promise<DocResponse>;\n\ntype DeleteDocFn<T extends DocTypes> = (existingDoc?: DocWithId<T>) => Promise<DocResponse>;\n\nexport type UseDocumentResult<T extends DocTypes> = [DocWithId<T>, UpdateDocFn<T>, StoreDocFn<T>, DeleteDocFn<T>];\n\nexport type UseDocumentInitialDocOrFn<T extends DocTypes> = DocSet<T> | (() => DocSet<T>);\nexport type UseDocument = <T extends DocTypes>(initialDocOrFn: UseDocumentInitialDocOrFn<T>) => UseDocumentResult<T>;\n\nexport interface UseFireproof {\n readonly database: Database;\n /**\n * ## Summary\n *\n * React hook that provides the ability to create/update/save new Fireproof documents into your custom Fireproof database.\n * The creation occurs when you do not pass in an `_id` as part of your initial document -- the database will assign a new\n * one when you call the provided `save` handler. The hook also provides generics support so you can inline your custom type into\n * the invocation to receive type-safety and auto-complete support in your IDE.\n *\n * ## Usage\n *\n * ```tsx\n * const [todo, setTodo, saveTodo] = useDocument<Todo>({\n * text: '',\n * date: Date.now(),\n * completed: false\n * })\n *\n * const [doc, setDoc, saveDoc] = useDocument<Customer>({\n * _id: `${props.customerId}-profile`, // you can imagine `customerId` as a prop passed in\n * name: \"\",\n * company: \"\",\n * startedAt: Date.now()\n * })\n * ```\n *\n * ## Overview\n *\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useLiveQuery` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\n readonly useDocument: UseDocument;\n /**\n * ## Summary\n * React hook that provides access to live query results, enabling real-time updates in your app.\n *\n * ## Usage\n * ```tsx\n * const result = useLiveQuery(\"date\"); // using string key\n * const result = useLiveQuery('date', { limit: 10, descending: true }) // key + options\n * const result = useLiveQuery<CustomType>(\"date\"); // using generics\n * const result = useLiveQuery((doc) => doc.date)); // using map function\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useLiveQuery` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\n readonly useLiveQuery: UseLiveQuery;\n /**\n * ## Summary\n * React hook that provides access to all documents in the database, sorted by `_id`.\n *\n * ## Usage\n * ```tsx\n * const result = useAllDocs({ limit: 10, descending: true }); // with options\n * const result = useAllDocs(); // without options\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useAllDocs` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\n readonly useAllDocs: UseAllDocs;\n /**\n * ## Summary\n * React hook that provides access to all new documents in the database added since the last time the changes was called\n *\n * ## Usage\n * ```tsx\n * const result = useChanges(prevresult.clock,{limit:10}); // with options\n * const result = useChanges(); // without options\n * const database = useChanges.database; // underlying \"useFireproof\" database accessor\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useAllDocs`, `useChanges` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\n readonly useChanges: UseChanges;\n}\n\n/**\n * @deprecated Use the `useFireproof` hook instead\n */\nexport const FireproofCtx = {} as UseFireproof;\n\n/**\n *\n * ## Summary\n *\n * React hook to create a custom-named Fireproof database and provides the utility hooks to query against it.\n *\n * ## Usage\n * ```tsx\n * const { database, useLiveQuery, useDocument } = useFireproof(\"dbname\");\n * const { database, useLiveQuery, useDocument } = useFireproof(\"dbname\", { ...options });\n * ```\n *\n * ## Overview\n *\n * TL;DR: Only use this hook if you need to configure a database name other than the default `useFireproof`.\n *\n * For most applications, using the `useLiveQuery` or `useDocument` hooks exported from `use-fireproof` should\n * suffice for the majority of use-cases. Under the hood, they act against a database named `useFireproof` instantiated with\n * default configurations. However, if you need to do a custom database setup or configure a database name more to your liking\n * than the default `useFireproof`, then use `useFireproof` as it exists for that purpose. It will provide you with the\n * custom database accessor and *lexically scoped* versions of `useLiveQuery` and `useDocument` that act against said\n * custom database.\n *\n */\nexport function useFireproof(name: string | Database = \"useFireproof\", config: ConfigOpts = {}): UseFireproof {\n const database = typeof name === \"string\" ? fireproof(name, config) : name;\n\n function useDocument<T extends DocTypes>(initialDocOrFn: UseDocumentInitialDocOrFn<T>): UseDocumentResult<T> {\n let initialDoc: DocSet<T>;\n if (typeof initialDocOrFn === \"function\") {\n initialDoc = initialDocOrFn();\n } else {\n initialDoc = initialDocOrFn;\n }\n\n // We purposely refetch the docId everytime to check if it has changed\n const docId = initialDoc._id ?? \"\";\n\n // We do not want to force consumers to memoize their initial document so we do it for them.\n // We use the stringified generator function to ensure that the memoization is stable across renders.\n // const initialDoc = useMemo(initialDocFn, [initialDocFn.toString()]);\n const [doc, setDoc] = useState(initialDoc);\n\n const refreshDoc = useCallback(async () => {\n // todo add option for mvcc checks\n const doc = docId ? await database.get<T>(docId).catch(() => initialDoc) : initialDoc;\n setDoc(doc);\n }, [docId]);\n\n const saveDoc: StoreDocFn<T> = useCallback(\n async (existingDoc) => {\n const res = await database.put(existingDoc ?? doc);\n // If the document was created, then we need to update the local state with the new `_id`\n if (!existingDoc && !doc._id) setDoc((d) => ({ ...d, _id: res.id }));\n return res;\n },\n [doc],\n );\n\n const deleteDoc: DeleteDocFn<T> = useCallback(\n async (existingDoc) => {\n const id = existingDoc?._id ?? docId;\n const doc = await database.get<T>(id).catch(() => undefined);\n if (!doc) throw database.logger.Error().Str(\"id\", id).Msg(`Document not found`).AsError();\n const res = await database.del(id);\n setDoc(initialDoc);\n return res;\n },\n [docId, initialDoc],\n );\n\n const updateDoc: UpdateDocFn<T> = useCallback(\n (newDoc, opts = { replace: false, reset: false }) => {\n if (!newDoc) return void (opts.reset ? setDoc(initialDoc) : refreshDoc());\n setDoc((d) => (opts.replace ? (newDoc as DocWithId<T>) : { ...d, ...newDoc }));\n },\n [refreshDoc, initialDoc],\n );\n\n useEffect(() => {\n if (!docId) return;\n return database.subscribe((changes) => {\n if (changes.find((c) => c._id === docId)) {\n void refreshDoc(); // todo use change.value\n }\n });\n }, [docId, refreshDoc]);\n\n useEffect(() => {\n void refreshDoc();\n }, [refreshDoc]);\n\n return [{ _id: docId, ...doc }, updateDoc, saveDoc, deleteDoc];\n }\n\n function useLiveQuery<T extends DocTypes, K extends IndexKeyType = string, R extends DocFragment = T>(\n mapFn: MapFn<T> | string,\n query = {},\n initialRows: IndexRow<K, T, R>[] = [],\n ): LiveQueryResult<T, K, R> {\n const [result, setResult] = useState<LiveQueryResult<T, K, R>>(() => ({\n rows: initialRows,\n docs: initialRows.map((r) => r.doc).filter((r): r is DocWithId<T> => !!r),\n }));\n\n const queryString = useMemo(() => JSON.stringify(query), [query]);\n const mapFnString = useMemo(() => mapFn.toString(), [mapFn]);\n\n const refreshRows = useCallback(async () => {\n const res = await database.query<K, T, R>(mapFn, query);\n setResult({ ...res, docs: res.rows.map((r) => r.doc as DocWithId<T>) });\n }, [mapFnString, queryString]);\n\n useEffect(() => {\n refreshRows(); // Initial data fetch\n return database.subscribe(refreshRows);\n }, [refreshRows]);\n\n return result;\n }\n\n function useAllDocs<T extends DocTypes>(query: AllDocsQueryOpts = {}): AllDocsResult<T> {\n const [result, setResult] = useState<AllDocsResult<T>>({\n docs: [],\n });\n\n const queryString = useMemo(() => JSON.stringify(query), [query]);\n\n const refreshRows = useCallback(async () => {\n const res = await database.allDocs<T>(query);\n setResult({ ...res, docs: res.rows.map((r) => r.value as DocWithId<T>) });\n }, [queryString]);\n\n useEffect(() => {\n refreshRows(); // Initial data fetch\n return database.subscribe(refreshRows);\n }, [refreshRows]);\n\n return result;\n }\n\n function useChanges<T extends DocTypes>(since: ClockHead = [], opts: ChangesOptions = {}): ChangesResult<T> {\n const [result, setResult] = useState<ChangesResult<T>>({\n docs: [],\n });\n\n const queryString = useMemo(() => JSON.stringify(opts), [opts]);\n\n const refreshRows = useCallback(async () => {\n const res = await database.changes<T>(since, opts);\n setResult({ ...res, docs: res.rows.map((r) => r.value as DocWithId<T>) });\n }, [since, queryString]);\n\n useEffect(() => {\n refreshRows(); // Initial data fetch\n return database.subscribe(refreshRows);\n }, [refreshRows]);\n\n return result;\n }\n\n return { database, useLiveQuery, useDocument, useAllDocs, useChanges };\n}\n","import { Database, DocTypes, DocWithId } from \"@fireproof/core\";\n\nimport { UseDocument, UseDocumentResult, useFireproof } from \"./useFireproof.js\";\n\nexport interface TLUseDocument {\n <T extends DocTypes>(initialDoc: DocWithId<T>): UseDocumentResult<T>;\n database: Database;\n}\n\nfunction topLevelUseDocument(...args: Parameters<UseDocument>) {\n const { useDocument, database } = useFireproof();\n (topLevelUseDocument as TLUseDocument).database = database;\n return useDocument(...args);\n}\n\n/**\n * ## Summary\n *\n * React hook that provides the ability to create new Fireproof documents. The creation occurs when\n * you do not pass in an `_id` as part of your initial document -- the database will assign a new one when\n * you call the provided `save` handler This uses the default database named `useFireproof` under the hood which you can also\n * access via the `database` accessor.\n *\n * ## Usage\n *\n * ```tsx\n * const [todo, setTodo, saveTodo] = useDocument(() => ({\n * text: '',\n * date: Date.now(),\n * completed: false\n * }))\n *\n * const [doc, setDoc, saveDoc] = useDocument(() => ({\n * _id: `${props.customerId}-profile`, // you can imagine `customerId` as a prop passed in\n * name: \"\",\n * company: \"\",\n * startedAt: Date.now()\n * }))\n *\n * const database = useDocument.database; // underlying \"useFireproof\" database accessor\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useLiveQuery` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\nexport const useDocument = topLevelUseDocument as TLUseDocument;\n","import { Database, DocFragment, DocTypes, IndexKeyType } from \"@fireproof/core\";\n\nimport { LiveQueryResult, useFireproof, UseLiveQuery } from \"./useFireproof.js\";\n\nexport interface TLUseLiveQuery {\n <T extends DocTypes, K extends IndexKeyType, R extends DocFragment = T>(\n ...args: Parameters<UseLiveQuery>\n ): LiveQueryResult<T, K, R>;\n database: Database;\n}\n\nfunction topLevelUseLiveQuery(...args: Parameters<UseLiveQuery>) {\n const { useLiveQuery, database } = useFireproof();\n (topLevelUseLiveQuery as TLUseLiveQuery).database = database;\n return useLiveQuery(...args);\n}\n\n/**\n * ## Summary\n * React hook that provides access to live query results, enabling real-time updates in your app. This uses\n * the default database named \"useFireproof\" under the hood which you can also access via the `database` accessor.\n *\n * ## Usage\n * ```tsx\n * const results = useLiveQuery(\"date\"); // using string\n * const results = useLiveQuery((doc) => doc.date)); // using map function\n * const database = useLiveQuery.database; // underlying \"useFireproof\" database accessor\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useLiveQuery` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\nexport const useLiveQuery = topLevelUseLiveQuery as TLUseLiveQuery;\n","import { Database, DocTypes } from \"@fireproof/core\";\n\nimport { AllDocsResult, useFireproof, UseAllDocs } from \"./useFireproof.js\";\n\nexport interface TLUseAllDocs {\n <T extends DocTypes>(...args: Parameters<UseAllDocs>): AllDocsResult<T>;\n database: Database;\n}\n\nfunction topLevelUseAllDocs(...args: Parameters<UseAllDocs>) {\n const { useAllDocs, database } = useFireproof();\n (topLevelUseAllDocs as TLUseAllDocs).database = database;\n return useAllDocs(...args);\n}\n\n/**\n * ## Summary\n * React hook that provides access to all documents in the database, sorted by `_id`.\n *\n * ## Usage\n * ```tsx\n * const result = useAllDocs({ limit: 10, descending: true }); // with options\n * const result = useAllDocs(); // without options\n * const database = useAllDocs.database; // underlying \"useFireproof\" database accessor\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useAllDocs` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\nexport const useAllDocs = topLevelUseAllDocs as TLUseAllDocs;\n","import { Database, DocTypes } from \"@fireproof/core\";\n\nimport { ChangesResult, useFireproof, UseChanges } from \"./useFireproof.js\";\n\nexport interface TLUseChanges {\n <T extends DocTypes>(...args: Parameters<UseChanges>): ChangesResult<T>;\n database: Database;\n}\n\nfunction topLevelUseChanges(...args: Parameters<UseChanges>) {\n const { useChanges, database } = useFireproof();\n (topLevelUseChanges as TLUseChanges).database = database;\n return useChanges(...args);\n}\n\n/**\n * ## Summary\n * React hook that provides access to all new documents in the database added since the last time the changes was called\n *\n * ## Usage\n * ```tsx\n * const result = useChanges(prevresult.clock,{limit:10}); // with options\n * const result = useChanges(); // without options\n * const database = useChanges.database; // underlying \"useFireproof\" database accessor\n * ```\n *\n * ## Overview\n * Changes made via remote sync peers, or other members of your cloud replica group will appear automatically\n * when you use the `useAllDocs`, `useChanges` and `useDocument` APIs. By default, Fireproof stores data in the browser's\n * local storage.\n */\nexport const useChanges = topLevelUseChanges as TLUseChanges;\n"],"mappings":"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","names":["useDocument","doc","useLiveQuery","useAllDocs","useChanges","useDocument","useLiveQuery","useAllDocs","useChanges"]}
@@ -1 +1 @@
1
- {"inputs":{"src/react/useFireproof.ts":{"bytes":11390,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/react/useDocument.ts":{"bytes":1680,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/useLiveQuery.ts":{"bytes":1409,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/useAllDocs.ts":{"bytes":1146,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/useChanges.ts":{"bytes":1191,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/index.ts":{"bytes":439,"imports":[{"path":"src/react/useDocument.ts","kind":"import-statement","original":"./useDocument.js"},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"},{"path":"src/react/useLiveQuery.ts","kind":"import-statement","original":"./useLiveQuery.js"},{"path":"src/react/useAllDocs.ts","kind":"import-statement","original":"./useAllDocs.js"},{"path":"src/react/useChanges.ts","kind":"import-statement","original":"./useChanges.js"}],"format":"esm"}},"outputs":{"dist/fireproof-core/react/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":22077},"dist/fireproof-core/react/index.cjs":{"imports":[{"path":"@fireproof/core","kind":"require-call","external":true},{"path":"react","kind":"require-call","external":true}],"exports":[],"entryPoint":"src/react/index.ts","inputs":{"src/react/index.ts":{"bytesInOutput":305},"src/react/useFireproof.ts":{"bytesInOutput":4237},"src/react/useDocument.ts":{"bytesInOutput":222},"src/react/useLiveQuery.ts":{"bytesInOutput":229},"src/react/useAllDocs.ts":{"bytesInOutput":215},"src/react/useChanges.ts":{"bytesInOutput":215}},"bytes":6390}}}
1
+ {"inputs":{"src/react/useFireproof.ts":{"bytes":11390,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/react/useDocument.ts":{"bytes":1680,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/useLiveQuery.ts":{"bytes":1409,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/useAllDocs.ts":{"bytes":1146,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/useChanges.ts":{"bytes":1191,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/index.ts":{"bytes":971,"imports":[{"path":"src/react/useDocument.ts","kind":"import-statement","original":"./useDocument.js"},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"},{"path":"src/react/useLiveQuery.ts","kind":"import-statement","original":"./useLiveQuery.js"},{"path":"src/react/useAllDocs.ts","kind":"import-statement","original":"./useAllDocs.js"},{"path":"src/react/useChanges.ts","kind":"import-statement","original":"./useChanges.js"}],"format":"esm"}},"outputs":{"dist/fireproof-core/react/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":22625},"dist/fireproof-core/react/index.cjs":{"imports":[{"path":"@fireproof/core","kind":"require-call","external":true},{"path":"react","kind":"require-call","external":true}],"exports":[],"entryPoint":"src/react/index.ts","inputs":{"src/react/index.ts":{"bytesInOutput":305},"src/react/useFireproof.ts":{"bytesInOutput":4237},"src/react/useDocument.ts":{"bytesInOutput":222},"src/react/useLiveQuery.ts":{"bytesInOutput":229},"src/react/useAllDocs.ts":{"bytesInOutput":215},"src/react/useChanges.ts":{"bytesInOutput":215}},"bytes":6390}}}
@@ -1 +1 @@
1
- {"inputs":{"src/react/useFireproof.ts":{"bytes":11390,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/react/useDocument.ts":{"bytes":1680,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/useLiveQuery.ts":{"bytes":1409,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/useAllDocs.ts":{"bytes":1146,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/useChanges.ts":{"bytes":1191,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/index.ts":{"bytes":439,"imports":[{"path":"src/react/useDocument.ts","kind":"import-statement","original":"./useDocument.js"},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"},{"path":"src/react/useLiveQuery.ts","kind":"import-statement","original":"./useLiveQuery.js"},{"path":"src/react/useAllDocs.ts","kind":"import-statement","original":"./useAllDocs.js"},{"path":"src/react/useChanges.ts","kind":"import-statement","original":"./useChanges.js"}],"format":"esm"}},"outputs":{"dist/fireproof-core/react/index.js.map":{"imports":[],"exports":[],"inputs":{},"bytes":21510},"dist/fireproof-core/react/index.js":{"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"exports":["FireproofCtx","useAllDocs","useChanges","useDocument","useFireproof","useLiveQuery"],"entryPoint":"src/react/index.ts","inputs":{"src/react/useFireproof.ts":{"bytesInOutput":3889},"src/react/useDocument.ts":{"bytesInOutput":222},"src/react/index.ts":{"bytesInOutput":0},"src/react/useLiveQuery.ts":{"bytesInOutput":229},"src/react/useAllDocs.ts":{"bytesInOutput":215},"src/react/useChanges.ts":{"bytesInOutput":215}},"bytes":5016}}}
1
+ {"inputs":{"src/react/useFireproof.ts":{"bytes":11390,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/react/useDocument.ts":{"bytes":1680,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/useLiveQuery.ts":{"bytes":1409,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/useAllDocs.ts":{"bytes":1146,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/useChanges.ts":{"bytes":1191,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"}],"format":"esm"},"src/react/index.ts":{"bytes":971,"imports":[{"path":"src/react/useDocument.ts","kind":"import-statement","original":"./useDocument.js"},{"path":"src/react/useFireproof.ts","kind":"import-statement","original":"./useFireproof.js"},{"path":"src/react/useLiveQuery.ts","kind":"import-statement","original":"./useLiveQuery.js"},{"path":"src/react/useAllDocs.ts","kind":"import-statement","original":"./useAllDocs.js"},{"path":"src/react/useChanges.ts","kind":"import-statement","original":"./useChanges.js"}],"format":"esm"}},"outputs":{"dist/fireproof-core/react/index.js.map":{"imports":[],"exports":[],"inputs":{},"bytes":21510},"dist/fireproof-core/react/index.js":{"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"exports":["FireproofCtx","useAllDocs","useChanges","useDocument","useFireproof","useLiveQuery"],"entryPoint":"src/react/index.ts","inputs":{"src/react/useFireproof.ts":{"bytesInOutput":3889},"src/react/useDocument.ts":{"bytesInOutput":222},"src/react/index.ts":{"bytesInOutput":0},"src/react/useLiveQuery.ts":{"bytesInOutput":229},"src/react/useAllDocs.ts":{"bytesInOutput":215},"src/react/useChanges.ts":{"bytesInOutput":215}},"bytes":5016}}}
@@ -0,0 +1,65 @@
1
+
2
+ describe("FPEnvelope", () => {
3
+ // const sthis = mockSuperThis();
4
+ // it("unknown bytes", () => {
5
+ // expect(bs.FPMsgMatch2Envelope(Uint8Array.from([1, 2, 3]), "bla").Err().message).toStrictEqual(
6
+ // "failed to decode envelope: Error: CBOR decode error: too many terminals, data makes no sense"
7
+ // );
8
+ // });
9
+
10
+ // it("unknown type", () => {
11
+ // expect(bs.FPMsgMatch2Envelope(encode({ type: "blax", payload: 4 }), "bla"))
12
+ // .toStrictEqual(Result.Err("expected type to be bla"));
13
+ // })
14
+
15
+ // it("no type", () => {
16
+ // expect(bs.FPMsgMatch2Envelope(encode({ type: "blax", payload: 4 })))
17
+ // .toStrictEqual(Result.Ok({ type: "blax", payload: 4 }));
18
+ // })
19
+
20
+ // it("car type", () => {
21
+ // expect(bs.FPMsg2Car(bs.Car2FPMsg(Uint8Array.from([1, 2, 3])).Ok().payload).Ok()).toStrictEqual(Uint8Array.from([1, 2, 3]));
22
+ // })
23
+
24
+ // it("file type", () => {
25
+ // expect(bs.FPMsg2File(bs.File2FPMsg(Uint8Array.from([1, 2, 3])).Ok().payload).Ok()).toStrictEqual(Uint8Array.from([1, 2, 3]));
26
+ // })
27
+
28
+ // it("meta type", async () => {
29
+ // const ref = {
30
+ // eventCid: await simpleCID(sthis),
31
+ // dbMeta: {
32
+ // cars: [
33
+ // await simpleCID(sthis)
34
+ // ]
35
+ // },
36
+ // parents: [
37
+ // await simpleCID(sthis),
38
+ // await simpleCID(sthis)
39
+ // ]
40
+ // } satisfies DbMetaEvent;
41
+ // expect(bs.FPMsg2Meta(bs.Meta2FPMsg([ref])).Ok()).toEqual(ref);
42
+ // })
43
+
44
+ // it("wal type", () => {
45
+ // const ref: bs.WALState = {
46
+ // fileOperations: [],
47
+ // noLoaderOps: [],
48
+ // operations: [
49
+ // {
50
+ // cars: [
51
+ // CID.parse("bag4yvqabciqdzvfxrxfi6feubspyz666zegmp3z5w556mr4ykya2kkdm22r7pyy")
52
+ // ]
53
+ // },
54
+ // {
55
+ // cars: [
56
+ // CID.parse("bag4yvqabciqd2ul2tw4mdcpvfq2pdqhvnqp2ktuyrtcl3j3gwhxbjzjt62xzeaq")
57
+ // ]
58
+ // }
59
+ // ]
60
+ // };
61
+ // const res = bs.FPMsg2WAL(bs.WAL2FPMsg(sthis, ref).Ok()).Ok();
62
+ // expect(res).toStrictEqual(ref);
63
+ // expect(res.operations[0].cars[0].version).toStrictEqual(1);
64
+ // })
65
+ })
@@ -0,0 +1,122 @@
1
+ import { Result, URI } from "@adviser/cement";
2
+ import { bs, fireproof, SuperThis } from "@fireproof/core";
3
+
4
+ class TestInterceptor extends bs.PassThroughGateway {
5
+ readonly fn = vitest.fn();
6
+
7
+ async buildUrl(sthis: SuperThis, baseUrl: URI, key: string): Promise<Result<bs.SerdeGatewayBuildUrlReturn>> {
8
+ const ret = await super.buildUrl(sthis, baseUrl, key);
9
+ this.fn("buildUrl", ret);
10
+ return ret;
11
+ }
12
+
13
+ async start(sthis: SuperThis, baseUrl: URI): Promise<Result<bs.SerdeGatewayStartReturn>> {
14
+ const ret = await super.start(sthis, baseUrl);
15
+ this.fn("start", ret);
16
+ return ret;
17
+ }
18
+ async close(sthis: SuperThis, baseUrl: URI): Promise<Result<bs.SerdeGatewayCloseReturn>> {
19
+ const ret = await super.close(sthis, baseUrl);
20
+ this.fn("close", ret);
21
+ return ret;
22
+ }
23
+ async delete(sthis: SuperThis, baseUrl: URI): Promise<Result<bs.SerdeGatewayDeleteReturn>> {
24
+ const ret = await super.delete(sthis, baseUrl);
25
+ this.fn("delete", ret);
26
+ return ret;
27
+ }
28
+ async destroy(sthis: SuperThis, baseUrl: URI): Promise<Result<bs.SerdeGatewayDestroyReturn>> {
29
+ const ret = await super.destroy(sthis, baseUrl);
30
+ this.fn("destroy", ret);
31
+ return ret;
32
+ }
33
+ async put<T>(sthis: SuperThis, url: URI, body: bs.FPEnvelope<T>): Promise<Result<bs.SerdeGatewayPutReturn<T>>> {
34
+ const ret = await super.put<T>(sthis, url, body);
35
+ this.fn("put", ret);
36
+ return ret;
37
+ }
38
+ async get<S>(sthis: SuperThis, url: URI): Promise<Result<bs.SerdeGatewayGetReturn<S>>> {
39
+ const ret = await super.get<S>(sthis, url);
40
+ this.fn("get", ret);
41
+ return ret;
42
+ }
43
+ async subscribe(
44
+ sthis: SuperThis,
45
+ url: URI,
46
+ callback: (meta: bs.FPEnvelopeMeta) => Promise<void>,
47
+ ): Promise<Result<bs.SerdeGatewaySubscribeReturn>> {
48
+ const ret = await super.subscribe(sthis, url, callback);
49
+ this.fn("subscribe", ret);
50
+ return ret;
51
+ }
52
+ }
53
+
54
+ describe("InterceptorGateway", () => {
55
+ it("passthrough", async () => {
56
+ const gwi = new TestInterceptor();
57
+ const db = fireproof("interceptor-gateway", {
58
+ gatewayInterceptor: gwi,
59
+ });
60
+ expect(
61
+ await db.put({
62
+ _id: "foo",
63
+ foo: 4,
64
+ }),
65
+ );
66
+ expect(await db.get("foo")).toEqual({
67
+ _id: "foo",
68
+ foo: 4,
69
+ });
70
+ await db.close();
71
+ await db.destroy();
72
+ // await sleep(1000);
73
+ expect(gwi.fn.mock.calls.length).toBe(42);
74
+ // might be a stupid test
75
+ expect(gwi.fn.mock.calls.map((i) => i[0]).sort() /* not ok there are some operation */).toEqual(
76
+ [
77
+ "start",
78
+ "start",
79
+ "buildUrl",
80
+ "get",
81
+ "buildUrl",
82
+ "get",
83
+ "start",
84
+ "start",
85
+ "buildUrl",
86
+ "get",
87
+ "buildUrl",
88
+ "put",
89
+ "buildUrl",
90
+ "put",
91
+ "buildUrl",
92
+ "put",
93
+ "start",
94
+ "start",
95
+ "start",
96
+ "start",
97
+ "close",
98
+ "close",
99
+ "close",
100
+ "close",
101
+ "close",
102
+ "close",
103
+ "close",
104
+ "close",
105
+ "buildUrl",
106
+ "get",
107
+ "close",
108
+ "close",
109
+ "close",
110
+ "close",
111
+ "destroy",
112
+ "destroy",
113
+ "destroy",
114
+ "destroy",
115
+ "destroy",
116
+ "destroy",
117
+ "destroy",
118
+ "destroy",
119
+ ].sort() /* not ok there are some operation */,
120
+ );
121
+ });
122
+ });
@@ -0,0 +1,130 @@
1
+ import { bs, PARAM, rt } from "@fireproof/core";
2
+ import { runtimeFn, toCryptoRuntime, URI } from "@adviser/cement";
3
+ import { base58btc } from "multiformats/bases/base58";
4
+ import { mockSuperThis } from "../helpers.js";
5
+ import { KeyBagProviderIndexDB } from "@fireproof/core/web";
6
+
7
+ describe("KeyBag indexdb and file", () => {
8
+ let url: URI;
9
+ const sthis = mockSuperThis();
10
+ beforeAll(async () => {
11
+ await sthis.start();
12
+ if (runtimeFn().isBrowser) {
13
+ url = URI.from("indexdb://fp-keybag");
14
+ } else {
15
+ url = URI.merge(`file://./dist/tests/key.bag`, sthis.env.get("FP_KEYBAG_URL"));
16
+ }
17
+ });
18
+ it("default-path", async () => {
19
+ const old = sthis.env.get("FP_KEYBAG_URL");
20
+ sthis.env.delete("FP_KEYBAG_URL");
21
+ const kb = await rt.kb.getKeyBag(sthis);
22
+ if (runtimeFn().isBrowser) {
23
+ expect(kb.rt.url.toString()).toBe(`indexdb://fp-keybag`);
24
+ } else {
25
+ expect(kb.rt.url.toString()).toBe(`file://${sthis.env.get("HOME")}/.fireproof/keybag`);
26
+ }
27
+ sthis.env.set("FP_KEYBAG_URL", old);
28
+ });
29
+ it("from env", async () => {
30
+ const old = sthis.env.get("FP_KEYBAG_URL");
31
+ sthis.env.set("FP_KEYBAG_URL", url.toString());
32
+ const kb = await rt.kb.getKeyBag(sthis);
33
+ expect(kb.rt.url.toString()).toBe(url.toString());
34
+ sthis.env.set("FP_KEYBAG_URL", old);
35
+ });
36
+ it("simple add", async () => {
37
+ const kb = await rt.kb.getKeyBag(sthis, {
38
+ url: url.toString(),
39
+ crypto: toCryptoRuntime({
40
+ randomBytes: (size) => new Uint8Array(size).map((_, i) => i),
41
+ }),
42
+ });
43
+ const name = "setkey" + Math.random();
44
+ expect((await kb.getNamedKey(name, true)).isErr()).toBeTruthy();
45
+
46
+ const key = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
47
+ const res = await kb.setNamedKey(name, key);
48
+ expect(res.isOk()).toBeTruthy();
49
+ expect((await kb.getNamedKey(name, true)).Ok()).toEqual(res.Ok());
50
+
51
+ const name2 = "implicit";
52
+ const created = await kb.getNamedKey(name2);
53
+ expect(created.isOk()).toBeTruthy();
54
+
55
+ expect((await kb.getNamedKey(name2)).Ok()).toEqual(created.Ok());
56
+
57
+ let diskBag: rt.kb.KeyItem;
58
+ let diskBag2: rt.kb.KeyItem;
59
+ const provider = await kb.rt.getBag();
60
+ if (runtimeFn().isBrowser) {
61
+ const p = provider as KeyBagProviderIndexDB;
62
+ diskBag = await p._prepare().then((db) => db.get("bag", name));
63
+ diskBag2 = await p._prepare().then((db) => db.get("bag", name2));
64
+ } else {
65
+ const p = provider as rt.gw.file.KeyBagProviderFile;
66
+ const { sysFS } = await p._prepare(name);
67
+
68
+ diskBag = await sysFS.readfile((await p._prepare(name)).fName).then((data) => {
69
+ return JSON.parse(sthis.txt.decode(data)) as rt.kb.KeyItem;
70
+ });
71
+ diskBag2 = await sysFS.readfile((await p._prepare(name2)).fName).then((data) => {
72
+ return JSON.parse(sthis.txt.decode(data)) as rt.kb.KeyItem;
73
+ });
74
+ }
75
+ expect(await kb.toKeyWithFingerPrint(diskBag.key)).toEqual(res);
76
+ expect(await kb.toKeyWithFingerPrint(diskBag2.key)).toEqual(created);
77
+ const algo = {
78
+ name: "AES-GCM",
79
+ iv: kb.rt.crypto.randomBytes(12),
80
+ tagLength: 128,
81
+ };
82
+ const data = kb.rt.crypto.randomBytes(122);
83
+ expect(await kb.rt.crypto.encrypt(algo, res.Ok().key, data)).toEqual(await kb.rt.crypto.encrypt(algo, created.Ok().key, data));
84
+ expect(await kb.rt.crypto.encrypt(algo, await kb.subtleKey(diskBag.key), data)).toEqual(
85
+ await kb.rt.crypto.encrypt(algo, created.Ok().key, data),
86
+ );
87
+ expect(await kb.rt.crypto.encrypt(algo, await kb.subtleKey(diskBag2.key), data)).toEqual(
88
+ await kb.rt.crypto.encrypt(algo, created.Ok().key, data),
89
+ );
90
+ });
91
+ });
92
+
93
+ describe("KeyedCryptoStore", () => {
94
+ let loader: bs.Loadable;
95
+ // let logger: Logger;
96
+ let baseUrl: URI;
97
+ const sthis = mockSuperThis();
98
+ beforeEach(async () => {
99
+ await sthis.start();
100
+ // logger = MockLogger().logger;
101
+ let kbUrl: URI;
102
+ if (runtimeFn().isBrowser) {
103
+ kbUrl = URI.from("indexdb://fp-keybag");
104
+ baseUrl = URI.from("indexdb://fp-keyed-crypto-store");
105
+ } else {
106
+ kbUrl = URI.merge(`file://./dist/tests/key.bag`, sthis.env.get("FP_KEYBAG_URL"));
107
+ baseUrl = URI.merge("file://./dist/tests/keyed-crypto-store", sthis.env.get("FP_STORAGE_URL"));
108
+ }
109
+ baseUrl = baseUrl.build().defParam(PARAM.NAME, "test").URI();
110
+ loader = {
111
+ keyBag: () => rt.kb.getKeyBag(sthis, { url: kbUrl }),
112
+ } as bs.Loadable;
113
+ });
114
+ it("no crypto", async () => {
115
+ const strt = bs.toStoreRuntime(sthis);
116
+ const url = baseUrl.build().setParam(PARAM.STORE_KEY, "insecure").URI();
117
+
118
+ for (const pstore of [
119
+ strt.makeDataStore({ sthis, url, loader }),
120
+ strt.makeMetaStore({ sthis, url, loader }),
121
+ strt.makeWALStore({ sthis, url, loader }),
122
+ ]) {
123
+ const store = await pstore;
124
+ // await store.start();
125
+ const kc = await store.keyedCrypto();
126
+ expect(kc.constructor.name).toBe("noCrypto");
127
+ // expect(kc.isEncrypting).toBe(false);
128
+ }
129
+ });
130
+ });