@fireproof/core 0.20.0-dev-preview-40 → 0.20.0-dev-preview-50
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 +6 -4
- package/deno/index.js +2 -2
- package/deno/index.js.map +1 -1
- package/deno.json +3 -2
- package/index.cjs +955 -599
- package/index.cjs.map +1 -1
- package/index.d.cts +334 -127
- package/index.d.ts +334 -127
- package/index.js +939 -582
- package/index.js.map +1 -1
- package/indexeddb/index.cjs.map +1 -1
- package/indexeddb/index.js.map +1 -1
- package/indexeddb/metafile-cjs.json +1 -1
- package/indexeddb/metafile-esm.json +1 -1
- package/metafile-cjs.json +1 -1
- package/metafile-esm.json +1 -1
- package/package.json +7 -5
- package/react/index.cjs +17 -9
- package/react/index.cjs.map +1 -1
- package/react/index.d.cts +5 -4
- package/react/index.d.ts +5 -4
- package/react/index.js +17 -9
- package/react/index.js.map +1 -1
- package/react/metafile-cjs.json +1 -1
- package/react/metafile-esm.json +1 -1
- package/tests/blockstore/interceptor-gateway.test.ts +15 -1
- package/tests/blockstore/keyed-crypto-indexeddb-file.test.ts +8 -18
- package/tests/blockstore/keyed-crypto.test.ts +31 -53
- package/tests/blockstore/loader.test.ts +21 -19
- package/tests/blockstore/store.test.ts +52 -56
- package/tests/blockstore/transaction.test.ts +13 -11
- package/tests/fireproof/all-gateway.test.ts +53 -50
- package/tests/fireproof/attachable.test.ts +356 -0
- package/tests/fireproof/crdt.test.ts +100 -60
- package/tests/fireproof/database.test.ts +95 -54
- package/tests/fireproof/fireproof.test.ts +58 -55
- package/tests/fireproof/hello.test.ts +4 -4
- package/tests/fireproof/indexer.test.ts +44 -44
- package/tests/fireproof/stable-cid.test.ts +69 -0
- package/tests/fireproof/utils.test.ts +21 -10
- package/tests/gateway/file/loader-config.test.ts +25 -25
- package/tests/gateway/fp-envelope-serialize.test.ts +8 -8
- package/tests/gateway/indexeddb/loader-config.test.ts +6 -6
- package/tests/helpers.ts +81 -2
- package/tests/react/useFireproof.test.tsx +59 -17
package/react/index.js
CHANGED
@@ -21,7 +21,7 @@ function useFireproof(name = "useFireproof", config = {}) {
|
|
21
21
|
}
|
22
22
|
const originalInitialDoc = useMemo(() => deepClone({ ...initialDoc }), []);
|
23
23
|
const [doc, setDoc] = useState(initialDoc);
|
24
|
-
const
|
24
|
+
const refresh = useCallback(async () => {
|
25
25
|
const gotDoc = doc._id ? await database.get(doc._id).catch(() => initialDoc) : initialDoc;
|
26
26
|
setDoc(gotDoc);
|
27
27
|
}, [doc._id]);
|
@@ -64,11 +64,11 @@ function useFireproof(name = "useFireproof", config = {}) {
|
|
64
64
|
const updateDoc = useCallback(
|
65
65
|
(newDoc, opts = { replace: false, reset: false }) => {
|
66
66
|
if (!newDoc) {
|
67
|
-
return opts.reset ? reset() :
|
67
|
+
return opts.reset ? reset() : refresh();
|
68
68
|
}
|
69
69
|
return opts.replace ? replace(newDoc) : merge(newDoc);
|
70
70
|
},
|
71
|
-
[
|
71
|
+
[refresh, reset, replace, merge]
|
72
72
|
);
|
73
73
|
useEffect(() => {
|
74
74
|
if (!doc._id) return;
|
@@ -77,14 +77,21 @@ function useFireproof(name = "useFireproof", config = {}) {
|
|
77
77
|
return;
|
78
78
|
}
|
79
79
|
if (changes.find((c) => c._id === doc._id)) {
|
80
|
-
void
|
80
|
+
void refresh();
|
81
81
|
}
|
82
82
|
}, true);
|
83
|
-
}, [doc._id,
|
83
|
+
}, [doc._id, refresh]);
|
84
84
|
useEffect(() => {
|
85
|
-
void
|
86
|
-
}, [
|
87
|
-
const
|
85
|
+
void refresh();
|
86
|
+
}, [refresh]);
|
87
|
+
const submit = useCallback(
|
88
|
+
async (e) => {
|
89
|
+
if (e?.preventDefault) e.preventDefault();
|
90
|
+
await save();
|
91
|
+
reset();
|
92
|
+
},
|
93
|
+
[save, reset]
|
94
|
+
);
|
88
95
|
const apiObject = {
|
89
96
|
doc: { ...doc },
|
90
97
|
merge,
|
@@ -92,7 +99,8 @@ function useFireproof(name = "useFireproof", config = {}) {
|
|
92
99
|
reset,
|
93
100
|
refresh,
|
94
101
|
save,
|
95
|
-
remove
|
102
|
+
remove,
|
103
|
+
submit
|
96
104
|
};
|
97
105
|
const tuple = [{ ...doc }, updateDoc, save, remove, reset, refresh];
|
98
106
|
Object.assign(apiObject, tuple);
|
package/react/index.js.map
CHANGED
@@ -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 DocFragment,\n DocResponse,\n DocSet,\n DocTypes,\n DocWithId,\n IndexKeyType,\n IndexRow,\n MapFn,\n QueryOpts,\n Database,\n} from \"@fireproof/core\";\nimport { fireproof } from \"@fireproof/core\";\nimport { useCallback, useEffect, useMemo, useState, useRef } 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 /** @internal */\n readonly length: number;\n /** @internal */\n map<U>(callbackfn: (value: DocWithId<T>, index: number, array: DocWithId<T>[]) => U): U[];\n /** @internal */\n filter(predicate: (value: DocWithId<T>, index: number, array: DocWithId<T>[]) => boolean): DocWithId<T>[];\n /** @internal */\n forEach(callbackfn: (value: DocWithId<T>, index: number, array: DocWithId<T>[]) => void): void;\n /** @internal */\n [Symbol.iterator](): Iterator<DocWithId<T>>;\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\ntype UseDocumentResultTuple<T extends DocTypes> = [DocWithId<T>, UpdateDocFn<T>, StoreDocFn<T>, DeleteDocFn<T>];\n\ninterface UseDocumentResultObject<T extends DocTypes> {\n doc: DocWithId<T>;\n merge: (newDoc: Partial<T>) => void;\n replace: (newDoc: T) => void;\n reset: () => void;\n refresh: () => void;\n save: StoreDocFn<T>;\n remove: DeleteDocFn<T>;\n}\n\nexport type UseDocumentResult<T extends DocTypes> = UseDocumentResultObject<T> & UseDocumentResultTuple<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 = useDocument<Todo>({\n * text: '',\n * date: Date.now(),\n * completed: false\n * })\n * // Access via object properties\n * todo.doc // The current document\n * todo.merge({ completed: true }) // Update specific fields\n * todo.replace({ text: 'new', date: Date.now(), completed: false }) // Replace entire doc\n * todo.save() // Save changes\n * todo.remove() // Delete document\n * todo.reset() // Reset to initial state\n * todo.refresh() // Refresh from database\n *\n * // Or use tuple destructuring for legacy compatibility\n * const [doc, updateDoc, saveDoc, removeDoc] = todo\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 * ```\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\nfunction deepClone<T>(value: T): T {\n if (typeof structuredClone !== \"undefined\") {\n return structuredClone(value);\n } else {\n // Fallback if structuredClone is not available (older browsers, older Node versions, etc.)\n return JSON.parse(JSON.stringify(value));\n }\n}\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 // Tracks whether we've done a local update (merge, replace, or reset)\n const updateHappenedRef = useRef(false);\n\n function useDocument<T extends DocTypes>(initialDocOrFn?: UseDocumentInitialDocOrFn<T>): UseDocumentResult<T> {\n // Get fresh initialDoc value\n let initialDoc: DocSet<T>;\n if (typeof initialDocOrFn === \"function\") {\n initialDoc = initialDocOrFn();\n } else {\n initialDoc = initialDocOrFn ?? ({} as T);\n }\n\n // Store the original initial doc without _id for resets\n const originalInitialDoc = useMemo(() => deepClone({ ...initialDoc }), []);\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 gotDoc = doc._id ? await database.get<T>(doc._id).catch(() => initialDoc) : initialDoc;\n setDoc(gotDoc);\n }, [doc._id]);\n\n const save: StoreDocFn<T> = useCallback(\n async (existingDoc) => {\n // This signals \"I'm applying local changes to DB, so let's go back to 'synced' mode\"\n updateHappenedRef.current = false;\n\n const toSave = existingDoc ?? doc;\n const res = await database.put(toSave);\n\n // If updateHappenedRef is *still* false after the save,\n // you can set _id or do any other \"subscription-friendly\" steps\n if (!updateHappenedRef.current && !doc._id && !existingDoc) {\n setDoc((d) => ({ ...d, _id: res.id }));\n }\n\n return res;\n },\n [doc],\n );\n\n const remove: DeleteDocFn<T> = useCallback(\n async (existingDoc) => {\n const id = existingDoc?._id ?? doc._id;\n if (!id) throw database.logger.Error().Msg(`Document must have an _id to be removed`).AsError();\n const gotDoc = await database.get<T>(id).catch(() => undefined);\n if (!gotDoc) 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 [doc, initialDoc],\n );\n\n // New granular update methods\n const merge = useCallback((newDoc: Partial<T>) => {\n updateHappenedRef.current = true;\n setDoc((prev) => ({ ...prev, ...newDoc }));\n }, []);\n\n const replace = useCallback((newDoc: T) => {\n updateHappenedRef.current = true;\n setDoc(newDoc);\n }, []);\n\n const reset = useCallback(() => {\n updateHappenedRef.current = true;\n setDoc({ ...originalInitialDoc });\n }, [originalInitialDoc]);\n\n // Legacy-compatible updateDoc\n const updateDoc = useCallback(\n (newDoc?: DocSet<T>, opts = { replace: false, reset: false }) => {\n if (!newDoc) {\n return opts.reset ? reset() : refreshDoc();\n }\n return opts.replace ? replace(newDoc as T) : merge(newDoc);\n },\n [refreshDoc, reset, replace, merge],\n );\n\n useEffect(() => {\n if (!doc._id) return;\n return database.subscribe((changes) => {\n if (updateHappenedRef.current) {\n return;\n }\n if (changes.find((c) => c._id === doc._id)) {\n void refreshDoc();\n }\n }, true);\n }, [doc._id, refreshDoc]);\n\n useEffect(() => {\n void refreshDoc();\n }, [refreshDoc]);\n\n const refresh = useCallback(() => void refreshDoc(), [refreshDoc]);\n\n // Primary Object API with both new and legacy methods\n const apiObject = {\n doc: { ...doc } as DocWithId<T>,\n merge,\n replace,\n reset,\n refresh,\n save,\n remove,\n };\n\n // Make the object properly iterable\n const tuple = [{ ...doc }, updateDoc, save, remove, reset, refresh];\n Object.assign(apiObject, tuple);\n Object.defineProperty(apiObject, Symbol.iterator, {\n enumerable: false,\n value: function* () {\n yield* tuple;\n },\n });\n\n return apiObject as UseDocumentResult<T>;\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 const docs = initialRows.map((r) => r.doc).filter((r): r is DocWithId<T> => !!r);\n return {\n rows: initialRows,\n docs,\n length: docs.length,\n map: (fn) => docs.map(fn),\n filter: (fn) => docs.filter(fn),\n forEach: (fn) => docs.forEach(fn),\n [Symbol.iterator]: () => docs[Symbol.iterator](),\n };\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 const docs = res.rows.map((r) => r.doc as DocWithId<T>).filter((r): r is DocWithId<T> => !!r);\n setResult({\n ...res,\n docs,\n length: docs.length,\n map: (fn) => docs.map(fn),\n filter: (fn) => docs.filter(fn),\n forEach: (fn) => docs.forEach(fn),\n [Symbol.iterator]: () => docs[Symbol.iterator](),\n });\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 and manage 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.\n *\n * ## Usage\n *\n * ```tsx\n * const todo = useDocument({\n * text: '',\n * date: Date.now(),\n * completed: false\n * })\n * // Access via object properties\n * todo.doc // The current document\n * todo.merge({ completed: true }) // Update specific fields\n * todo.replace({ text: 'new', date: Date.now(), completed: false }) // Replace entire doc\n * todo.save() // Save changes\n * todo.remove() // Delete document\n * todo.reset() // Reset to initial state\n * todo.refresh() // Refresh from database\n * ```\n *\n * ### Create document with custom ID\n * Custom IDs let you create predictable document identifiers for data that has\n * a natural unique key, like userIds or email addresses. This makes it easy to\n * look up and update specific documents without having to query for them first.\n * For example, storing user profiles by customerId:\n *\n * ```tsx\n * const profile = useDocument({\n * _id: `${props.customerId}-profile`, // Predictable ID based on customerId\n * name: \"\",\n * company: \"\",\n * startedAt: Date.now()\n * })\n * ```\n *\n * ## API\n *\n * - `doc`: The current document state\n * - `merge(newDoc)`: Merge new properties into the document\n * - `replace(newDoc)`: Replace the entire document\n * - `reset()`: Reset to initial state\n * - `refresh()`: Refresh from database\n * - `save()`: Save changes to the document\n * - `remove()`: Delete the document\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 { DocTypes, Database } 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","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 MapFn,\n QueryOpts,\n Database,\n} from \"@fireproof/core\";\nimport { fireproof } from \"@fireproof/core\";\nimport { useCallback, useEffect, useMemo, useState, useRef } 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 /** @internal */\n readonly length: number;\n /** @internal */\n map<U>(callbackfn: (value: DocWithId<T>, index: number, array: DocWithId<T>[]) => U): U[];\n /** @internal */\n filter(predicate: (value: DocWithId<T>, index: number, array: DocWithId<T>[]) => boolean): DocWithId<T>[];\n /** @internal */\n forEach(callbackfn: (value: DocWithId<T>, index: number, array: DocWithId<T>[]) => void): void;\n /** @internal */\n [Symbol.iterator](): Iterator<DocWithId<T>>;\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\ntype UseDocumentResultTuple<T extends DocTypes> = [DocWithId<T>, UpdateDocFn<T>, StoreDocFn<T>, DeleteDocFn<T>];\n\ninterface UseDocumentResultObject<T extends DocTypes> {\n doc: DocWithId<T>;\n merge: (newDoc: Partial<T>) => void;\n replace: (newDoc: T) => void;\n reset: () => void;\n refresh: () => Promise<void>;\n save: StoreDocFn<T>;\n remove: DeleteDocFn<T>;\n submit: (e?: Event) => Promise<void>;\n}\n\nexport type UseDocumentResult<T extends DocTypes> = UseDocumentResultObject<T> & UseDocumentResultTuple<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 = useDocument<Todo>({\n * text: '',\n * date: Date.now(),\n * completed: false\n * })\n * // Access via object properties\n * todo.doc // The current document\n * todo.merge({ completed: true }) // Update specific fields\n * todo.replace({ text: 'new', date: Date.now(), completed: false }) // Replace entire doc\n * todo.save() // Save changes\n * todo.remove() // Delete document\n * todo.reset() // Reset to initial state\n * todo.refresh() // Refresh from database\n *\n * // Or use tuple destructuring for legacy compatibility\n * const [doc, updateDoc, saveDoc, removeDoc] = todo\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 * ```\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\nfunction deepClone<T>(value: T): T {\n if (typeof structuredClone !== \"undefined\") {\n return structuredClone(value);\n } else {\n // Fallback if structuredClone is not available (older browsers, older Node versions, etc.)\n return JSON.parse(JSON.stringify(value));\n }\n}\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 const updateHappenedRef = useRef(false);\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 ?? ({} as T);\n }\n\n const originalInitialDoc = useMemo(() => deepClone({ ...initialDoc }), []);\n\n const [doc, setDoc] = useState(initialDoc);\n\n const refresh = useCallback(async () => {\n const gotDoc = doc._id ? await database.get<T>(doc._id).catch(() => initialDoc) : initialDoc;\n setDoc(gotDoc);\n }, [doc._id]);\n\n const save: StoreDocFn<T> = useCallback(\n async (existingDoc) => {\n updateHappenedRef.current = false;\n const toSave = existingDoc ?? doc;\n const res = await database.put(toSave);\n\n if (!updateHappenedRef.current && !doc._id && !existingDoc) {\n setDoc((d) => ({ ...d, _id: res.id }));\n }\n\n return res;\n },\n [doc],\n );\n\n const remove: DeleteDocFn<T> = useCallback(\n async (existingDoc) => {\n const id = existingDoc?._id ?? doc._id;\n if (!id) throw database.logger.Error().Msg(`Document must have an _id to be removed`).AsError();\n const gotDoc = await database.get<T>(id).catch(() => undefined);\n if (!gotDoc) 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 [doc, initialDoc],\n );\n\n // New granular update methods\n const merge = useCallback((newDoc: Partial<T>) => {\n updateHappenedRef.current = true;\n setDoc((prev) => ({ ...prev, ...newDoc }));\n }, []);\n\n const replace = useCallback((newDoc: T) => {\n updateHappenedRef.current = true;\n setDoc(newDoc);\n }, []);\n\n const reset = useCallback(() => {\n updateHappenedRef.current = true;\n setDoc({ ...originalInitialDoc });\n }, [originalInitialDoc]);\n\n // Legacy-compatible updateDoc\n const updateDoc = useCallback(\n (newDoc?: DocSet<T>, opts = { replace: false, reset: false }) => {\n if (!newDoc) {\n return opts.reset ? reset() : refresh();\n }\n return opts.replace ? replace(newDoc as T) : merge(newDoc);\n },\n [refresh, reset, replace, merge],\n );\n\n useEffect(() => {\n if (!doc._id) return;\n return database.subscribe((changes) => {\n if (updateHappenedRef.current) {\n return;\n }\n if (changes.find((c) => c._id === doc._id)) {\n void refresh();\n }\n }, true);\n }, [doc._id, refresh]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const submit = useCallback(\n async (e?: Event) => {\n if (e?.preventDefault) e.preventDefault();\n await save();\n reset();\n },\n [save, reset],\n );\n\n // Primary Object API with both new and legacy methods\n const apiObject = {\n doc: { ...doc } as DocWithId<T>,\n merge,\n replace,\n reset,\n refresh,\n save,\n remove,\n submit,\n };\n\n // Make the object properly iterable\n const tuple = [{ ...doc }, updateDoc, save, remove, reset, refresh];\n Object.assign(apiObject, tuple);\n Object.defineProperty(apiObject, Symbol.iterator, {\n enumerable: false,\n value: function* () {\n yield* tuple;\n },\n });\n\n return apiObject as UseDocumentResult<T>;\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 const docs = initialRows.map((r) => r.doc).filter((r): r is DocWithId<T> => !!r);\n return {\n rows: initialRows,\n docs,\n length: docs.length,\n map: (fn) => docs.map(fn),\n filter: (fn) => docs.filter(fn),\n forEach: (fn) => docs.forEach(fn),\n [Symbol.iterator]: () => docs[Symbol.iterator](),\n };\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 const docs = res.rows.map((r) => r.doc as DocWithId<T>).filter((r): r is DocWithId<T> => !!r);\n setResult({\n ...res,\n docs,\n length: docs.length,\n map: (fn) => docs.map(fn),\n filter: (fn) => docs.filter(fn),\n forEach: (fn) => docs.forEach(fn),\n [Symbol.iterator]: () => docs[Symbol.iterator](),\n });\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 and manage 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.\n *\n * ## Usage\n *\n * ```tsx\n * const todo = useDocument({\n * text: '',\n * date: Date.now(),\n * completed: false\n * })\n * // Access via object properties\n * todo.doc // The current document\n * todo.merge({ completed: true }) // Update specific fields\n * todo.replace({ text: 'new', date: Date.now(), completed: false }) // Replace entire doc\n * todo.save() // Save changes\n * todo.remove() // Delete document\n * todo.reset() // Reset to initial state\n * todo.refresh() // Refresh from database\n * ```\n *\n * ### Create document with custom ID\n * Custom IDs let you create predictable document identifiers for data that has\n * a natural unique key, like userIds or email addresses. This makes it easy to\n * look up and update specific documents without having to query for them first.\n * For example, storing user profiles by customerId:\n *\n * ```tsx\n * const profile = useDocument({\n * _id: `${props.customerId}-profile`, // Predictable ID based on customerId\n * name: \"\",\n * company: \"\",\n * startedAt: Date.now()\n * })\n * ```\n *\n * ## API\n *\n * - `doc`: The current document state\n * - `merge(newDoc)`: Merge new properties into the document\n * - `replace(newDoc)`: Replace the entire document\n * - `reset()`: Reset to initial state\n * - `refresh()`: Refresh from database\n * - `save()`: Save changes to the document\n * - `remove()`: Delete the document\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 { DocTypes, Database } 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","useLiveQuery","useAllDocs","useChanges","useDocument","useLiveQuery","useAllDocs","useChanges"]}
|
package/react/metafile-cjs.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"inputs":{"src/react/useFireproof.ts":{"bytes":
|
1
|
+
{"inputs":{"src/react/useFireproof.ts":{"bytes":14322,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/react/useDocument.ts":{"bytes":2460,"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":1017,"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":28152},"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":6388},"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":8541}}}
|
package/react/metafile-esm.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"inputs":{"src/react/useFireproof.ts":{"bytes":
|
1
|
+
{"inputs":{"src/react/useFireproof.ts":{"bytes":14322,"imports":[{"path":"@fireproof/core","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/react/useDocument.ts":{"bytes":2460,"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":1017,"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":26991},"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":5940},"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":7067}}}
|
@@ -70,7 +70,7 @@ describe("InterceptorGateway", () => {
|
|
70
70
|
await db.close();
|
71
71
|
await db.destroy();
|
72
72
|
// await sleep(1000);
|
73
|
-
expect(gwi.fn.mock.calls.length).toBe(
|
73
|
+
expect(gwi.fn.mock.calls.length).toBe(56);
|
74
74
|
// might be a stupid test
|
75
75
|
expect(gwi.fn.mock.calls.map((i) => i[0]).sort() /* not ok there are some operation */).toEqual(
|
76
76
|
[
|
@@ -79,17 +79,31 @@ describe("InterceptorGateway", () => {
|
|
79
79
|
"buildUrl",
|
80
80
|
"get",
|
81
81
|
"buildUrl",
|
82
|
+
"buildUrl",
|
83
|
+
"buildUrl",
|
84
|
+
"buildUrl",
|
85
|
+
"buildUrl",
|
86
|
+
"buildUrl",
|
87
|
+
"buildUrl",
|
88
|
+
"buildUrl",
|
89
|
+
"get",
|
82
90
|
"get",
|
83
91
|
"start",
|
84
92
|
"start",
|
85
93
|
"buildUrl",
|
86
94
|
"get",
|
95
|
+
"get",
|
87
96
|
"buildUrl",
|
88
97
|
"put",
|
98
|
+
"put",
|
89
99
|
"buildUrl",
|
90
100
|
"put",
|
91
101
|
"buildUrl",
|
92
102
|
"put",
|
103
|
+
"put",
|
104
|
+
"put",
|
105
|
+
"put",
|
106
|
+
"put",
|
93
107
|
"start",
|
94
108
|
"start",
|
95
109
|
"start",
|
@@ -1,9 +1,8 @@
|
|
1
1
|
import { bs, ensureSuperThis, PARAM, rt } from "@fireproof/core";
|
2
2
|
import { runtimeFn, toCryptoRuntime, URI } from "@adviser/cement";
|
3
3
|
import { base58btc } from "multiformats/bases/base58";
|
4
|
-
import { mockSuperThis } from "../helpers.js";
|
4
|
+
import { mockLoader, mockSuperThis } from "../helpers.js";
|
5
5
|
import { KeyBagProviderIndexedDB } from "@fireproof/core/indexeddb";
|
6
|
-
import { toKeyWithFingerPrint } from "../../src/runtime/key-bag.js";
|
7
6
|
|
8
7
|
describe("KeyBag indexeddb and file", () => {
|
9
8
|
let url: URI;
|
@@ -73,10 +72,10 @@ describe("KeyBag indexeddb and file", () => {
|
|
73
72
|
return JSON.parse(sthis.txt.decode(data)) as rt.kb.KeysItem;
|
74
73
|
});
|
75
74
|
}
|
76
|
-
expect((await toKeyWithFingerPrint(kb, Object.values(diskBag.keys)[0].key)).Ok().fingerPrint).toEqual(
|
75
|
+
expect((await rt.kb.toKeyWithFingerPrint(kb, Object.values(diskBag.keys)[0].key)).Ok().fingerPrint).toEqual(
|
77
76
|
(await res.Ok().get())?.fingerPrint,
|
78
77
|
);
|
79
|
-
expect((await toKeyWithFingerPrint(kb, Object.values(diskBag2.keys)[0].key)).Ok().fingerPrint).toEqual(
|
78
|
+
expect((await rt.kb.toKeyWithFingerPrint(kb, Object.values(diskBag2.keys)[0].key)).Ok().fingerPrint).toEqual(
|
80
79
|
(await created.Ok().get())?.fingerPrint,
|
81
80
|
);
|
82
81
|
const algo = {
|
@@ -105,29 +104,20 @@ describe("KeyedCryptoStore", () => {
|
|
105
104
|
beforeEach(async () => {
|
106
105
|
await sthis.start();
|
107
106
|
// logger = MockLogger().logger;
|
108
|
-
let kbUrl: URI;
|
107
|
+
// let kbUrl: URI;
|
109
108
|
if (runtimeFn().isBrowser) {
|
110
|
-
kbUrl = URI.from("indexeddb://fp-keybag");
|
109
|
+
// kbUrl = URI.from("indexeddb://fp-keybag");
|
111
110
|
baseUrl = URI.from("indexeddb://fp-keyed-crypto-store");
|
112
111
|
} else {
|
113
|
-
kbUrl = URI.merge(`file://./dist/tests/key.bag`, sthis.env.get("FP_KEYBAG_URL"));
|
112
|
+
// kbUrl = URI.merge(`file://./dist/tests/key.bag`, sthis.env.get("FP_KEYBAG_URL"));
|
114
113
|
baseUrl = URI.merge("file://./dist/tests/keyed-crypto-store", sthis.env.get("FP_STORAGE_URL"));
|
115
114
|
}
|
116
115
|
baseUrl = baseUrl.build().defParam(PARAM.NAME, "test").URI();
|
117
|
-
loader =
|
118
|
-
sthis,
|
119
|
-
keyBag: () => rt.kb.getKeyBag(sthis, { url: kbUrl }),
|
120
|
-
} as bs.Loadable;
|
116
|
+
loader = mockLoader(sthis);
|
121
117
|
});
|
122
118
|
it("no crypto", async () => {
|
123
|
-
const strt = bs.toStoreRuntime(sthis);
|
124
119
|
const url = baseUrl.build().setParam(PARAM.STORE_KEY, "insecure").URI();
|
125
|
-
|
126
|
-
for (const pstore of [
|
127
|
-
strt.makeDataStore({ url, loader }),
|
128
|
-
strt.makeMetaStore({ url, loader }),
|
129
|
-
strt.makeWALStore({ url, loader }),
|
130
|
-
]) {
|
120
|
+
for (const pstore of (await bs.createAttachedStores(url, loader, "insecure")).stores.baseStores) {
|
131
121
|
const store = await pstore;
|
132
122
|
// await store.start();
|
133
123
|
const kc = await store.keyedCrypto();
|
@@ -1,12 +1,11 @@
|
|
1
|
-
import { bs, ensureSuperThis, PARAM, rt } from "@fireproof/core";
|
1
|
+
import { bs, ensureSuperThis, PARAM, rt, StoreType, storeType2DataMetaWal } from "@fireproof/core";
|
2
2
|
import { BuildURI, runtimeFn, toCryptoRuntime, URI } from "@adviser/cement";
|
3
3
|
import { base58btc } from "multiformats/bases/base58";
|
4
|
-
import { sha256 as hasher } from "multiformats/hashes/sha2";
|
5
|
-
import * as dagCodec from "@ipld/dag-cbor";
|
4
|
+
// import { sha256 as hasher } from "multiformats/hashes/sha2";
|
5
|
+
// import * as dagCodec from "@ipld/dag-cbor";
|
6
|
+
import * as cborg from "cborg";
|
6
7
|
import type { KeyBagProviderIndexedDB } from "@fireproof/core/indexeddb";
|
7
|
-
import { MockSuperThis, mockSuperThis } from "../helpers.js";
|
8
|
-
import { KeyWithFingerPrint } from "../../src/blockstore/types.js";
|
9
|
-
import { toKeyWithFingerPrint } from "../../src/runtime/key-bag.js";
|
8
|
+
import { mockLoader, MockSuperThis, mockSuperThis } from "../helpers.js";
|
10
9
|
|
11
10
|
describe("KeyBag", () => {
|
12
11
|
let url: URI;
|
@@ -113,10 +112,10 @@ describe("KeyBag", () => {
|
|
113
112
|
return JSON.parse(sthis.txt.decode(data)) as rt.kb.KeysItem;
|
114
113
|
});
|
115
114
|
}
|
116
|
-
expect((await toKeyWithFingerPrint(kb, Object.values(diskBag.keys)[0].key)).Ok().fingerPrint).toEqual(
|
115
|
+
expect((await rt.toKeyWithFingerPrint(kb, Object.values(diskBag.keys)[0].key)).Ok().fingerPrint).toEqual(
|
117
116
|
(await res.Ok().get())?.fingerPrint,
|
118
117
|
);
|
119
|
-
expect((await toKeyWithFingerPrint(kb, Object.values(diskBag2.keys)[0].key)).Ok().fingerPrint).toEqual(
|
118
|
+
expect((await rt.toKeyWithFingerPrint(kb, Object.values(diskBag2.keys)[0].key)).Ok().fingerPrint).toEqual(
|
120
119
|
(await created.Ok().get())?.fingerPrint,
|
121
120
|
);
|
122
121
|
const algo = {
|
@@ -129,7 +128,7 @@ describe("KeyBag", () => {
|
|
129
128
|
expect(await kb.rt.crypto.encrypt(algo, (await res.Ok().get())!.key, data))
|
130
129
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
131
130
|
.toEqual(await kb.rt.crypto.encrypt(algo, (await created.Ok().get())!.key, data));
|
132
|
-
const kf = (await created.Ok().get()) as KeyWithFingerPrint;
|
131
|
+
const kf = (await created.Ok().get()) as bs.KeyWithFingerPrint;
|
133
132
|
expect(await kb.rt.crypto.encrypt(algo, await kb.subtleKey(Object.values(diskBag.keys)[0].key), data)).toEqual(
|
134
133
|
await kb.rt.crypto.encrypt(algo, kf.key, data),
|
135
134
|
);
|
@@ -150,11 +149,11 @@ describe("KeyBag", () => {
|
|
150
149
|
}
|
151
150
|
expect(Object.keys((await kb.getNamedKey(name).then((i) => i.Ok().asKeysItem())).keys).length).toBe(1);
|
152
151
|
|
153
|
-
const myKey = (await rMyKey.Ok().get()) as KeyWithFingerPrint;
|
152
|
+
const myKey = (await rMyKey.Ok().get()) as bs.KeyWithFingerPrint;
|
154
153
|
expect(myKey.fingerPrint).toMatch(/^z/);
|
155
154
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
156
155
|
await rMyKey.Ok().upsert((await myKey.extract())!.key);
|
157
|
-
const myKey1 = (await rMyKey.Ok().get()) as KeyWithFingerPrint;
|
156
|
+
const myKey1 = (await rMyKey.Ok().get()) as bs.KeyWithFingerPrint;
|
158
157
|
expect(myKey.fingerPrint).toEqual(myKey1.fingerPrint);
|
159
158
|
|
160
159
|
expect(Object.keys((await kb.getNamedKey(name).then((i) => i.Ok().asKeysItem())).keys).length).toBe(1);
|
@@ -164,13 +163,13 @@ describe("KeyBag", () => {
|
|
164
163
|
const res1 = await rMyKey1.Ok().upsert(kb.rt.crypto.randomBytes(kb.rt.keyLength));
|
165
164
|
expect(res1.isOk()).toBeTruthy();
|
166
165
|
|
167
|
-
const myKey2 = (await rMyKey1.Ok().get()) as KeyWithFingerPrint;
|
166
|
+
const myKey2 = (await rMyKey1.Ok().get()) as bs.KeyWithFingerPrint;
|
168
167
|
expect(myKey.fingerPrint).toEqual(myKey2.fingerPrint);
|
169
168
|
expect(Object.keys((await kb.getNamedKey(name).then((i) => i.Ok().asKeysItem())).keys).length).toBe(2);
|
170
169
|
|
171
170
|
const res = await rMyKey1.Ok().upsert(kb.rt.crypto.randomBytes(kb.rt.keyLength), true);
|
172
171
|
expect(res.isOk()).toBeTruthy();
|
173
|
-
const myKey3 = (await rMyKey.Ok().get()) as KeyWithFingerPrint;
|
172
|
+
const myKey3 = (await rMyKey.Ok().get()) as bs.KeyWithFingerPrint;
|
174
173
|
expect(Object.keys((await kb.getNamedKey(name).then((i) => i.Ok().asKeysItem())).keys).length).toBe(3);
|
175
174
|
|
176
175
|
expect(myKey.fingerPrint).not.toEqual(myKey3.fingerPrint);
|
@@ -185,7 +184,7 @@ describe("KeyBag", () => {
|
|
185
184
|
});
|
186
185
|
const key = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
|
187
186
|
const name = "default-key" + Math.random();
|
188
|
-
const fpr = (await toKeyWithFingerPrint(kb, key)).Ok().fingerPrint;
|
187
|
+
const fpr = (await rt.toKeyWithFingerPrint(kb, key)).Ok().fingerPrint;
|
189
188
|
const rMyKey = await kb.getNamedKey(name, false, key);
|
190
189
|
expect(rMyKey.isOk()).toBeTruthy();
|
191
190
|
const myKey = rMyKey.Ok();
|
@@ -199,7 +198,7 @@ describe("KeyBag", () => {
|
|
199
198
|
const keys = [{ key, fpr }];
|
200
199
|
for (let i = 0; i < 10; ++i) {
|
201
200
|
const key = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
|
202
|
-
const fpr = (await toKeyWithFingerPrint(kb, key)).Ok().fingerPrint;
|
201
|
+
const fpr = (await rt.toKeyWithFingerPrint(kb, key)).Ok().fingerPrint;
|
203
202
|
keys.push({ key, fpr });
|
204
203
|
const rUpsert = await myKey.upsert(key, true);
|
205
204
|
expect(rUpsert.Ok().modified).toBeTruthy();
|
@@ -230,11 +229,11 @@ describe("KeyBag", () => {
|
|
230
229
|
});
|
231
230
|
|
232
231
|
describe("KeyedCryptoStore", () => {
|
233
|
-
let loader: bs.Loadable;
|
234
232
|
let kb: rt.kb.KeyBag;
|
235
233
|
// let logger: Logger;
|
236
234
|
let baseUrl: URI;
|
237
235
|
const sthis = ensureSuperThis();
|
236
|
+
let loader: bs.Loadable;
|
238
237
|
beforeEach(async () => {
|
239
238
|
await sthis.start();
|
240
239
|
// logger = MockLogger().logger;
|
@@ -256,20 +255,12 @@ describe("KeyedCryptoStore", () => {
|
|
256
255
|
}
|
257
256
|
baseUrl = baseUrl.build().setParam(PARAM.NAME, "test").URI();
|
258
257
|
kb = await rt.kb.getKeyBag(sthis, {});
|
259
|
-
loader =
|
260
|
-
sthis,
|
261
|
-
keyBag: async () => kb,
|
262
|
-
} as bs.Loadable;
|
258
|
+
loader = mockLoader(sthis);
|
263
259
|
});
|
264
260
|
it("no crypto", async () => {
|
265
|
-
const strt = bs.toStoreRuntime(sthis);
|
266
261
|
const url = baseUrl.build().setParam(PARAM.STORE_KEY, "insecure").URI();
|
267
262
|
|
268
|
-
for (const pstore of
|
269
|
-
strt.makeDataStore({ url, loader }),
|
270
|
-
strt.makeMetaStore({ url, loader }),
|
271
|
-
strt.makeWALStore({ url, loader }),
|
272
|
-
]) {
|
263
|
+
for (const pstore of (await bs.createAttachedStores(url, loader, "insecure")).stores.baseStores) {
|
273
264
|
const store = await pstore;
|
274
265
|
// await store.start();
|
275
266
|
const kc = await store.keyedCrypto();
|
@@ -281,17 +272,14 @@ describe("KeyedCryptoStore", () => {
|
|
281
272
|
});
|
282
273
|
|
283
274
|
it("create key", async () => {
|
284
|
-
const
|
285
|
-
for (const pstore of [
|
286
|
-
strt.makeDataStore({ url: baseUrl, loader }),
|
287
|
-
strt.makeMetaStore({ url: baseUrl, loader }),
|
288
|
-
strt.makeWALStore({ url: baseUrl, loader }),
|
289
|
-
]) {
|
275
|
+
for (const pstore of (await bs.createAttachedStores(baseUrl, loader, "insecure")).stores.baseStores) {
|
290
276
|
const store = await pstore; // await bs.ensureStart(await pstore, logger);
|
291
277
|
const kc = await store.keyedCrypto();
|
292
278
|
expect(kc.constructor.name).toBe("cryptoAction");
|
293
279
|
// expect(kc.isEncrypting).toBe(true);
|
294
|
-
expect(store.url().getParam(PARAM.STORE_KEY)).toBe(
|
280
|
+
expect(store.url().getParam(PARAM.STORE_KEY)).toBe(
|
281
|
+
`@test-${storeType2DataMetaWal(store.url().getParam(PARAM.STORE) as StoreType)}@`,
|
282
|
+
);
|
295
283
|
}
|
296
284
|
});
|
297
285
|
|
@@ -299,12 +287,7 @@ describe("KeyedCryptoStore", () => {
|
|
299
287
|
const key = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
|
300
288
|
const genKey = await kb.getNamedKey("@heute@", false, key);
|
301
289
|
const url = baseUrl.build().setParam(PARAM.STORE_KEY, "@heute@").URI();
|
302
|
-
const
|
303
|
-
for (const pstore of [
|
304
|
-
strt.makeDataStore({ url, loader }),
|
305
|
-
strt.makeMetaStore({ url, loader }),
|
306
|
-
strt.makeWALStore({ url, loader }),
|
307
|
-
]) {
|
290
|
+
for (const pstore of (await bs.createAttachedStores(url, loader, "insecure")).stores.baseStores) {
|
308
291
|
const store = await pstore;
|
309
292
|
// await store.start();
|
310
293
|
expect(store.url().getParam(PARAM.STORE_KEY)).toBe(`@heute@`);
|
@@ -315,7 +298,7 @@ describe("KeyedCryptoStore", () => {
|
|
315
298
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
316
299
|
const blk = await kc._encrypt({ bytes: testData, key: (await kc.key.get())!.key, iv });
|
317
300
|
expect(blk).not.toEqual(testData);
|
318
|
-
const fpkey = (await genKey.Ok().get()) as KeyWithFingerPrint;
|
301
|
+
const fpkey = (await genKey.Ok().get()) as bs.KeyWithFingerPrint;
|
319
302
|
expect(fpkey.fingerPrint).toEqual(fpkey.fingerPrint);
|
320
303
|
const dec = new Uint8Array(await kc.crypto.decrypt(kc.algo(iv), fpkey.key, blk));
|
321
304
|
expect(dec).toEqual(testData);
|
@@ -324,13 +307,8 @@ describe("KeyedCryptoStore", () => {
|
|
324
307
|
|
325
308
|
it("key", async () => {
|
326
309
|
const key = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
|
327
|
-
const strt = bs.toStoreRuntime(sthis);
|
328
310
|
const url = baseUrl.build().setParam(PARAM.STORE_KEY, key).URI();
|
329
|
-
for (const pstore of
|
330
|
-
strt.makeDataStore({ url, loader }),
|
331
|
-
strt.makeMetaStore({ url, loader }),
|
332
|
-
strt.makeWALStore({ url, loader }),
|
333
|
-
]) {
|
311
|
+
for (const pstore of (await bs.createAttachedStores(url, loader, "insecure")).stores.baseStores) {
|
334
312
|
// for (const pstore of [strt.makeDataStore(loader), strt.makeMetaStore(loader), strt.makeWALStore(loader)]) {
|
335
313
|
const store = await pstore;
|
336
314
|
// await store.start();
|
@@ -339,7 +317,7 @@ describe("KeyedCryptoStore", () => {
|
|
339
317
|
expect(kc.constructor.name).toBe("cryptoAction");
|
340
318
|
const testData = kb.rt.crypto.randomBytes(1024);
|
341
319
|
const iv = kb.rt.crypto.randomBytes(12);
|
342
|
-
const ks = (await kc.key.get()) as KeyWithFingerPrint;
|
320
|
+
const ks = (await kc.key.get()) as bs.KeyWithFingerPrint;
|
343
321
|
const blk = await kc._encrypt({ bytes: testData, key: ks.key, iv });
|
344
322
|
expect(blk).not.toEqual(testData);
|
345
323
|
const dec = await kc._decrypt({ bytes: blk, key: ks.key, iv });
|
@@ -371,12 +349,12 @@ describe("KeyedCrypto", () => {
|
|
371
349
|
const iv = kb.rt.crypto.randomBytes(12);
|
372
350
|
const codec = kycr.codec(iv, { noIVVerify: true });
|
373
351
|
const blk = (await codec.encode(testData)) as Uint8Array;
|
374
|
-
const myDec =
|
375
|
-
expect(myDec.
|
376
|
-
const kc = (await kycr.key.get()) as KeyWithFingerPrint;
|
377
|
-
expect(base58btc.encode(myDec.
|
352
|
+
const myDec = cborg.decode(blk) as bs.IvKeyIdData;
|
353
|
+
expect(myDec.iv).toEqual(iv);
|
354
|
+
const kc = (await kycr.key.get()) as bs.KeyWithFingerPrint;
|
355
|
+
expect(base58btc.encode(myDec.keyId)).toEqual(kc.fingerPrint);
|
378
356
|
const dec = await codec.decode(blk);
|
379
|
-
expect(dec).toEqual(testData);
|
357
|
+
expect(dec.data).toEqual(testData);
|
380
358
|
});
|
381
359
|
|
382
360
|
it("codec implict iv", async () => {
|
@@ -385,7 +363,7 @@ describe("KeyedCrypto", () => {
|
|
385
363
|
const blk = await codec.encode(testData);
|
386
364
|
expect(blk.length).toBeGreaterThanOrEqual(12 + testData.length);
|
387
365
|
const dec = await codec.decode(blk);
|
388
|
-
expect(dec).toEqual(testData);
|
366
|
+
expect(dec.data).toEqual(testData);
|
389
367
|
});
|
390
368
|
|
391
369
|
it("codec implict iv same for multiple clients", async () => {
|