@spirobel/monero-wallet-api 0.1.2 → 0.3.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.
Files changed (67) hide show
  1. package/README.md +13 -1
  2. package/dist/api.d.ts +25 -53
  3. package/dist/api.js +23 -101
  4. package/dist/io/BunFileInterface.d.ts +32 -0
  5. package/dist/io/BunFileInterface.js +1 -0
  6. package/dist/io/atomicWrite.d.ts +2 -0
  7. package/dist/io/atomicWrite.js +10 -0
  8. package/dist/io/extension.d.ts +18 -0
  9. package/dist/io/extension.js +11 -0
  10. package/dist/io/indexedDB.d.ts +45 -0
  11. package/dist/io/indexedDB.js +221 -0
  12. package/dist/io/readDir.d.ts +1 -0
  13. package/dist/io/readDir.js +7 -0
  14. package/dist/io/sleep.d.ts +1 -0
  15. package/dist/io/sleep.js +1 -0
  16. package/dist/keypairs-seeds/keypairs.d.ts +29 -0
  17. package/dist/keypairs-seeds/keypairs.js +207 -0
  18. package/dist/keypairs-seeds/writeKeypairs.d.ts +11 -0
  19. package/dist/keypairs-seeds/writeKeypairs.js +75 -0
  20. package/dist/node-interaction/binaryEndpoints.d.ts +67 -10
  21. package/dist/node-interaction/binaryEndpoints.js +127 -53
  22. package/dist/node-interaction/jsonEndpoints.d.ts +249 -187
  23. package/dist/node-interaction/jsonEndpoints.js +287 -0
  24. package/dist/node-interaction/nodeUrl.d.ts +129 -0
  25. package/dist/node-interaction/nodeUrl.js +113 -0
  26. package/dist/scanning-syncing/backgroundWorker.d.ts +6 -0
  27. package/dist/scanning-syncing/backgroundWorker.js +56 -0
  28. package/dist/scanning-syncing/connectionStatus.d.ts +15 -0
  29. package/dist/scanning-syncing/connectionStatus.js +35 -0
  30. package/dist/scanning-syncing/openWallet.d.ts +28 -0
  31. package/dist/scanning-syncing/openWallet.js +57 -0
  32. package/dist/scanning-syncing/scanSettings.d.ts +96 -0
  33. package/dist/scanning-syncing/scanSettings.js +243 -0
  34. package/dist/scanning-syncing/scanresult/computeKeyImage.d.ts +3 -0
  35. package/dist/scanning-syncing/scanresult/computeKeyImage.js +21 -0
  36. package/dist/scanning-syncing/scanresult/getBlocksbinBuffer.d.ts +28 -0
  37. package/dist/scanning-syncing/scanresult/getBlocksbinBuffer.js +52 -0
  38. package/dist/scanning-syncing/scanresult/reorg.d.ts +14 -0
  39. package/dist/scanning-syncing/scanresult/reorg.js +78 -0
  40. package/dist/scanning-syncing/scanresult/scanCache.d.ts +84 -0
  41. package/dist/scanning-syncing/scanresult/scanCache.js +134 -0
  42. package/dist/scanning-syncing/scanresult/scanCacheOpened.d.ts +149 -0
  43. package/dist/scanning-syncing/scanresult/scanCacheOpened.js +648 -0
  44. package/dist/scanning-syncing/scanresult/scanResult.d.ts +64 -0
  45. package/dist/scanning-syncing/scanresult/scanResult.js +213 -0
  46. package/dist/scanning-syncing/scanresult/scanStats.d.ts +60 -0
  47. package/dist/scanning-syncing/scanresult/scanStats.js +273 -0
  48. package/dist/scanning-syncing/worker-entrypoints/worker.d.ts +1 -0
  49. package/dist/scanning-syncing/worker-entrypoints/worker.js +8 -0
  50. package/dist/scanning-syncing/worker-mains/worker.d.ts +1 -0
  51. package/dist/scanning-syncing/worker-mains/worker.js +7 -0
  52. package/dist/send-functionality/conversion.d.ts +4 -0
  53. package/dist/send-functionality/conversion.js +75 -0
  54. package/dist/send-functionality/inputSelection.d.ts +13 -0
  55. package/dist/send-functionality/inputSelection.js +8 -0
  56. package/dist/send-functionality/transactionBuilding.d.ts +51 -0
  57. package/dist/send-functionality/transactionBuilding.js +111 -0
  58. package/dist/tools/monero-tools.d.ts +46 -0
  59. package/dist/tools/monero-tools.js +165 -0
  60. package/dist/viewpair/ViewPair.d.ts +157 -0
  61. package/dist/viewpair/ViewPair.js +346 -0
  62. package/dist/wasm-processing/wasi.js +1 -2
  63. package/dist/wasm-processing/wasmFile.d.ts +1 -1
  64. package/dist/wasm-processing/wasmFile.js +2 -2
  65. package/dist/wasm-processing/wasmProcessor.d.ts +16 -4
  66. package/dist/wasm-processing/wasmProcessor.js +23 -7
  67. package/package.json +29 -6
package/README.md CHANGED
@@ -18,7 +18,19 @@ rust release build
18
18
 
19
19
  ```bash
20
20
  cd rust || cd ../rust
21
- cargo wasi build --target wasm32-wasip1 --release --lib
21
+ cargo build --target wasm32-wasip1 --release --lib
22
+ ```
23
+
24
+ prerequisite: install rust
25
+
26
+ ```bash
27
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
28
+ ```
29
+
30
+ ```bash
31
+ rustup install 1.89.0
32
+ rustup default 1.89.0
33
+ rustup target add wasm32-wasip1
22
34
  ```
23
35
 
24
36
  ## reproducible build with pinned cargo + rust + cargo wasi
package/dist/api.d.ts CHANGED
@@ -1,55 +1,27 @@
1
- import { type ScanResult, type ErrorResponse, type GetBlocksBinMetaCallback, type GetBlocksBinRequest } from "./node-interaction/binaryEndpoints";
2
- import { WasmProcessor } from "./wasm-processing/wasmProcessor";
1
+ import "./io/indexedDB";
2
+ export type { ScanResult, ScanResultCallback, } from "./scanning-syncing/scanresult/scanResult";
3
+ export type { CacheChangedCallback, CacheChangedCallbackParameters, } from "./scanning-syncing/scanresult/scanCache";
4
+ export { NodeUrl } from "./node-interaction/nodeUrl";
5
+ export { ViewPair } from "./viewpair/ViewPair";
6
+ export { ScanCacheOpened, ManyScanCachesOpened, } from "./scanning-syncing/scanresult/scanCacheOpened";
3
7
  export * from "./node-interaction/binaryEndpoints";
4
8
  export * from "./node-interaction/jsonEndpoints";
5
- export type ScanResultCallback = (result: ScanResult | ErrorResponse) => void;
6
- /**
7
- * This class is useful to interact with Moneros DaemonRpc binary requests in a convenient way.
8
- * (similar to how you would interact with a REST api that gives you json back.)
9
- * The wasm part will handle the creation of the binary requests and parse the responses and then parse them
10
- * and return outputs that belong to the ViewPair.
11
- * {@link https://docs.getmonero.org/rpc-library/monerod-rpc/#get_blocksbin}
12
- */
13
- export declare class ViewPair extends WasmProcessor {
14
- static create(primary_address: string, secret_view_key: string, node_url?: string): Promise<ViewPair>;
15
- /**
16
- * This request helps making requests to the get_blocks.bin endpoint of the Monerod nodes.
17
- * @link https://docs.getmonero.org/rpc-library/monerod-rpc/#get_blocksbin
18
- * @param params params that will be turned into epee (moner lib that does binary serialization)
19
- * @param metaCallBack contains meta information about the getBlocksbin call (new sync height = start_height param + number of blocks)
20
- * @returns The difference to the same method on NodeUrl is: It returns {@link ScanResult} (outputs that belong to viewpair) and not just the blocks as json.
21
- */
22
- getBlocksBin(params: GetBlocksBinRequest, metaCallBack?: GetBlocksBinMetaCallback): Promise<ScanResult | ErrorResponse>;
23
- /**
24
- * This method will use getBlocks.bin from start height to daemon height.
25
- * This is CPU bound work, so it should be executed in a seperate thread (worker).
26
- * The scanner.ts worker in the standard-checkout dir shows how to keep scanning after the tip is reached.
27
- * It also shows how the outputs are saved (note the unqiue requirement for the stealth_adress).
28
- * @param start_height the height to start syncing from.
29
- * @param callback this function will get the new outputs as they are found as a parameter
30
- */
31
- scan(start_height: number, callback: ScanResultCallback): Promise<void>;
32
- /**
33
- * This method makes an integrated Address for the Address of the Viewpair it was opened with.
34
- * The network (mainnet, stagenet, testnet) is the same as the one of the Viewpairaddress.
35
- * @param paymentId (u64 under the hood) you can use a random number or a primary key of an sqlite db to associate payments with customer sessions.
36
- * @returns Adressstring
37
- */
38
- makeIntegratedAddress(paymentId: number): string;
39
- }
40
- /**
41
- * This class is useful to interact with Moneros DaemonRpc binary requests in a convenient way.
42
- * (similar to how you would interact with a REST api that gives you json back.)
43
- * The wasm part will handle the creation of the binary requests and parse the responses and return them as json.
44
- * {@link https://docs.getmonero.org/rpc-library/monerod-rpc/#get_blocksbin}
45
- */
46
- export declare class NodeUrl extends WasmProcessor {
47
- static create(node_url?: string): Promise<NodeUrl>;
48
- /**
49
- * This request helps making requests to the get_blocks.bin endpoint of the Monerod nodes.
50
- * @link https://docs.getmonero.org/rpc-library/monerod-rpc/#get_blocksbin
51
- * @param params params that will be turned into epee (moner lib that does binary serialization)
52
- * @returns after the request is made it will return epee serialized objects that are then parsed into json.
53
- */
54
- getBlocksBin(params: GetBlocksBinRequest): Promise<import("./api").GetBlocksBinResponse | ErrorResponse>;
55
- }
9
+ export * from "./io/readDir";
10
+ export * from "./io/atomicWrite";
11
+ export * from "./io/sleep";
12
+ export { writeScanSettings, readScanSettings, } from "./scanning-syncing/scanSettings";
13
+ export { signTransaction, parseAddress, type ParsedAddress, type ParseAddressError, } from "./send-functionality/transactionBuilding";
14
+ export { computeKeyImage } from "./scanning-syncing/scanresult/computeKeyImage";
15
+ export { scanWallets, startWebworker, createWebworker, makeWebworkerScript, } from "./scanning-syncing/backgroundWorker";
16
+ export { spendable } from "./scanning-syncing/scanresult/scanResult";
17
+ export { openWallets, openWallet } from "./scanning-syncing/openWallet";
18
+ export * from "./scanning-syncing/connectionStatus";
19
+ export * from "./scanning-syncing/scanSettings";
20
+ export * from "./scanning-syncing/scanresult/scanResult";
21
+ export * from "./scanning-syncing/scanresult/scanStats";
22
+ export * from "./scanning-syncing/scanresult/scanCache";
23
+ export * from "./keypairs-seeds/writeKeypairs";
24
+ export * from "./keypairs-seeds/keypairs";
25
+ export * from "./send-functionality/conversion";
26
+ export * from "./send-functionality/inputSelection";
27
+ export * from "./tools/monero-tools";
package/dist/api.js CHANGED
@@ -1,103 +1,25 @@
1
- import { getBlocksBinJson, getBlocksBinScan, } from "./node-interaction/binaryEndpoints";
2
- import { TinyWASI } from "./wasm-processing/wasi";
3
- import { WasmProcessor } from "./wasm-processing/wasmProcessor";
1
+ import "./io/indexedDB";
2
+ export { NodeUrl } from "./node-interaction/nodeUrl";
3
+ export { ViewPair } from "./viewpair/ViewPair";
4
+ export { ScanCacheOpened, ManyScanCachesOpened, } from "./scanning-syncing/scanresult/scanCacheOpened";
4
5
  export * from "./node-interaction/binaryEndpoints";
5
6
  export * from "./node-interaction/jsonEndpoints";
6
- /**
7
- * This class is useful to interact with Moneros DaemonRpc binary requests in a convenient way.
8
- * (similar to how you would interact with a REST api that gives you json back.)
9
- * The wasm part will handle the creation of the binary requests and parse the responses and then parse them
10
- * and return outputs that belong to the ViewPair.
11
- * {@link https://docs.getmonero.org/rpc-library/monerod-rpc/#get_blocksbin}
12
- */
13
- export class ViewPair extends WasmProcessor {
14
- static async create(primary_address, secret_view_key, node_url) {
15
- const viewPair = new ViewPair(new TinyWASI(), node_url || "http://localhost:38081");
16
- const tinywasi = await viewPair.initWasmModule();
17
- viewPair.writeToWasmMemory = (ptr, len) => {
18
- viewPair.writeString(ptr, len, primary_address);
19
- viewPair.writeToWasmMemory = (ptr, len) => {
20
- viewPair.writeString(ptr, len, secret_view_key);
21
- };
22
- };
23
- //@ts-ignore
24
- tinywasi.instance.exports.init_viewpair(primary_address.length, secret_view_key.length);
25
- return viewPair;
26
- }
27
- /**
28
- * This request helps making requests to the get_blocks.bin endpoint of the Monerod nodes.
29
- * @link https://docs.getmonero.org/rpc-library/monerod-rpc/#get_blocksbin
30
- * @param params params that will be turned into epee (moner lib that does binary serialization)
31
- * @param metaCallBack contains meta information about the getBlocksbin call (new sync height = start_height param + number of blocks)
32
- * @returns The difference to the same method on NodeUrl is: It returns {@link ScanResult} (outputs that belong to viewpair) and not just the blocks as json.
33
- */
34
- getBlocksBin(params, metaCallBack) {
35
- return getBlocksBinScan(this, params, metaCallBack);
36
- }
37
- /**
38
- * This method will use getBlocks.bin from start height to daemon height.
39
- * This is CPU bound work, so it should be executed in a seperate thread (worker).
40
- * The scanner.ts worker in the standard-checkout dir shows how to keep scanning after the tip is reached.
41
- * It also shows how the outputs are saved (note the unqiue requirement for the stealth_adress).
42
- * @param start_height the height to start syncing from.
43
- * @param callback this function will get the new outputs as they are found as a parameter
44
- */
45
- async scan(start_height, callback) {
46
- let latest_meta = {
47
- new_height: start_height,
48
- daemon_height: start_height + 1,
49
- status: "",
50
- };
51
- while (latest_meta.new_height < latest_meta.daemon_height) {
52
- const res = await this.getBlocksBin({
53
- start_height: latest_meta.new_height - 1,
54
- }, (meta) => {
55
- latest_meta = meta;
56
- });
57
- callback(res);
58
- }
59
- }
60
- /**
61
- * This method makes an integrated Address for the Address of the Viewpair it was opened with.
62
- * The network (mainnet, stagenet, testnet) is the same as the one of the Viewpairaddress.
63
- * @param paymentId (u64 under the hood) you can use a random number or a primary key of an sqlite db to associate payments with customer sessions.
64
- * @returns Adressstring
65
- */
66
- makeIntegratedAddress(paymentId) {
67
- let address = "";
68
- this.readFromWasmMemory = (ptr, len) => {
69
- address = this.readString(ptr, len);
70
- };
71
- //@ts-ignore
72
- this.tinywasi.instance.exports.make_integrated_address(BigInt(paymentId));
73
- return address;
74
- }
75
- }
76
- /**
77
- * This class is useful to interact with Moneros DaemonRpc binary requests in a convenient way.
78
- * (similar to how you would interact with a REST api that gives you json back.)
79
- * The wasm part will handle the creation of the binary requests and parse the responses and return them as json.
80
- * {@link https://docs.getmonero.org/rpc-library/monerod-rpc/#get_blocksbin}
81
- */
82
- export class NodeUrl extends WasmProcessor {
83
- static async create(node_url) {
84
- const nodeUrl = new NodeUrl(new TinyWASI(), node_url || "http://localhost:38081");
85
- await nodeUrl.initWasmModule();
86
- return nodeUrl;
87
- }
88
- /**
89
- * This request helps making requests to the get_blocks.bin endpoint of the Monerod nodes.
90
- * @link https://docs.getmonero.org/rpc-library/monerod-rpc/#get_blocksbin
91
- * @param params params that will be turned into epee (moner lib that does binary serialization)
92
- * @returns after the request is made it will return epee serialized objects that are then parsed into json.
93
- */
94
- getBlocksBin(params) {
95
- return getBlocksBinJson(this, params);
96
- }
97
- }
98
- // const nodeurl = await NodeUrl.create("http://stagenet.community.rino.io:38081");
99
- // nodeurl.getBlocksBin({ start_height: 1731707 });
100
- // const viewpair = await ViewPair.create(
101
- // "5B5ieVKGSyfAyh68X6AFB48Gnx9diT8jPbWN6UcZHJUZVQSLRhaaHuHQz3dGuxxZDXPYgCXzrkerK3m6Q1tHoougR7VYyd9",
102
- // "10b9885324933ee6055b001a3ee4b70f6832b866db389ad023b51fe7e2e7ca01"
103
- // );
7
+ export * from "./io/readDir";
8
+ export * from "./io/atomicWrite";
9
+ export * from "./io/sleep";
10
+ export { writeScanSettings, readScanSettings, } from "./scanning-syncing/scanSettings";
11
+ export { signTransaction, parseAddress, } from "./send-functionality/transactionBuilding";
12
+ export { computeKeyImage } from "./scanning-syncing/scanresult/computeKeyImage";
13
+ export { scanWallets, startWebworker, createWebworker, makeWebworkerScript, } from "./scanning-syncing/backgroundWorker";
14
+ export { spendable } from "./scanning-syncing/scanresult/scanResult";
15
+ export { openWallets, openWallet } from "./scanning-syncing/openWallet";
16
+ export * from "./scanning-syncing/connectionStatus";
17
+ export * from "./scanning-syncing/scanSettings";
18
+ export * from "./scanning-syncing/scanresult/scanResult";
19
+ export * from "./scanning-syncing/scanresult/scanStats";
20
+ export * from "./scanning-syncing/scanresult/scanCache";
21
+ export * from "./keypairs-seeds/writeKeypairs";
22
+ export * from "./keypairs-seeds/keypairs";
23
+ export * from "./send-functionality/conversion";
24
+ export * from "./send-functionality/inputSelection";
25
+ export * from "./tools/monero-tools";
@@ -0,0 +1,32 @@
1
+ export interface Bun {
2
+ stdin: BunFile;
3
+ stdout: BunFile;
4
+ stderr: BunFile;
5
+ file(path: string | number | URL, options?: {
6
+ type?: string;
7
+ }): BunFile;
8
+ write(destination: string | number | BunFile | URL, input: string | Blob | ArrayBuffer | SharedArrayBuffer | TypedArray | Response): Promise<number>;
9
+ }
10
+ export interface BunFile {
11
+ readonly size: number;
12
+ readonly type: string;
13
+ text(): Promise<string>;
14
+ stream(): ReadableStream;
15
+ arrayBuffer(): Promise<ArrayBuffer>;
16
+ json(): Promise<any>;
17
+ writer(params: {
18
+ highWaterMark?: number;
19
+ }): FileSink;
20
+ exists(): Promise<boolean>;
21
+ }
22
+ export interface FileSink {
23
+ write(chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer): number | Promise<number>;
24
+ flush(): number | Promise<number>;
25
+ end(error?: Error): number | Promise<number>;
26
+ start(options?: {
27
+ highWaterMark?: number;
28
+ }): void;
29
+ ref(): void;
30
+ unref(): void;
31
+ }
32
+ export type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | Uint8ClampedArray;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { TypedArray } from "./BunFileInterface";
2
+ export declare function atomicWrite(targetPath: string, data: string | Blob | ArrayBuffer | SharedArrayBuffer | TypedArray | Response): Promise<number>;
@@ -0,0 +1,10 @@
1
+ export async function atomicWrite(targetPath, data) {
2
+ // in the browser we don't have rename + indexedDB writes are atomic in any case
3
+ if (areWeInTheBrowser)
4
+ return await Bun.write(targetPath, data);
5
+ const { rename } = await import("node:fs/promises");
6
+ const tempPath = targetPath + ".tmp";
7
+ const bytesWritten = await Bun.write(tempPath, data);
8
+ await rename(tempPath, targetPath);
9
+ return bytesWritten;
10
+ }
@@ -0,0 +1,18 @@
1
+ interface ExtensionRuntime {
2
+ id: string;
3
+ connect?: (extensionId?: string) => any;
4
+ sendMessage?: (message: any) => Promise<any> | ((callback: (response: any) => void) => void);
5
+ }
6
+ interface Chrome {
7
+ runtime?: ExtensionRuntime;
8
+ }
9
+ interface Browser {
10
+ runtime?: ExtensionRuntime;
11
+ }
12
+ declare global {
13
+ var chrome: Chrome | undefined;
14
+ var browser: Browser | undefined;
15
+ }
16
+ export declare function isExtensionContext(): boolean;
17
+ export declare function getRuntime(): ExtensionRuntime | null;
18
+ export {};
@@ -0,0 +1,11 @@
1
+ export function isExtensionContext() {
2
+ return !!((typeof chrome !== "undefined" && chrome.runtime?.id) ||
3
+ (typeof browser !== "undefined" && browser.runtime?.id));
4
+ }
5
+ export function getRuntime() {
6
+ if (chrome?.runtime?.id)
7
+ return chrome.runtime;
8
+ if (browser?.runtime?.id)
9
+ return browser.runtime;
10
+ return null;
11
+ }
@@ -0,0 +1,45 @@
1
+ import type { BunFile, Bun, TypedArray } from "./BunFileInterface";
2
+ export type PossibleBunFileContent = string | Blob | ArrayBuffer | SharedArrayBuffer | TypedArray | Response;
3
+ declare class IndexedDBBun implements Bun {
4
+ stdin: BunFile;
5
+ stdout: BunFile;
6
+ stderr: BunFile;
7
+ file(path: string | number | URL, options?: {
8
+ type?: string;
9
+ }): BunFile;
10
+ write(destination: string | number | BunFile | URL, input: PossibleBunFileContent): Promise<number>;
11
+ env: BunEnv;
12
+ }
13
+ export type BunEnv = {
14
+ [key: string]: string | undefined;
15
+ TZ?: string | undefined;
16
+ NODE_ENV?: string | undefined;
17
+ };
18
+ export type IndexedDBItem = string | Blob | ArrayBufferLike | ArrayBuffer | SharedArrayBuffer;
19
+ export declare function getItemLength(input: PossibleBunFileContent): Promise<[IndexedDBItem, number]>;
20
+ export declare function putFileIntoIndexedDB(path: string, content: PossibleBunFileContent): Promise<number>;
21
+ export declare function getFileFromIndexedDB(path: string): Promise<unknown>;
22
+ export declare function deleteFileFromIndexedDB(path: string): Promise<void>;
23
+ export declare const fileStoreName = "files";
24
+ export type BrowserGlobal = {
25
+ filesDb?: IDBDatabase;
26
+ Bun: IndexedDBBun;
27
+ areWeInTheBrowser: boolean;
28
+ };
29
+ declare global {
30
+ var areWeInTheBrowser: boolean;
31
+ }
32
+ export declare function refreshEnvIndexedDB(): Promise<void>;
33
+ export declare function writeEnvIndexedDB(key: string, value: string): Promise<void>;
34
+ export declare function readEnvIndexedDB(): Promise<{
35
+ [key: string]: string;
36
+ }>;
37
+ /**
38
+ * useless function
39
+ * you can just do process.env[key] instead. Look at the code above.
40
+ * @param key
41
+ * @returns value
42
+ */
43
+ export declare function readEnvIndexedDBLine(key: string): Promise<string>;
44
+ export declare function readdir(dirpath: string): Promise<string[]>;
45
+ export {};
@@ -0,0 +1,221 @@
1
+ import { writeEnvLineToDotEnvRefresh } from "../keypairs-seeds/writeKeypairs";
2
+ class IndexedDBBun {
3
+ stdin = new IndexedDBFile();
4
+ stdout = new IndexedDBFile();
5
+ stderr = new IndexedDBFile();
6
+ file(path, options) {
7
+ return new IndexedDBFile(getFileFromIndexedDB(path.toString()), path.toString());
8
+ }
9
+ async write(destination, input) {
10
+ return await putFileIntoIndexedDB(destination.toString(), input);
11
+ }
12
+ env = {};
13
+ }
14
+ class IndexedDBFile {
15
+ content;
16
+ path;
17
+ size = 0;
18
+ type = "";
19
+ constructor(content, path) {
20
+ this.content = content;
21
+ this.path = path;
22
+ }
23
+ async text() {
24
+ const result = (await this.content);
25
+ if (!result)
26
+ throw new Error(`no such file or directory, open '${this.path}'`);
27
+ return result;
28
+ }
29
+ stream() {
30
+ throw new Error("not implemented");
31
+ return new ReadableStream();
32
+ }
33
+ async arrayBuffer() {
34
+ const result = (await this.content);
35
+ if (!result)
36
+ throw new Error(`no such file or directory, open '${this.path}'`);
37
+ return result;
38
+ }
39
+ json() {
40
+ throw new Error("not implemented");
41
+ return Promise.resolve({});
42
+ }
43
+ writer(params) {
44
+ throw new Error("not implemented");
45
+ return new BunFileSink();
46
+ }
47
+ exists() {
48
+ throw new Error("not implemented");
49
+ return Promise.resolve(false);
50
+ }
51
+ delete() {
52
+ return deleteFileFromIndexedDB(this.path);
53
+ }
54
+ }
55
+ class BunFileSink {
56
+ write(chunk) {
57
+ throw new Error("not implemented");
58
+ return 0;
59
+ }
60
+ flush() {
61
+ throw new Error("not implemented");
62
+ return 0;
63
+ }
64
+ end(error) {
65
+ throw new Error("not implemented");
66
+ return 0;
67
+ }
68
+ start(options) {
69
+ throw new Error("not implemented");
70
+ }
71
+ ref() {
72
+ throw new Error("not implemented");
73
+ }
74
+ unref() {
75
+ throw new Error("not implemented");
76
+ }
77
+ }
78
+ export async function getItemLength(input) {
79
+ if (typeof input === "string") {
80
+ return [input, new TextEncoder().encode(input).length];
81
+ }
82
+ if (input instanceof Blob) {
83
+ return [input, input.size];
84
+ }
85
+ if (ArrayBuffer.isView(input)) {
86
+ return [input.buffer, input.byteLength];
87
+ }
88
+ if ("arrayBuffer" in input) {
89
+ const bytes = await input.arrayBuffer();
90
+ return [bytes, bytes.byteLength];
91
+ }
92
+ // SharedArrayBuffer/ArrayBuffer fallback
93
+ if ("byteLength" in input) {
94
+ return [input, input.byteLength];
95
+ }
96
+ throw new Error(`ENOSPC: unsupported input type`);
97
+ }
98
+ export async function putFileIntoIndexedDB(path, content) {
99
+ if (!browserGlobal.filesDb) {
100
+ throw new Error("IndexedDB not initialized");
101
+ }
102
+ const [dbContent, byteLength] = await getItemLength(content);
103
+ const tx = browserGlobal.filesDb.transaction(fileStoreName, "readwrite");
104
+ const store = tx.objectStore(fileStoreName);
105
+ const request = store.put(dbContent, path);
106
+ return await new Promise((resolve, reject) => {
107
+ request.onsuccess = () => resolve(byteLength);
108
+ request.onerror = () => reject(request.error);
109
+ });
110
+ }
111
+ export function getFileFromIndexedDB(path) {
112
+ if (!browserGlobal.filesDb) {
113
+ throw new Error("IndexedDB not initialized");
114
+ }
115
+ else {
116
+ const tx = browserGlobal.filesDb.transaction(fileStoreName, "readonly");
117
+ const store = tx.objectStore(fileStoreName);
118
+ const request = store.get(path);
119
+ return new Promise((resolve, reject) => {
120
+ request.onsuccess = () => resolve(request.result);
121
+ request.onerror = () => reject(request.error);
122
+ });
123
+ }
124
+ }
125
+ export async function deleteFileFromIndexedDB(path) {
126
+ if (!browserGlobal.filesDb) {
127
+ throw new Error("IndexedDB not initialized");
128
+ }
129
+ const tx = browserGlobal.filesDb.transaction(fileStoreName, "readwrite");
130
+ const store = tx.objectStore(fileStoreName);
131
+ const request = store.delete(path.trim());
132
+ return new Promise((resolve, reject) => {
133
+ request.onsuccess = () => resolve();
134
+ request.onerror = () => reject(request.error);
135
+ });
136
+ }
137
+ export const fileStoreName = "files";
138
+ async function initFilesDB() {
139
+ return new Promise((resolve, reject) => {
140
+ const request = indexedDB.open(fileStoreName);
141
+ request.onerror = () => reject(request.error);
142
+ request.onsuccess = () => resolve(request.result);
143
+ request.onupgradeneeded = () => request.result.createObjectStore(fileStoreName);
144
+ });
145
+ }
146
+ // In browsers: window in main thread, self in workers
147
+ const hasWindow = typeof window !== "undefined";
148
+ const hasSelf = typeof self !== "undefined";
149
+ //@ts-ignore
150
+ const browserGlobal = hasWindow ? window : hasSelf ? self : {}; // non-browser -> no shimming
151
+ if (typeof globalThis.Bun === "undefined") {
152
+ browserGlobal.filesDb = await initFilesDB();
153
+ browserGlobal.Bun = new IndexedDBBun();
154
+ browserGlobal.Bun.env = await readEnvIndexedDB();
155
+ browserGlobal.areWeInTheBrowser = true;
156
+ }
157
+ else {
158
+ browserGlobal.areWeInTheBrowser = false;
159
+ }
160
+ export async function refreshEnvIndexedDB() {
161
+ browserGlobal.Bun.env = await readEnvIndexedDB();
162
+ }
163
+ // we need this to change the env at runtime from inside the Browser extension,
164
+ // or react native app. Or to persist view keys in bun web backend.
165
+ // this one is specifically for indexedDB (convention of treating .env as Bun.env)
166
+ export async function writeEnvIndexedDB(key, value) {
167
+ // this file should be treated as ephemeral
168
+ // private spendkeys + viewkeys are deterministically derived from seedphrase and password
169
+ // we have to go through indexedDB just so the background worker has access to this.
170
+ // (after waking up from an alarm or onmessage event)
171
+ await writeEnvLineToDotEnvRefresh(key, value, ".env");
172
+ }
173
+ export async function readEnvIndexedDB() {
174
+ const file = Bun.file(".env");
175
+ const content = await file
176
+ .text()
177
+ .catch(() => { })
178
+ .then((c) => c || "");
179
+ const lines = content.split("\n");
180
+ const result = {};
181
+ for (const line of lines) {
182
+ const keyValue = line.split("=");
183
+ const key = keyValue[0];
184
+ if (!key)
185
+ continue;
186
+ const value = keyValue[1];
187
+ result[key.trim()] = value?.trim();
188
+ }
189
+ return result;
190
+ }
191
+ /**
192
+ * useless function
193
+ * you can just do process.env[key] instead. Look at the code above.
194
+ * @param key
195
+ * @returns value
196
+ */
197
+ export async function readEnvIndexedDBLine(key) {
198
+ const file = Bun.file(".env");
199
+ const content = await file.text();
200
+ const lines = content.split("\n");
201
+ const idx = lines.findIndex((line) => line.startsWith(key.trim()));
202
+ return lines[idx].split("=")[1].trim();
203
+ }
204
+ export async function readdir(dirpath) {
205
+ if (!browserGlobal.filesDb) {
206
+ throw new Error("IndexedDB not initialized");
207
+ }
208
+ let prefix = dirpath.trim();
209
+ if (prefix && !prefix.endsWith("/")) {
210
+ prefix += "/";
211
+ }
212
+ const tx = browserGlobal.filesDb.transaction(fileStoreName, "readonly");
213
+ const store = tx.objectStore(fileStoreName);
214
+ const range = IDBKeyRange.bound(prefix, prefix + "\uffff", false, true);
215
+ const keys = await new Promise((resolve, reject) => {
216
+ const request = store.getAllKeys(range);
217
+ request.onsuccess = () => resolve(request.result);
218
+ request.onerror = () => reject(request.error);
219
+ });
220
+ return keys.map((key) => key.slice(prefix.length));
221
+ }
@@ -0,0 +1 @@
1
+ export declare function readDir(path: string): Promise<string[]>;
@@ -0,0 +1,7 @@
1
+ import { readdir as indexedDBreaddir } from "./indexedDB";
2
+ export async function readDir(path) {
3
+ if (areWeInTheBrowser)
4
+ return await indexedDBreaddir(path);
5
+ const { readdir } = await import("node:fs/promises");
6
+ return await readdir(path);
7
+ }
@@ -0,0 +1 @@
1
+ export declare const sleep: (ms: number) => Promise<unknown>;
@@ -0,0 +1 @@
1
+ export const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -0,0 +1,29 @@
1
+ /**
2
+ * "So when we first decided to create a mnemonic system the spec we
3
+ * came up with was: take the seed from the mnemonic, hash it for the
4
+ * spend key, hash it twice for the view key. Somewhere during the
5
+ * simplewallet implementation we forgot about that, and just used the
6
+ * mnemonic seed as the spendkey directly.
7
+ *
8
+ * This proved to be a blessing in disguise, though, as we'd not realised
9
+ * that people might want to retrieve their seed. Using our original
10
+ * design this wouldn't have been possible, as we didn't store the seed
11
+ * in the wallet file.
12
+ *
13
+ * Much later on when we were creating MyMonero (a different group of
14
+ * developers, I'm the only common link between the two) we decided that
15
+ * a 13 word seed would be much easier for people to remember, but
16
+ * because we wanted it to match simplewallet's implementation we made
17
+ * sure that we followed the spec... as it was originally... before we
18
+ * duffed the implementation."
19
+ */
20
+ export type SpendKey = string;
21
+ export declare function makeSpendKey(): Promise<SpendKey>;
22
+ export declare function makeSpendKeyFromSeed(wallet_secret: string): Promise<SpendKey>;
23
+ export type ViewPairJson = {
24
+ view_key: string;
25
+ mainnet_primary: string;
26
+ stagenet_primary: string;
27
+ testnet_primary: string;
28
+ };
29
+ export declare function makeViewKey(spend_private_key: string): Promise<ViewPairJson>;