sliftutils 1.4.2 → 1.4.4

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.
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ require("typenode");
4
+ require("../storage/remoteFileServer").runFileHoster();
package/index.d.ts CHANGED
@@ -849,8 +849,29 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabase2" {
849
849
  getColumnInfo(): Promise<BulkColumnInfo[]>;
850
850
  /** A cheap snapshot of the collection's shape (row/key counts, total bytes, columns) — no row data. */
851
851
  getReaderInfo(): Promise<BulkReaderInfo>;
852
+ /**
853
+ * Per-file breakdown of the on-disk files, read fresh from disk each call (latest sizes, including
854
+ * stream files still being appended). `bytes` is the actual on-disk size. Good for showing collection
855
+ * size/fragmentation and deciding whether to call tryMergeNow()/compact().
856
+ */
857
+ getFileInfo(): Promise<{
858
+ files: {
859
+ name: string;
860
+ type: "bulk" | "stream";
861
+ bytes: number;
862
+ }[];
863
+ count: number;
864
+ totalBytes: number;
865
+ }>;
852
866
  /** Consolidate on-disk files. Optional to call; the database also does this in the background. */
853
867
  compact(): Promise<void>;
868
+ /**
869
+ * Flush buffered stream writes to disk now. Writes are coalesced and flushed on a ramping delay (to
870
+ * avoid the browser rewriting the whole stream file per write), so a write's promise resolving means
871
+ * "accepted" (in memory + cross-tab), not necessarily "on disk". Call this to force durability — it's
872
+ * also run automatically on tab hide/close and before every merge.
873
+ */
874
+ flush(): Promise<void>;
854
875
  /**
855
876
  * Run one merge pass now (the same policy the database runs on a timer): consolidate recent
856
877
  * fragmentation and dedup a key range if it's worth it. Returns whether it merged anything and
@@ -878,8 +899,10 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseBase" {
878
899
  export declare const bulkDatabase2Timing: {
879
900
  streamSealAgeMs: number;
880
901
  mergeCheckIntervalMs: number;
902
+ mergeSpacingMs: number;
881
903
  firstMergeTriggerFiles: number;
882
904
  firstMergeTriggerRangeMs: number;
905
+ writeFlushMaxDelayMs: number;
883
906
  };
884
907
  export interface ReactiveDeps {
885
908
  observe(signal: string): void;
@@ -895,6 +918,11 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseBase" {
895
918
  protected deps: ReactiveDeps;
896
919
  private storageFactory;
897
920
  constructor(name: string, deps: ReactiveDeps, storageFactory: StorageFactory);
921
+ private pendingAppends;
922
+ private flushTimer;
923
+ private flushChain;
924
+ private currentFlushDelay;
925
+ private lastWriteTime;
898
926
  static clearCache(): void;
899
927
  storage: {
900
928
  (): Promise<FileStorage>;
@@ -919,6 +947,10 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseBase" {
919
947
  writeBatch(entries: T[]): Promise<void>;
920
948
  delete(key: string): Promise<void>;
921
949
  deleteBatch(keys: string[]): Promise<void>;
950
+ private streamAppend;
951
+ flush(): Promise<void>;
952
+ private flushPending;
953
+ private doFlush;
922
954
  update(entry: Partial<T> & {
923
955
  key: string;
924
956
  }): Promise<void>;
@@ -944,7 +976,9 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseBase" {
944
976
  private resolveReaders;
945
977
  private mergeFileSet;
946
978
  private canDeleteStream;
979
+ private mergeSpacingDelay;
947
980
  private testMerge;
981
+ private findDuplicateGroups;
948
982
  private formatInfo;
949
983
  private patchColumn;
950
984
  getSingleField<Column extends keyof T>(key: string, column: Column): Promise<T[Column] | undefined>;
@@ -990,6 +1024,15 @@ declare module "sliftutils/storage/BulkDatabase2/BulkDatabaseBase" {
990
1024
  byteSize: number;
991
1025
  }[];
992
1026
  }>;
1027
+ getFileInfo(): Promise<{
1028
+ files: {
1029
+ name: string;
1030
+ type: "bulk" | "stream";
1031
+ bytes: number;
1032
+ }[];
1033
+ count: number;
1034
+ totalBytes: number;
1035
+ }>;
993
1036
  }
994
1037
 
995
1038
  }
@@ -1797,6 +1840,68 @@ declare module "sliftutils/storage/fileSystemPointer" {
1797
1840
 
1798
1841
  }
1799
1842
 
1843
+ declare module "sliftutils/storage/remoteFileServer" {
1844
+ export declare function generatePassword(wordCount: number): string;
1845
+ export type RemoteFileServerOptions = {
1846
+ root: string;
1847
+ port?: number;
1848
+ host?: string;
1849
+ password?: string;
1850
+ logAccess?: boolean;
1851
+ };
1852
+ export type RemoteFileServerHandle = {
1853
+ port: number;
1854
+ password: string;
1855
+ url: string;
1856
+ close: () => Promise<void>;
1857
+ };
1858
+ export declare function startRemoteFileServer(options: RemoteFileServerOptions): Promise<RemoteFileServerHandle>;
1859
+ export declare function runFileHoster(): Promise<void>;
1860
+
1861
+ }
1862
+
1863
+ declare module "sliftutils/storage/remoteFileStorage" {
1864
+ /// <reference types="node" />
1865
+ /// <reference types="node" />
1866
+ /// <reference types="node" />
1867
+ import https from "https";
1868
+ import type { FileStorage } from "./FileFolderAPI";
1869
+ export type RemoteFileStorageOptions = {
1870
+ chunkBytes?: number;
1871
+ cacheBytes?: number;
1872
+ latencyMs?: number;
1873
+ };
1874
+ type Connection = {
1875
+ url: string;
1876
+ password: string;
1877
+ latencyMs: number;
1878
+ agent: https.Agent | undefined;
1879
+ cache: RangeCache;
1880
+ stats: {
1881
+ requestCount: number;
1882
+ bytesFetched: number;
1883
+ };
1884
+ };
1885
+ declare class RangeCache {
1886
+ private chunkBytes;
1887
+ private budget;
1888
+ private chunks;
1889
+ private bytes;
1890
+ constructor(chunkBytes: number, budget: number);
1891
+ private key;
1892
+ private peek;
1893
+ private store;
1894
+ invalidate(path: string): void;
1895
+ getRange(conn: Connection, path: string, start: number, end: number): Promise<Buffer | undefined>;
1896
+ }
1897
+ export type RemoteStorageFactory = ((path: string) => Promise<FileStorage>) & {
1898
+ stats: Connection["stats"];
1899
+ };
1900
+ export declare function getRemoteFileStorage(url: string, password: string, options?: RemoteFileStorageOptions): RemoteStorageFactory;
1901
+ export {};
1902
+
1903
+ }
1904
+
1800
1905
  declare module "sliftutils/storage/storage" {
1801
1906
 
1802
1907
 
package/package.json CHANGED
@@ -1,70 +1,72 @@
1
- {
2
- "name": "sliftutils",
3
- "version": "1.4.2",
4
- "main": "index.js",
5
- "license": "MIT",
6
- "files": [
7
- "**/*",
8
- ".gitignore"
9
- ],
10
- "scripts": {
11
- "type": "yarn tsc --noEmit",
12
- "emit-dts": "yarn tsc --project tsconfig.declarations.json || true",
13
- "generate-index-dts": "typenode ./builders/generateIndexDts.ts",
14
- "update-types": "yarn emit-dts && yarn generate-index-dts",
15
- "prepublishOnly": "yarn update-types",
16
- "run-nodejs": "node ./build-nodejs/server.js",
17
- "run-nodejs-dev": "typenode ./nodejs/server.ts --npminstall",
18
- "run-web": "node ./builders/webRun.js",
19
- "run-electron": "node ./node_modules/electron/cli.js ./build-electron/electronMain.js",
20
- "build-nodejs": "node ./builders/nodeJSBuildRun.js",
21
- "build-web": "node ./builders/webBuildRun.js",
22
- "build-extension": "node ./builders/extensionBuildRun.js",
23
- "build-electron": "node ./builders/electronBuildRun.js",
24
- "watch-nodejs": "node ./builders/watchRun.js --port 9876 \"nodejs/*.ts\" \"nodejs/*.tsx\" \"yarn build-nodejs\"",
25
- "watch-web": "node ./builders/watchRun.js --port 9877 \"web/*.ts\" \"web/*.tsx\" \"yarn build-web\"",
26
- "watch-extension": "node ./builders/watchRun.js --port 9878 \"extension/*.ts\" \"extension/*.tsx\" \"yarn build-extension\"",
27
- "watch-electron": "node ./builders/watchRun.js --port 9879 \"electron/*.ts\" \"electron/*.tsx\" \"yarn build-electron\"",
28
- "notes": "mobx, preact, socket-function, typenode SHOULD be peerDependencies. But we want to use yarn (better dependency deduplication), so we can't use peerDependencies (as they aren't installed by default, which makes them a nightmare to use). If you want to override the versions, feel free to use overrides/resolutions.",
29
- "test": "typenode ./test.ts"
30
- },
31
- "bin": {
32
- "build-nodejs": "./builders/nodeJSBuildRun.js",
33
- "buildnodejs": "./builders/nodeJSBuildRun.js",
34
- "build-extension": "./builders/extensionBuildRun.js",
35
- "buildextension": "./builders/extensionBuildRun.js",
36
- "build-web": "./builders/webBuildRun.js",
37
- "buildweb": "./builders/webBuildRun.js",
38
- "build-electron": "./builders/electronBuildRun.js",
39
- "buildelectron": "./builders/electronBuildRun.js",
40
- "slift-watch": "./builders/watchRun.js",
41
- "sliftwatch": "./builders/watchRun.js",
42
- "slift-setup": "./builders/setupRun.js",
43
- "sliftsetup": "./builders/setupRun.js"
44
- },
45
- "dependencies": {
46
- "@types/chrome": "^0.0.237",
47
- "@types/node-forge": "^1.3.11",
48
- "@types/shell-quote": "^1.7.5",
49
- "acme-client": "^5.0.0",
50
- "js-sha256": "^0.11.1",
51
- "mobx": "^6.13.3",
52
- "preact-old-types": "^10.28.1",
53
- "shell-quote": "^1.8.3",
54
- "socket-function": "^1.1.42",
55
- "typenode": "*",
56
- "typesafecss": "*",
57
- "ws": "^8.18.3",
58
- "yargs": "15.4.1"
59
- },
60
- "resolutions": {
61
- "preact": "npm:preact-old-types@*"
62
- },
63
- "devDependencies": {
64
- "@types/yargs": "15.0.19",
65
- "debugbreak": "^0.9.9",
66
- "electron": "^33.2.1",
67
- "open": "^8.4.0",
68
- "typedev": "^0.1.1"
69
- }
70
- }
1
+ {
2
+ "name": "sliftutils",
3
+ "version": "1.4.4",
4
+ "main": "index.js",
5
+ "license": "MIT",
6
+ "files": [
7
+ "**/*",
8
+ ".gitignore"
9
+ ],
10
+ "scripts": {
11
+ "type": "yarn tsc --noEmit",
12
+ "emit-dts": "yarn tsc --project tsconfig.declarations.json || true",
13
+ "generate-index-dts": "typenode ./builders/generateIndexDts.ts",
14
+ "update-types": "yarn emit-dts && yarn generate-index-dts",
15
+ "prepublishOnly": "yarn update-types",
16
+ "run-nodejs": "node ./build-nodejs/server.js",
17
+ "run-nodejs-dev": "typenode ./nodejs/server.ts --npminstall",
18
+ "run-web": "node ./builders/webRun.js",
19
+ "run-electron": "node ./node_modules/electron/cli.js ./build-electron/electronMain.js",
20
+ "build-nodejs": "node ./builders/nodeJSBuildRun.js",
21
+ "build-web": "node ./builders/webBuildRun.js",
22
+ "build-extension": "node ./builders/extensionBuildRun.js",
23
+ "build-electron": "node ./builders/electronBuildRun.js",
24
+ "watch-nodejs": "node ./builders/watchRun.js --port 9876 \"nodejs/*.ts\" \"nodejs/*.tsx\" \"yarn build-nodejs\"",
25
+ "watch-web": "node ./builders/watchRun.js --port 9877 \"web/*.ts\" \"web/*.tsx\" \"yarn build-web\"",
26
+ "watch-extension": "node ./builders/watchRun.js --port 9878 \"extension/*.ts\" \"extension/*.tsx\" \"yarn build-extension\"",
27
+ "watch-electron": "node ./builders/watchRun.js --port 9879 \"electron/*.ts\" \"electron/*.tsx\" \"yarn build-electron\"",
28
+ "notes": "mobx, preact, socket-function, typenode SHOULD be peerDependencies. But we want to use yarn (better dependency deduplication), so we can't use peerDependencies (as they aren't installed by default, which makes them a nightmare to use). If you want to override the versions, feel free to use overrides/resolutions.",
29
+ "test": "typenode ./test.ts",
30
+ "filehoster": "node ./bin/filehoster.js"
31
+ },
32
+ "bin": {
33
+ "filehoster": "./bin/filehoster.js",
34
+ "build-nodejs": "./builders/nodeJSBuildRun.js",
35
+ "buildnodejs": "./builders/nodeJSBuildRun.js",
36
+ "build-extension": "./builders/extensionBuildRun.js",
37
+ "buildextension": "./builders/extensionBuildRun.js",
38
+ "build-web": "./builders/webBuildRun.js",
39
+ "buildweb": "./builders/webBuildRun.js",
40
+ "build-electron": "./builders/electronBuildRun.js",
41
+ "buildelectron": "./builders/electronBuildRun.js",
42
+ "slift-watch": "./builders/watchRun.js",
43
+ "sliftwatch": "./builders/watchRun.js",
44
+ "slift-setup": "./builders/setupRun.js",
45
+ "sliftsetup": "./builders/setupRun.js"
46
+ },
47
+ "dependencies": {
48
+ "@types/chrome": "^0.0.237",
49
+ "@types/node-forge": "^1.3.11",
50
+ "@types/shell-quote": "^1.7.5",
51
+ "acme-client": "^5.0.0",
52
+ "js-sha256": "^0.11.1",
53
+ "mobx": "^6.13.3",
54
+ "preact-old-types": "^10.28.1",
55
+ "shell-quote": "^1.8.3",
56
+ "socket-function": "^1.1.42",
57
+ "typenode": "*",
58
+ "typesafecss": "*",
59
+ "ws": "^8.18.3",
60
+ "yargs": "15.4.1"
61
+ },
62
+ "resolutions": {
63
+ "preact": "npm:preact-old-types@*"
64
+ },
65
+ "devDependencies": {
66
+ "@types/yargs": "15.0.19",
67
+ "debugbreak": "^0.9.9",
68
+ "electron": "^33.2.1",
69
+ "open": "^8.4.0",
70
+ "typedev": "^0.1.1"
71
+ }
72
+ }
@@ -48,7 +48,11 @@ export class FullscreenModal extends preact.Component<{
48
48
  cursor: "pointer",
49
49
  ...this.props.outerStyle,
50
50
  }}
51
- onClick={e => {
51
+ // Close on mouse DOWN on the backdrop, not click — otherwise a drag that starts
52
+ // inside the modal (e.g. selecting text) and releases out on the backdrop fires a
53
+ // click on the backdrop and wrongly closes it. currentTarget === target means the
54
+ // press began on the backdrop itself, not bubbled up from the modal content.
55
+ onMouseDown={e => {
52
56
  if (e.currentTarget === e.target) {
53
57
  if (parentState) parentState.open = false;
54
58
  this.props.onCancel?.();
@@ -84,8 +84,29 @@ export interface IBulkDatabase2<T extends {
84
84
  getColumnInfo(): Promise<BulkColumnInfo[]>;
85
85
  /** A cheap snapshot of the collection's shape (row/key counts, total bytes, columns) — no row data. */
86
86
  getReaderInfo(): Promise<BulkReaderInfo>;
87
+ /**
88
+ * Per-file breakdown of the on-disk files, read fresh from disk each call (latest sizes, including
89
+ * stream files still being appended). `bytes` is the actual on-disk size. Good for showing collection
90
+ * size/fragmentation and deciding whether to call tryMergeNow()/compact().
91
+ */
92
+ getFileInfo(): Promise<{
93
+ files: {
94
+ name: string;
95
+ type: "bulk" | "stream";
96
+ bytes: number;
97
+ }[];
98
+ count: number;
99
+ totalBytes: number;
100
+ }>;
87
101
  /** Consolidate on-disk files. Optional to call; the database also does this in the background. */
88
102
  compact(): Promise<void>;
103
+ /**
104
+ * Flush buffered stream writes to disk now. Writes are coalesced and flushed on a ramping delay (to
105
+ * avoid the browser rewriting the whole stream file per write), so a write's promise resolving means
106
+ * "accepted" (in memory + cross-tab), not necessarily "on disk". Call this to force durability — it's
107
+ * also run automatically on tab hide/close and before every merge.
108
+ */
109
+ flush(): Promise<void>;
89
110
  /**
90
111
  * Run one merge pass now (the same policy the database runs on a timer): consolidate recent
91
112
  * fragmentation and dedup a key range if it's worth it. Returns whether it merged anything and
@@ -69,10 +69,24 @@ export interface IBulkDatabase2<T extends { key: string }> {
69
69
  getColumnInfo(): Promise<BulkColumnInfo[]>;
70
70
  /** A cheap snapshot of the collection's shape (row/key counts, total bytes, columns) — no row data. */
71
71
  getReaderInfo(): Promise<BulkReaderInfo>;
72
+ /**
73
+ * Per-file breakdown of the on-disk files, read fresh from disk each call (latest sizes, including
74
+ * stream files still being appended). `bytes` is the actual on-disk size. Good for showing collection
75
+ * size/fragmentation and deciding whether to call tryMergeNow()/compact().
76
+ */
77
+ getFileInfo(): Promise<{ files: { name: string; type: "bulk" | "stream"; bytes: number }[]; count: number; totalBytes: number }>;
72
78
 
73
79
  /** Consolidate on-disk files. Optional to call; the database also does this in the background. */
74
80
  compact(): Promise<void>;
75
81
 
82
+ /**
83
+ * Flush buffered stream writes to disk now. Writes are coalesced and flushed on a ramping delay (to
84
+ * avoid the browser rewriting the whole stream file per write), so a write's promise resolving means
85
+ * "accepted" (in memory + cross-tab), not necessarily "on disk". Call this to force durability — it's
86
+ * also run automatically on tab hide/close and before every merge.
87
+ */
88
+ flush(): Promise<void>;
89
+
76
90
  /**
77
91
  * Run one merge pass now (the same policy the database runs on a timer): consolidate recent
78
92
  * fragmentation and dedup a key range if it's worth it. Returns whether it merged anything and
@@ -2,8 +2,10 @@ import type { FileStorage } from "../FileFolderAPI";
2
2
  export declare const bulkDatabase2Timing: {
3
3
  streamSealAgeMs: number;
4
4
  mergeCheckIntervalMs: number;
5
+ mergeSpacingMs: number;
5
6
  firstMergeTriggerFiles: number;
6
7
  firstMergeTriggerRangeMs: number;
8
+ writeFlushMaxDelayMs: number;
7
9
  };
8
10
  export interface ReactiveDeps {
9
11
  observe(signal: string): void;
@@ -19,6 +21,11 @@ export declare class BulkDatabaseBase<T extends {
19
21
  protected deps: ReactiveDeps;
20
22
  private storageFactory;
21
23
  constructor(name: string, deps: ReactiveDeps, storageFactory: StorageFactory);
24
+ private pendingAppends;
25
+ private flushTimer;
26
+ private flushChain;
27
+ private currentFlushDelay;
28
+ private lastWriteTime;
22
29
  static clearCache(): void;
23
30
  storage: {
24
31
  (): Promise<FileStorage>;
@@ -43,6 +50,10 @@ export declare class BulkDatabaseBase<T extends {
43
50
  writeBatch(entries: T[]): Promise<void>;
44
51
  delete(key: string): Promise<void>;
45
52
  deleteBatch(keys: string[]): Promise<void>;
53
+ private streamAppend;
54
+ flush(): Promise<void>;
55
+ private flushPending;
56
+ private doFlush;
46
57
  update(entry: Partial<T> & {
47
58
  key: string;
48
59
  }): Promise<void>;
@@ -68,7 +79,9 @@ export declare class BulkDatabaseBase<T extends {
68
79
  private resolveReaders;
69
80
  private mergeFileSet;
70
81
  private canDeleteStream;
82
+ private mergeSpacingDelay;
71
83
  private testMerge;
84
+ private findDuplicateGroups;
72
85
  private formatInfo;
73
86
  private patchColumn;
74
87
  getSingleField<Column extends keyof T>(key: string, column: Column): Promise<T[Column] | undefined>;
@@ -114,4 +127,13 @@ export declare class BulkDatabaseBase<T extends {
114
127
  byteSize: number;
115
128
  }[];
116
129
  }>;
130
+ getFileInfo(): Promise<{
131
+ files: {
132
+ name: string;
133
+ type: "bulk" | "stream";
134
+ bytes: number;
135
+ }[];
136
+ count: number;
137
+ totalBytes: number;
138
+ }>;
117
139
  }