@qntx/wallet-engine 0.5.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/contract-CEsgLme3.mjs +277 -0
- package/dist/contract-CEsgLme3.mjs.map +1 -0
- package/dist/gateway-contract.d.mts +285 -0
- package/dist/gateway-contract.mjs +1 -0
- package/dist/idb.d.mts +0 -4
- package/dist/idb.mjs +3 -6
- package/dist/idb.mjs.map +1 -1
- package/dist/index.d.mts +976 -499
- package/dist/index.mjs +2971 -965
- package/dist/index.mjs.map +1 -1
- package/dist/registry-LcFSPrE1.d.mts +23 -0
- package/package.json +14 -8
package/dist/idb.d.mts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
//#region src/store/port.d.ts
|
|
2
1
|
/**
|
|
3
2
|
* Engine storage port: named collections of byte values. `collection` is synchronous and cheap —
|
|
4
3
|
* the same collection object backs every call, so guards (closed) live on the store.
|
|
@@ -14,8 +13,6 @@ type EngineStore = {
|
|
|
14
13
|
readonly collection: (name: string) => EngineCollection;
|
|
15
14
|
readonly close: () => Promise<void>;
|
|
16
15
|
};
|
|
17
|
-
//#endregion
|
|
18
|
-
//#region src/idb/indexeddb.d.ts
|
|
19
16
|
export type Random = (length: number) => Uint8Array;
|
|
20
17
|
export type IndexedDbEngineStoreOptions = {
|
|
21
18
|
readonly name: string;
|
|
@@ -23,6 +20,5 @@ export type IndexedDbEngineStoreOptions = {
|
|
|
23
20
|
readonly random: Random;
|
|
24
21
|
};
|
|
25
22
|
export declare function openIndexedDbEngineStore(options: IndexedDbEngineStoreOptions): Promise<EngineStore>;
|
|
26
|
-
//#endregion
|
|
27
23
|
export {};
|
|
28
24
|
//# sourceMappingURL=idb.d.mts.map
|
package/dist/idb.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
|
|
2
|
-
|
|
2
|
+
// src/errors.ts
|
|
3
3
|
/** Typed engine errors: store codes are `closed` and `integrity` (decrypt or bind failure). */
|
|
4
4
|
var EngineStoreError = class extends Error {
|
|
5
5
|
code;
|
|
@@ -9,14 +9,12 @@ var EngineStoreError = class extends Error {
|
|
|
9
9
|
this.code = code;
|
|
10
10
|
}
|
|
11
11
|
};
|
|
12
|
-
|
|
13
|
-
//#region src/store/guard.ts
|
|
12
|
+
// src/store/guard.ts
|
|
14
13
|
/** NUL is the composite-key/AAD separator — a name or key containing it collides. */
|
|
15
14
|
function checkName(kind, value) {
|
|
16
15
|
if (value.includes("\0")) throw new EngineStoreError("invalid-input", `${kind} must not contain NUL`);
|
|
17
16
|
}
|
|
18
|
-
|
|
19
|
-
//#region src/idb/indexeddb.ts
|
|
17
|
+
// src/idb/indexeddb.ts
|
|
20
18
|
/**
|
|
21
19
|
* The Web EngineStore: one IndexedDB database, one `records` object store, values encrypted per
|
|
22
20
|
* record with XChaCha20-Poly1305. Key = the injected 32-byte data key; nonce = 24 random bytes
|
|
@@ -128,7 +126,6 @@ function makeStore(db, key, random) {
|
|
|
128
126
|
}
|
|
129
127
|
};
|
|
130
128
|
}
|
|
131
|
-
//#endregion
|
|
132
129
|
export { openIndexedDbEngineStore };
|
|
133
130
|
|
|
134
131
|
//# sourceMappingURL=idb.mjs.map
|
package/dist/idb.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idb.mjs","names":[],"sources":["../src/errors.ts","../src/store/guard.ts","../src/idb/indexeddb.ts"],"sourcesContent":["export type EngineErrorCode = \"closed\" | \"integrity\" | \"invalid-input\";\n\n/** Typed engine errors: store codes are `closed` and `integrity` (decrypt or bind failure). */\nexport class EngineStoreError extends Error {\n readonly code: EngineErrorCode;\n\n constructor(code: EngineErrorCode, message: string) {\n super(message);\n this.name = \"EngineStoreError\";\n this.code = code;\n }\n}\n","import { EngineStoreError } from \"../errors.ts\";\n\n/** NUL is the composite-key/AAD separator — a name or key containing it collides. */\nexport function checkName(kind: \"collection\" | \"key\", value: string): void {\n if (value.includes(\"\\u0000\")) {\n throw new EngineStoreError(\"invalid-input\", `${kind} must not contain NUL`);\n }\n}\n","/**\n * The Web EngineStore: one IndexedDB database, one `records` object store, values encrypted per\n * record with XChaCha20-Poly1305. Key = the injected 32-byte data key; nonce = 24 random bytes\n * stored as nonce‖ciphertext; AAD = UTF-8 `<collection>\\0<key>` — moving a record to another key or\n * collection fails the MAC, same as a tampered payload. `close()` drops the connection, wipes the\n * module-held key copy and latches every call to `closed`.\n */\nimport { xchacha20poly1305 } from \"@noble/ciphers/chacha.js\";\n\nimport { EngineStoreError } from \"../errors.ts\";\nimport { checkName } from \"../store/guard.ts\";\nimport type { EngineCollection, EngineStore } from \"../store/port.ts\";\n\nexport type Random = (length: number) => Uint8Array;\n\nexport type IndexedDbEngineStoreOptions = {\n readonly name: string;\n readonly dataKey: Uint8Array;\n readonly random: Random;\n};\n\nconst STORE = \"records\";\n\nconst id = (collection: string, recordKey: string): string => `${collection}\\u0000${recordKey}`;\nconst aad = (collection: string, recordKey: string): Uint8Array =>\n new TextEncoder().encode(`${collection}\\u0000${recordKey}`);\n\nasync function request<T>(req: IDBRequest<T>): Promise<T> {\n return new Promise((resolve, reject) => {\n req.addEventListener(\"success\", () => {\n resolve(req.result);\n });\n req.addEventListener(\"error\", () => {\n reject(new Error(\"indexeddb request failed\", { cause: req.error }));\n });\n });\n}\n\nasync function done(tx: IDBTransaction): Promise<void> {\n return new Promise((resolve, reject) => {\n tx.addEventListener(\"complete\", () => {\n resolve();\n });\n tx.addEventListener(\"error\", () => {\n reject(new Error(\"indexeddb transaction failed\", { cause: tx.error }));\n });\n tx.addEventListener(\"abort\", () => {\n reject(new Error(\"indexeddb transaction aborted\", { cause: tx.error }));\n });\n });\n}\n\nexport async function openIndexedDbEngineStore(\n options: IndexedDbEngineStoreOptions,\n): Promise<EngineStore> {\n const key = new Uint8Array(options.dataKey);\n return new Promise<EngineStore>((resolve, reject) => {\n const open = indexedDB.open(options.name, 1);\n open.addEventListener(\"upgradeneeded\", () => {\n open.result.createObjectStore(STORE);\n });\n open.addEventListener(\"success\", () => {\n resolve(makeStore(open.result, key, options.random));\n });\n open.addEventListener(\"error\", () => {\n key.fill(0);\n reject(new Error(\"indexeddb open failed\", { cause: open.error }));\n });\n });\n}\n\nfunction makeStore(db: IDBDatabase, key: Uint8Array, random: Random): EngineStore {\n let closed = false;\n\n const guard = (): IDBDatabase => {\n if (closed) {\n throw new EngineStoreError(\"closed\", \"engine store is closed\");\n }\n return db;\n };\n\n const seal = (collection: string, recordKey: string, bytes: Uint8Array): Uint8Array => {\n const nonce = random(24);\n const ciphertext = xchacha20poly1305(key, nonce, aad(collection, recordKey)).encrypt(bytes);\n const record = new Uint8Array(24 + ciphertext.length);\n record.set(nonce, 0);\n record.set(ciphertext, 24);\n return record;\n };\n\n const open = (collection: string, recordKey: string, record: Uint8Array): Uint8Array => {\n if (record.length < 24) {\n throw new EngineStoreError(\"integrity\", \"engine record too short\");\n }\n try {\n return xchacha20poly1305(key, record.slice(0, 24), aad(collection, recordKey)).decrypt(\n record.slice(24),\n );\n } catch {\n throw new EngineStoreError(\"integrity\", \"engine record failed integrity\");\n }\n };\n\n const make = (name: string): EngineCollection => ({\n get: async (recordKey) => {\n const database = guard();\n checkName(\"key\", recordKey);\n const tx = database.transaction(STORE, \"readonly\");\n const raw = tx.objectStore(STORE).get(id(name, recordKey));\n // oxlint-disable-next-line typescript/no-unsafe-argument -- IDB get() is any-typed by spec\n const record = await request<Uint8Array | undefined>(raw);\n return record === undefined ? undefined : open(name, recordKey, record);\n },\n put: async (recordKey, bytes) => {\n const database = guard();\n checkName(\"key\", recordKey);\n const tx = database.transaction(STORE, \"readwrite\");\n tx.objectStore(STORE).put(seal(name, recordKey, bytes), id(name, recordKey));\n await done(tx);\n },\n delete: async (recordKey) => {\n const database = guard();\n checkName(\"key\", recordKey);\n const tx = database.transaction(STORE, \"readwrite\");\n tx.objectStore(STORE).delete(id(name, recordKey));\n await done(tx);\n },\n list: async () => {\n const database = guard();\n const tx = database.transaction(STORE, \"readonly\");\n const all = tx.objectStore(STORE).getAllKeys();\n const keys = await request<IDBValidKey[]>(all);\n const prefix = `${name}\\u0000`;\n return keys\n .filter((k): k is string => typeof k === \"string\" && k.startsWith(prefix))\n .map((k) => k.slice(prefix.length));\n },\n });\n\n return {\n collection: (name) => {\n checkName(\"collection\", name);\n return make(name);\n },\n close: async () => {\n closed = true;\n db.close();\n key.fill(0);\n await Promise.resolve();\n },\n };\n}\n"],"mappings":";;;AAGA,IAAa,mBAAb,cAAsC,MAAM;CAC1C;CAEA,YAAY,MAAuB,SAAiB;EAClD,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,OAAO;CACd;AACF
|
|
1
|
+
{"version":3,"file":"idb.mjs","names":[],"sources":["../src/errors.ts","../src/store/guard.ts","../src/idb/indexeddb.ts"],"sourcesContent":["export type EngineErrorCode = \"closed\" | \"integrity\" | \"invalid-input\";\n\n/** Typed engine errors: store codes are `closed` and `integrity` (decrypt or bind failure). */\nexport class EngineStoreError extends Error {\n readonly code: EngineErrorCode;\n\n constructor(code: EngineErrorCode, message: string) {\n super(message);\n this.name = \"EngineStoreError\";\n this.code = code;\n }\n}\n","import { EngineStoreError } from \"../errors.ts\";\n\n/** NUL is the composite-key/AAD separator — a name or key containing it collides. */\nexport function checkName(kind: \"collection\" | \"key\", value: string): void {\n if (value.includes(\"\\u0000\")) {\n throw new EngineStoreError(\"invalid-input\", `${kind} must not contain NUL`);\n }\n}\n","/**\n * The Web EngineStore: one IndexedDB database, one `records` object store, values encrypted per\n * record with XChaCha20-Poly1305. Key = the injected 32-byte data key; nonce = 24 random bytes\n * stored as nonce‖ciphertext; AAD = UTF-8 `<collection>\\0<key>` — moving a record to another key or\n * collection fails the MAC, same as a tampered payload. `close()` drops the connection, wipes the\n * module-held key copy and latches every call to `closed`.\n */\nimport { xchacha20poly1305 } from \"@noble/ciphers/chacha.js\";\n\nimport { EngineStoreError } from \"../errors.ts\";\nimport { checkName } from \"../store/guard.ts\";\nimport type { EngineCollection, EngineStore } from \"../store/port.ts\";\n\nexport type Random = (length: number) => Uint8Array;\n\nexport type IndexedDbEngineStoreOptions = {\n readonly name: string;\n readonly dataKey: Uint8Array;\n readonly random: Random;\n};\n\nconst STORE = \"records\";\n\nconst id = (collection: string, recordKey: string): string => `${collection}\\u0000${recordKey}`;\nconst aad = (collection: string, recordKey: string): Uint8Array =>\n new TextEncoder().encode(`${collection}\\u0000${recordKey}`);\n\nasync function request<T>(req: IDBRequest<T>): Promise<T> {\n return new Promise((resolve, reject) => {\n req.addEventListener(\"success\", () => {\n resolve(req.result);\n });\n req.addEventListener(\"error\", () => {\n reject(new Error(\"indexeddb request failed\", { cause: req.error }));\n });\n });\n}\n\nasync function done(tx: IDBTransaction): Promise<void> {\n return new Promise((resolve, reject) => {\n tx.addEventListener(\"complete\", () => {\n resolve();\n });\n tx.addEventListener(\"error\", () => {\n reject(new Error(\"indexeddb transaction failed\", { cause: tx.error }));\n });\n tx.addEventListener(\"abort\", () => {\n reject(new Error(\"indexeddb transaction aborted\", { cause: tx.error }));\n });\n });\n}\n\nexport async function openIndexedDbEngineStore(\n options: IndexedDbEngineStoreOptions,\n): Promise<EngineStore> {\n const key = new Uint8Array(options.dataKey);\n return new Promise<EngineStore>((resolve, reject) => {\n const open = indexedDB.open(options.name, 1);\n open.addEventListener(\"upgradeneeded\", () => {\n open.result.createObjectStore(STORE);\n });\n open.addEventListener(\"success\", () => {\n resolve(makeStore(open.result, key, options.random));\n });\n open.addEventListener(\"error\", () => {\n key.fill(0);\n reject(new Error(\"indexeddb open failed\", { cause: open.error }));\n });\n });\n}\n\nfunction makeStore(db: IDBDatabase, key: Uint8Array, random: Random): EngineStore {\n let closed = false;\n\n const guard = (): IDBDatabase => {\n if (closed) {\n throw new EngineStoreError(\"closed\", \"engine store is closed\");\n }\n return db;\n };\n\n const seal = (collection: string, recordKey: string, bytes: Uint8Array): Uint8Array => {\n const nonce = random(24);\n const ciphertext = xchacha20poly1305(key, nonce, aad(collection, recordKey)).encrypt(bytes);\n const record = new Uint8Array(24 + ciphertext.length);\n record.set(nonce, 0);\n record.set(ciphertext, 24);\n return record;\n };\n\n const open = (collection: string, recordKey: string, record: Uint8Array): Uint8Array => {\n if (record.length < 24) {\n throw new EngineStoreError(\"integrity\", \"engine record too short\");\n }\n try {\n return xchacha20poly1305(key, record.slice(0, 24), aad(collection, recordKey)).decrypt(\n record.slice(24),\n );\n } catch {\n throw new EngineStoreError(\"integrity\", \"engine record failed integrity\");\n }\n };\n\n const make = (name: string): EngineCollection => ({\n get: async (recordKey) => {\n const database = guard();\n checkName(\"key\", recordKey);\n const tx = database.transaction(STORE, \"readonly\");\n const raw = tx.objectStore(STORE).get(id(name, recordKey));\n // oxlint-disable-next-line typescript/no-unsafe-argument -- IDB get() is any-typed by spec\n const record = await request<Uint8Array | undefined>(raw);\n return record === undefined ? undefined : open(name, recordKey, record);\n },\n put: async (recordKey, bytes) => {\n const database = guard();\n checkName(\"key\", recordKey);\n const tx = database.transaction(STORE, \"readwrite\");\n tx.objectStore(STORE).put(seal(name, recordKey, bytes), id(name, recordKey));\n await done(tx);\n },\n delete: async (recordKey) => {\n const database = guard();\n checkName(\"key\", recordKey);\n const tx = database.transaction(STORE, \"readwrite\");\n tx.objectStore(STORE).delete(id(name, recordKey));\n await done(tx);\n },\n list: async () => {\n const database = guard();\n const tx = database.transaction(STORE, \"readonly\");\n const all = tx.objectStore(STORE).getAllKeys();\n const keys = await request<IDBValidKey[]>(all);\n const prefix = `${name}\\u0000`;\n return keys\n .filter((k): k is string => typeof k === \"string\" && k.startsWith(prefix))\n .map((k) => k.slice(prefix.length));\n },\n });\n\n return {\n collection: (name) => {\n checkName(\"collection\", name);\n return make(name);\n },\n close: async () => {\n closed = true;\n db.close();\n key.fill(0);\n await Promise.resolve();\n },\n };\n}\n"],"mappings":"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"}
|