sliftutils 0.1.1

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 (47) hide show
  1. package/.cursorrules +161 -0
  2. package/.eslintrc.js +38 -0
  3. package/.vscode/settings.json +39 -0
  4. package/bundler/buffer.js +2370 -0
  5. package/bundler/bundleEntry.ts +32 -0
  6. package/bundler/bundleEntryCaller.ts +8 -0
  7. package/bundler/bundleRequire.ts +244 -0
  8. package/bundler/bundleWrapper.ts +115 -0
  9. package/bundler/bundler.ts +72 -0
  10. package/bundler/flattenSourceMaps.ts +0 -0
  11. package/bundler/sourceMaps.ts +261 -0
  12. package/misc/environment.ts +11 -0
  13. package/misc/types.ts +3 -0
  14. package/misc/zip.ts +37 -0
  15. package/package.json +24 -0
  16. package/spec.txt +33 -0
  17. package/storage/CachedStorage.ts +32 -0
  18. package/storage/DelayedStorage.ts +30 -0
  19. package/storage/DiskCollection.ts +272 -0
  20. package/storage/FileFolderAPI.tsx +427 -0
  21. package/storage/IStorage.ts +40 -0
  22. package/storage/IndexedDBFileFolderAPI.ts +170 -0
  23. package/storage/JSONStorage.ts +35 -0
  24. package/storage/PendingManager.tsx +63 -0
  25. package/storage/PendingStorage.ts +47 -0
  26. package/storage/PrivateFileSystemStorage.ts +192 -0
  27. package/storage/StorageObservable.ts +122 -0
  28. package/storage/TransactionStorage.ts +485 -0
  29. package/storage/fileSystemPointer.ts +81 -0
  30. package/storage/storage.d.ts +41 -0
  31. package/tsconfig.json +31 -0
  32. package/web/DropdownCustom.tsx +150 -0
  33. package/web/FullscreenModal.tsx +75 -0
  34. package/web/GenericFormat.tsx +186 -0
  35. package/web/Input.tsx +350 -0
  36. package/web/InputLabel.tsx +288 -0
  37. package/web/InputPicker.tsx +158 -0
  38. package/web/LocalStorageParam.ts +56 -0
  39. package/web/SyncedController.ts +405 -0
  40. package/web/SyncedLoadingIndicator.tsx +37 -0
  41. package/web/Table.tsx +188 -0
  42. package/web/URLParam.ts +84 -0
  43. package/web/asyncObservable.ts +40 -0
  44. package/web/colors.tsx +14 -0
  45. package/web/mobxTyped.ts +29 -0
  46. package/web/modal.tsx +18 -0
  47. package/web/observer.tsx +35 -0
@@ -0,0 +1,32 @@
1
+ import path from "path";
2
+ import { bundle } from "./bundler";
3
+ import fs from "fs";
4
+
5
+ function getCommandLineArg(name: string) {
6
+ let index = process.argv.indexOf(name);
7
+ if (index === -1) return null;
8
+ return process.argv[index + 1];
9
+ }
10
+ async function main() {
11
+ let entryPoint = getCommandLineArg("--entryPoint");
12
+ if (!entryPoint) {
13
+ throw new Error("No entry point provided");
14
+ }
15
+ require("../" + entryPoint);
16
+
17
+ let name = path.basename(entryPoint);
18
+ if (name.endsWith(".ts") || name.endsWith(".tsx")) {
19
+ name = name.split(".").slice(0, -1).join(".");
20
+ }
21
+ name += ".js";
22
+
23
+ let modules = Object.values(require.cache).filter(x => x?.id !== module.id);
24
+
25
+ let bundled = await bundle({
26
+ modules,
27
+ rootPath: path.resolve("."),
28
+ entryPoints: [entryPoint],
29
+ });
30
+ await fs.promises.writeFile(`./build-extension/${name}`, bundled.bundle);
31
+ }
32
+ main().catch(console.error).finally(() => process.exit());
@@ -0,0 +1,8 @@
1
+ import child_process from "child_process";
2
+ import { runPromise } from "socket-function/src/runPromise";
3
+
4
+
5
+ export async function bundleEntryCaller(entryPoint: string, args = "") {
6
+ let command = "yarn typenode ./bundler/bundleEntry.ts --entryPoint " + entryPoint + " " + args;
7
+ await runPromise(command);
8
+ }
@@ -0,0 +1,244 @@
1
+ import { SerializedModule } from "./bundleWrapper";
2
+
3
+ // Sets globalThis.require = ..., utilizing registeredModules (from bundleWrapper.ts) when require is called
4
+ export interface BundleRequireConfig {
5
+ rootPath: string;
6
+ }
7
+ export function bundleRequire(config: BundleRequireConfig) {
8
+ globalThis.process = globalThis.process || {
9
+ env: {
10
+ NODE_ENV: "production",
11
+ },
12
+ versions: {},
13
+ on: () => { },
14
+ };
15
+ (globalThis as any).window = (globalThis as any).window || globalThis;
16
+ (globalThis as any).global = (globalThis as any).global || globalThis;
17
+ (globalThis as any).setImmediate = (globalThis as any).setImmediate || globalThis.setTimeout;
18
+
19
+ // Set document, so isNode checks return false.
20
+ (globalThis as any).document = (globalThis as any).document || {};
21
+ (globalThis as any).BOOTED_EDGE_NODE = undefined;
22
+
23
+ const builtInModuleExports = {
24
+ worker_threads: {
25
+ isMainThread: true,
26
+ },
27
+ util: {
28
+ // https://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor
29
+ inherits(constructor: any, superConstructor: any) {
30
+ Object.setPrototypeOf(constructor.prototype, superConstructor.prototype);
31
+ },
32
+ TextDecoder: TextDecoder,
33
+ TextEncoder: TextEncoder,
34
+ },
35
+ buffer: { Buffer },
36
+ stream: {
37
+ // HACK: Needed to get SAX JS to work correctly.
38
+ Stream: function () { },
39
+ Transform: function () { },
40
+
41
+ Writable: function () { },
42
+ },
43
+ timers: {
44
+ // TODO: Add all members of timers
45
+ setImmediate: globalThis.setImmediate,
46
+ },
47
+ child_process: {},
48
+ events: class EventEmitter { },
49
+ };
50
+
51
+ // Just path.resolve (but needs to be reimplemented, because we can't use imports)
52
+ function pathResolve(...paths: string[]): string {
53
+ // Start with empty path segments array
54
+ let segments: string[] = [];
55
+ let isWindowsPath = false;
56
+
57
+ paths = paths.map(x => x.replace(/\\/g, "/"));
58
+
59
+ // Process each path argument
60
+ for (const path of paths) {
61
+ // Check for Windows drive letter (e.g., C:/)
62
+ if (/^[A-Za-z]:/.test(path)) {
63
+ isWindowsPath = true;
64
+ // Remove drive letter for processing
65
+ const withoutDrive = path.slice(2);
66
+ if (withoutDrive.startsWith("/")) {
67
+ segments = [path.slice(0, 2)]; // Keep drive letter and reset segments
68
+ } else {
69
+ // If no leading slash, keep current segments (relative to current drive path)
70
+ if (segments.length === 0 || !segments[0].match(/^[A-Za-z]:/)) {
71
+ segments = [path.slice(0, 2)];
72
+ }
73
+ }
74
+ // Add the rest of the path parts
75
+ segments.push(...withoutDrive.split("/").filter(x => x));
76
+ continue;
77
+ }
78
+
79
+ // If absolute path, reset segments but keep drive letter if present
80
+ if (path.startsWith("/")) {
81
+ if (isWindowsPath && segments.length > 0 && segments[0].match(/^[A-Za-z]:/)) {
82
+ const drive = segments[0];
83
+ segments = [drive];
84
+ } else {
85
+ segments = [];
86
+ }
87
+ }
88
+
89
+ // Split path into segments and process each
90
+ const pathParts = path.split("/").filter(x => x);
91
+ for (const part of pathParts) {
92
+ if (part === "..") {
93
+ // Don't pop off the drive letter
94
+ if (segments.length > (isWindowsPath ? 1 : 0)) {
95
+ segments.pop();
96
+ }
97
+ } else if (part !== ".") {
98
+ // Add segment if not current directory marker
99
+ segments.push(part);
100
+ }
101
+ }
102
+ }
103
+
104
+ // Combine segments into final path
105
+ let result = segments.join("/");
106
+ if (!isWindowsPath) {
107
+ result = "/" + result;
108
+ }
109
+ return result;
110
+ }
111
+ function dirname(path: string): string {
112
+ return path.split("/").slice(0, -1).join("/");
113
+ }
114
+
115
+ const requireCache: { [id: string]: NodeJS.Module } = {};
116
+
117
+ let rootModule = createModule({
118
+ parentModule: undefined,
119
+ resolveAbsolutePath: config.rootPath + "/rootPlaceholder",
120
+ });
121
+ globalThis.require = rootModule.require as any;
122
+
123
+ function createModule(config: {
124
+ parentModule: NodeJS.Module | undefined;
125
+ resolveAbsolutePath: string;
126
+ }): NodeJS.Module {
127
+ const { parentModule, resolveAbsolutePath } = config;
128
+ let cached = requireCache[resolveAbsolutePath];
129
+ if (cached) {
130
+ return cached;
131
+ }
132
+ let serialized = globalThis.registeredModules?.[resolveAbsolutePath];
133
+
134
+ let newModule: NodeJS.Module = {
135
+ id: resolveAbsolutePath,
136
+ filename: resolveAbsolutePath,
137
+ exports: {},
138
+ parent: parentModule,
139
+ children: [],
140
+ isPreloading: false,
141
+ loaded: false,
142
+ path: dirname(resolveAbsolutePath),
143
+ paths: serialized?.paths || [],
144
+ require,
145
+ load,
146
+ } as any;
147
+ newModule.exports.default = newModule.exports;
148
+ if (parentModule) {
149
+ parentModule.children.push(newModule);
150
+ }
151
+ for (let [key, value] of Object.entries(serialized?.moduleFields || {})) {
152
+ if (key in newModule) continue;
153
+ (newModule as any)[key] = value;
154
+ }
155
+ resolve.paths = (request: string) => [];
156
+
157
+ requireCache[newModule.id] = newModule;
158
+ require.resolve = resolve;
159
+ require.cache = requireCache;
160
+ require.main = newModule;
161
+ require.extensions = "extension not implemented yet" as any;
162
+
163
+ // Resolves file extensions
164
+ function innerResolve(path: string): string {
165
+ let candidates = [
166
+ path,
167
+ path + ".js",
168
+ path + ".ts",
169
+ path + ".tsx",
170
+ ];
171
+ for (let candidate of candidates) {
172
+ let registered = globalThis.registeredModules?.[candidate];
173
+ if (registered) {
174
+ return registered.id;
175
+ }
176
+ }
177
+ return path;
178
+ }
179
+
180
+ function resolve(path: string): string {
181
+ path = path.replace(/\\/g, "/");
182
+ if (path.startsWith(".")) {
183
+ return innerResolve(pathResolve(newModule.path, path));
184
+ }
185
+ // We need to search all paths
186
+ for (let searchRoot of serialized?.paths || []) {
187
+ let candidate = innerResolve(pathResolve(searchRoot, path));
188
+ let registered = globalThis.registeredModules?.[candidate];
189
+ if (registered) {
190
+ return registered.id;
191
+ }
192
+ }
193
+ // It is probably "fs" or something like that
194
+ return path;
195
+ // debugger;
196
+ // throw new Error(`Module ${path} not found`);
197
+ }
198
+
199
+ function require(path: string) {
200
+ if (path in builtInModuleExports) {
201
+ return builtInModuleExports[path as keyof typeof builtInModuleExports];
202
+ }
203
+ let resolved = resolve(path);
204
+ let subModule = createModule({
205
+ parentModule: newModule,
206
+ resolveAbsolutePath: resolved,
207
+ }) as any;
208
+ subModule.load(newModule.filename);
209
+ return subModule.exports;
210
+ }
211
+
212
+ function load() {
213
+ if (newModule.loaded) return;
214
+ // NOTE: Set loaded immediately, in case we have a circular dependency
215
+ newModule.loaded = true;
216
+
217
+ if (serialized) {
218
+ serialized.moduleFnc(newModule.exports, require, newModule, newModule.filename, newModule.path);
219
+ } else {
220
+ // If we are being imported by the root module, we need to throw an error
221
+ if (!config.parentModule?.parent) {
222
+ debugger;
223
+ throw new Error(`Could not find required module ${JSON.stringify(config.resolveAbsolutePath)}, have ${JSON.stringify(Object.keys(globalThis.registeredModules || {}))}`);
224
+ }
225
+ newModule.exports = new Proxy(
226
+ {},
227
+ {
228
+ get(target, property) {
229
+ if (property === "__esModule") return undefined;
230
+ if (property === "default") return newModule.exports;
231
+
232
+ console.warn(
233
+ `Module ${newModule.filename} is not available (are you missing "module.allowclient = true"?). Tried to access ${String(property)}.`
234
+ );
235
+ return undefined;
236
+ },
237
+ }
238
+ );
239
+ }
240
+ }
241
+
242
+ return newModule;
243
+ }
244
+ }
@@ -0,0 +1,115 @@
1
+ import { cache } from "socket-function/src/caching";
2
+ import path from "path";
3
+ import fs from "fs";
4
+
5
+ const getPackageJsonPath = cache((directory: string): string | undefined => {
6
+ if (!directory.includes("/") && !directory.includes("\\")) {
7
+ return undefined;
8
+ }
9
+ let packageJsonPath = path.resolve(directory, "package.json");
10
+ if (fs.existsSync(packageJsonPath)) {
11
+ return packageJsonPath;
12
+ }
13
+ return getPackageJsonPath(path.dirname(directory));
14
+ });
15
+ const getMainPath = cache((directory: string): string | undefined => {
16
+ let packageJsonPath = getPackageJsonPath(directory);
17
+ if (!packageJsonPath) return undefined;
18
+ let packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
19
+ let dir = path.dirname(packageJsonPath);
20
+ let mainName = packageJson.main;
21
+ if (!mainName) {
22
+ if (fs.existsSync(path.resolve(dir, "index.js"))) {
23
+ mainName = "index.js";
24
+ } else if (fs.existsSync(path.resolve(dir, "index.ts"))) {
25
+ mainName = "index.ts";
26
+ } else if (fs.existsSync(path.resolve(dir, "index.tsx"))) {
27
+ mainName = "index.tsx";
28
+ } else {
29
+ mainName = "index.js";
30
+ }
31
+ }
32
+ let mainPath = path.resolve(dir, mainName);
33
+ return mainPath;
34
+ });
35
+
36
+
37
+ // Wraps the module so it registers itself when the returned code is evaluated
38
+ // - See https://nodejs.org/api/modules.html#the-module-wrapper
39
+ export function wrapModule(module: NodeJS.Module): string {
40
+ let contents = (module as any).moduleContents || "/* No contents */";
41
+
42
+ // NOTE: debugName only matters during module evaluation. After that the sourcemap should work.
43
+ let debugName = module.filename
44
+ .replace(/\\/g, "/")
45
+ .split("/")
46
+ .slice(-1)[0]
47
+ .replace(/\./g, "_")
48
+ .replace(/[^a-zA-Z_]/g, "");
49
+
50
+ let wrapped = `(function ${debugName}(exports, require, module, __filename, __dirname) { ${contents}
51
+ })`;
52
+
53
+ let moduleFields: { [flag: string]: unknown; } = {};
54
+ for (let [key, value] of Object.entries(module)) {
55
+ if (typeof value === "function") continue;
56
+ if (typeof value === "boolean") {
57
+ moduleFields[key] = value;
58
+ } else if (typeof value === "string" && value.length < 150) {
59
+ moduleFields[key] = value;
60
+ } else if (typeof value === "number") {
61
+ moduleFields[key] = value;
62
+ }
63
+ }
64
+
65
+ let isModuleMain: string | undefined;
66
+ let dirname = path.dirname(module.filename);
67
+ let packageJsonPath = getPackageJsonPath(dirname);
68
+ if (packageJsonPath) {
69
+ let mainPath = getMainPath(dirname);
70
+ if (mainPath?.replaceAll("\\", "/") === module.filename.replaceAll("\\", "/")) {
71
+ // Then we are the main of the module
72
+ isModuleMain = path.dirname(packageJsonPath).replaceAll("\\", "/");
73
+ }
74
+ }
75
+
76
+ // NOTE: We can't have new lines, or they break source maps
77
+ let objWrapped = `{`
78
+ + ` id: ${JSON.stringify(module.id.replaceAll("\\", "/"))},`
79
+ + ` filename: ${JSON.stringify(module.filename.replaceAll("\\", "/"))},`
80
+ + ` isModuleMain: ${JSON.stringify(isModuleMain)},`
81
+ + ` paths: ${JSON.stringify(module.paths.map(p => p.replaceAll("\\", "/")))},`
82
+ + ` moduleFields: ${JSON.stringify(moduleFields)},`
83
+ + ` moduleFnc: ${wrapped}`
84
+ + ` }`;
85
+
86
+ function initModule(serialized: SerializedModule) {
87
+ globalThis.registeredModules = globalThis.registeredModules || {};
88
+ globalThis.registeredModules[serialized.id] = serialized;
89
+ if (serialized.isModuleMain) {
90
+ globalThis.registeredModules[serialized.isModuleMain] = serialized;
91
+ }
92
+ }
93
+
94
+ return `;(${initModule.toString().replaceAll("\n", " ")})(${objWrapped});`;
95
+ }
96
+
97
+ declare global {
98
+ var registeredModules: { [id: string]: SerializedModule; } | undefined;
99
+ }
100
+
101
+ export interface SerializedModule {
102
+ id: string;
103
+ filename: string;
104
+
105
+ // The main main we represent. Ex, "/ai3/node_modules/typesafecss"
106
+ isModuleMain?: string;
107
+
108
+ // Paths which the require function searches for non-relative imports
109
+ paths: string[];
110
+
111
+ // Fields to be set on the module, when it is created
112
+ moduleFields: { [flag: string]: unknown; };
113
+
114
+ moduleFnc: (exports: any, require: any, module: any, __filename: string, __dirname: string) => unknown;
115
+ }
@@ -0,0 +1,72 @@
1
+ import { sha256 } from "js-sha256";
2
+ import { bundleRequire, BundleRequireConfig } from "./bundleRequire";
3
+ import { wrapModule } from "./bundleWrapper";
4
+ import { addToInProgressSourceMap, encodeSourceMapLineComment, finalizeInProgressSourceMap, getInProgressSourceMap, InProgressSourceMap, removeSourceMap } from "./sourceMaps";
5
+ import fs from "fs";
6
+
7
+ export async function bundle(config: {
8
+ modules: (typeof require.cache[""])[];
9
+ rootPath: string;
10
+ entryPoints: string[];
11
+ }): Promise<{
12
+ bundle: string;
13
+ }> {
14
+ const { modules, rootPath, entryPoints } = config;
15
+
16
+ // NOTE: We COULD use an "index source map", which contains other sourcemaps
17
+ // and gives offsets for them. However... tooling support will is better
18
+ // for regular sourcemaps, and it's more flexible.
19
+
20
+ let inProgressSourceMap: InProgressSourceMap = {
21
+ sources: [],
22
+ mappings: [],
23
+ };
24
+
25
+ let code = "";
26
+ let curLineCount = 0;
27
+ for (let module of modules) {
28
+ if (!module) continue;
29
+
30
+ let newCode = wrapModule(module);
31
+
32
+ let { sourceMap, code: newCode2 } = removeSourceMap(newCode);
33
+ newCode = newCode2;
34
+ if (sourceMap) {
35
+ let inProgress = getInProgressSourceMap(sourceMap);
36
+ for (let mapping of inProgress.mappings) {
37
+ mapping.generatedLine += curLineCount;
38
+ }
39
+ addToInProgressSourceMap(inProgressSourceMap, inProgress);
40
+ }
41
+
42
+ code += newCode + "\n";
43
+ curLineCount += (newCode.match(/\n/g) || []).length + 1;
44
+ }
45
+ code += "\n/* Inlined buffer implementation: */\n";
46
+ code += `\n;\n${fs.readFileSync(__dirname + "/buffer.js").toString()}\n;\n`;
47
+ code += `\n;globalThis.__BUNDLE_HASH__ = ${JSON.stringify(sha256(code))};`;
48
+ let bundleConfig: BundleRequireConfig = {
49
+ rootPath,
50
+ };
51
+ code += `;(${bundleRequire.toString()})(${JSON.stringify(bundleConfig)});`;
52
+ // Delay the initial requires, so our extension can boot and we can debug startup errors
53
+ code += "\n;setTimeout(() => {";
54
+ for (let entryPoint of entryPoints) {
55
+ code += `\n;globalThis.require(${JSON.stringify(entryPoint)});`;
56
+ }
57
+ code += "\n;});";
58
+ code += "\n" + encodeSourceMapLineComment(finalizeInProgressSourceMap(inProgressSourceMap));
59
+ return {
60
+ bundle: code,
61
+ };
62
+ }
63
+
64
+ declare global {
65
+ var __BUNDLE_HASH__: string | undefined;
66
+ }
67
+
68
+ export function extractBundleHash(code: string) {
69
+ let match = code.match(/;globalThis.__BUNDLE_HASH__ = "([^"]+)";/);
70
+ if (!match) return undefined;
71
+ return match[1];
72
+ }
File without changes