socket-function 0.8.40 → 0.9.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 (45) hide show
  1. package/.eslintrc.js +50 -50
  2. package/SocketFunction.ts +280 -276
  3. package/SocketFunctionTypes.ts +90 -90
  4. package/hot/HotReloadController.ts +105 -70
  5. package/mobx/UrlParam.ts +39 -39
  6. package/mobx/observer.tsx +49 -49
  7. package/mobx/promiseToObservable.tsx +41 -41
  8. package/package.json +30 -28
  9. package/require/CSSShim.ts +19 -19
  10. package/require/RequireController.ts +252 -252
  11. package/require/buffer.js +2368 -2368
  12. package/require/compileFlags.ts +44 -44
  13. package/require/require.html +13 -13
  14. package/require/require.js +462 -454
  15. package/spec.txt +115 -115
  16. package/src/CallFactory.ts +389 -383
  17. package/src/JSONLACKS/JSONLACKS.generated.js +17 -17
  18. package/src/JSONLACKS/JSONLACKS.pegjs +247 -247
  19. package/src/JSONLACKS/JSONLACKS.ts +429 -375
  20. package/src/args.ts +21 -21
  21. package/src/batching.ts +170 -126
  22. package/src/caching.ts +318 -314
  23. package/src/callHTTPHandler.ts +203 -203
  24. package/src/callManager.ts +134 -134
  25. package/src/certStore.ts +29 -25
  26. package/src/fixLargeNetworkCalls.ts +8 -8
  27. package/src/formatting/colors.ts +78 -78
  28. package/src/formatting/format.ts +160 -156
  29. package/src/formatting/logColors.ts +17 -17
  30. package/src/misc.ts +302 -150
  31. package/src/nodeCache.ts +92 -92
  32. package/src/nodeProxy.ts +54 -54
  33. package/src/profiling/getOwnTime.ts +142 -142
  34. package/src/profiling/measure.ts +273 -244
  35. package/src/profiling/stats.ts +212 -212
  36. package/src/profiling/tcpLagProxy.ts +63 -63
  37. package/src/storagePath.ts +10 -10
  38. package/src/tlsParsing.ts +96 -96
  39. package/src/types.ts +8 -8
  40. package/src/webSocketServer.ts +250 -237
  41. package/test/client.css +2 -2
  42. package/test/client.ts +46 -46
  43. package/test/server.ts +43 -43
  44. package/test/shared.ts +52 -58
  45. package/tsconfig.json +26 -26
@@ -1,455 +1,463 @@
1
- (function () {
2
- // Globals
3
- Object.assign(window, {
4
- process: {
5
- argv: [],
6
- env: {
7
- // Mirror the tnode.js setting
8
- NODE_ENV: "production"
9
- },
10
- },
11
- setImmediate(callback) {
12
- setTimeout(callback, 0);
13
- },
14
- // Ignore flags for now, even though they should work fine if we just hardcoded compileFlags.ts here.
15
- setFlag() { },
16
- global: window,
17
- });
18
-
19
- // Not real modules, as we just define their exports
20
- const builtInModuleExports = {
21
- worker_threads: {
22
- isMainThread: true
23
- },
24
- util: {
25
- // https://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor
26
- inherits(constructor, superConstructor) {
27
- Object.setPrototypeOf(constructor.prototype, superConstructor.prototype);
28
- }
29
- },
30
- buffer: { Buffer },
31
- stream: {
32
- // HACK: Needed to get SAX JS to work correctly.
33
- Stream: function () { },
34
- },
35
- timers: {
36
- // TODO: Add all members of timers
37
- setImmediate: window.setImmediate,
38
- },
39
- child_process: {},
40
- events: {},
41
- };
42
- global.builtInModuleExports = builtInModuleExports;
43
-
44
-
45
- /** @type {{
46
- [resolvePath: string]: {
47
- // May be different then the module filename
48
- filename: string;
49
- // If a module is not allowed clientside it is likely requests will be empty,
50
- // to save effort parsing requests for modules that only exist to give better
51
- // error messages.
52
- requests: {
53
- // request => resolvedPath
54
- [request: string]: string;
55
- };
56
- // NOTE: IF !allowclient && !serveronly, it might just mean we didn't add allowclient
57
- // to the module yet. BUT, if serveronly, then we know for sure we don't want it client.
58
- // So the messages and behavior will be different.
59
- allowclient?: boolean;
60
- serveronly?: boolean;
61
-
62
- source?: string;
63
- }
64
- }} */
65
- let serializedModules = Object.create(null);
66
-
67
- let moduleCache = Object.create(null);
68
- let alreadyHave = undefined;
69
-
70
- let rootResolveCache = Object.create(null);
71
-
72
- rootRequire.cache = moduleCache;
73
- // Expose require for debugging, not so it can be called
74
- window.require = rootRequire;
75
- window.import = rootRequire;
76
-
77
- window.r = function r(text) {
78
- text = text.toLowerCase();
79
- return Object
80
- .values(moduleCache)
81
- .filter(x => x.filename.toLowerCase().includes(text))
82
- [0]
83
- .exports;
84
- };
85
-
86
- let requireBatch;
87
- function rootRequire(request, batch) {
88
- if (!batch) {
89
- if (request in rootResolveCache) {
90
- let resolvedRequest = rootResolveCache[request];
91
- if (resolvedRequest in rootRequire.cache) {
92
- return rootRequire.cache[resolvedRequest].exports;
93
- }
94
- }
95
-
96
-
97
- if (request in rootRequire.cache) {
98
- return rootRequire.cache[request].exports;
99
- }
100
- }
101
-
102
- if (request in builtInModuleExports) {
103
- return builtInModuleExports[request];
104
- }
105
- if (batch) {
106
- if (!requireBatch) {
107
- requireBatch = requireBatch || {};
108
- setTimeout(() => {
109
- let requests = Object.keys(requireBatch);
110
- let callbacks = Object.values(requireBatch).reduce((a, b) => a.concat(b), []);
111
- requireBatch = undefined;
112
- void rootRequireMultiple(requests, true).then(() => {
113
- for (let callback of callbacks) {
114
- callback();
115
- }
116
- }, err => { throw err; });
117
- }, 0);
118
- }
119
- return new Promise(resolve => {
120
- requireBatch[request] = requireBatch[request] || [];
121
- requireBatch[request].push(resolve);
122
- });
123
- } else {
124
- return rootRequireMultiple([request]).then(x => x[0].exports);
125
- }
126
- }
127
- async function rootRequireMultiple(requests) {
128
- console.log(`%cimport(${requests.join(", ")})`, "color: orange");
129
-
130
- let time = Date.now();
131
-
132
- let alreadyHaveRanges;
133
- if (alreadyHave) {
134
- let seqNums = Object.keys(alreadyHave.seqNums).map(x => +x);
135
- seqNums.sort((a, b) => a - b);
136
- let seqNumRanges = [];
137
- alreadyHaveRanges = { requireSeqNumProcessId: alreadyHave.requireSeqNumProcessId, seqNumRanges };
138
- for (let seqNum of seqNums) {
139
- let prev = seqNumRanges[seqNumRanges.length - 1];
140
- if (prev?.e === seqNum) {
141
- prev.e++;
142
- } else {
143
- seqNumRanges.push({ s: seqNum, e: seqNum + 1 });
144
- }
145
- }
146
- for (let range of seqNumRanges) {
147
- if (range.s + 1 === range.e) {
148
- delete range.e;
149
- }
150
- }
151
- }
152
-
153
- let args = [requests, alreadyHaveRanges];
154
- // We have to add hardcoded support for droppermissions, because... this call
155
- // doesn't have the conventional persisted code sending code, because... it's
156
- // all on its own.
157
- if (new URL(location).searchParams.get("droppermissions") !== null) {
158
- args.push(true);
159
- }
160
- let requestUrl = location.origin + location.pathname + `?classGuid=RequireController-e2f811f3-14b8-4759-b0d6-73f14516cf1d&functionName=getModules`;
161
- let rawText = await requestText(requestUrl, { args });
162
- let resultObj;
163
- try {
164
- resultObj = JSON.parse(rawText);
165
- } catch (e) {
166
- console.log(rawText);
167
- throw e;
168
- }
169
- let { modules, requestsResolvedPaths, requireSeqNumProcessId, error } = resultObj;
170
-
171
- if (error) {
172
- let errorObj = new Error();
173
- errorObj.stack = error;
174
- throw errorObj;
175
- }
176
-
177
- for (let i = 0; i < requests.length; i++) {
178
- rootResolveCache[requests[i]] = requestsResolvedPaths[i];
179
- }
180
-
181
- // Store the function, so we only call it if it exists BEFORE we import
182
- // (which means we already have something loading, so this is likely hot reloading...)
183
- let observerOnHotReload = global.observerOnHotReload;
184
- setTimeout(() => {
185
- if (observerOnHotReload) {
186
- observerOnHotReload();
187
- }
188
- }, 0);
189
-
190
- time = Date.now() - time;
191
- let moduleCount = Object.values(modules).filter(x => x.source).length;
192
- let requireModuleCount = Object.values(modules).filter(x => !x.source).length;
193
- let dependenciesOnlyText = requireModuleCount ? ` (+${requireModuleCount} dependencies only)` : "";
194
- console.log(`%cimport(${requests.join(", ")}) download ${time}ms, ${Math.ceil(rawText.length / 1024)}KB, ${moduleCount} modules${dependenciesOnlyText}`, "color: green");
195
-
196
- time = Date.now();
197
-
198
- if (alreadyHave?.requireSeqNumProcessId !== requireSeqNumProcessId) {
199
- alreadyHave = { requireSeqNumProcessId, seqNums: {} };
200
- }
201
-
202
- for (let id in modules) {
203
- let module = modules[id];
204
- alreadyHave.seqNums[module.seqNum] = 1;
205
- serializedModules[id] = module;
206
- }
207
-
208
- try {
209
- return requestsResolvedPaths.map(x => getModule(x));
210
- } finally {
211
- time = Date.now() - time;
212
- console.log(`%cimport(${requests.join(", ")}) evaluate ${time}ms (${moduleCount} modules)`, "color: blue");
213
- }
214
- }
215
-
216
- function createRequire(module, serializedModule, asyncIsFine) {
217
- require.cache = moduleCache;
218
- require.resolve = function (request) {
219
- // TODO: Maybe do a request, making this async, if it isn't found?
220
- return serializedModule.requests[request];
221
- };
222
- return require;
223
- function require(request) {
224
- if (request in builtInModuleExports) {
225
- return builtInModuleExports[request];
226
- }
227
-
228
- if (!(request in serializedModule.requests)) {
229
- if (!asyncIsFine) {
230
- console.warn(`Accessed unexpected module %c${request}%c in %c${module.id}%c\n\tTreating it as an async require.\n\tAll modules require synchronously clientside must be required serverside at a module level.`,
231
- "color: red", "color: unset",
232
- "color: red", "color: unset",
233
- );
234
- }
235
- debugger;
236
- return rootRequire(request);
237
- }
238
-
239
- // Built in modules that we haven't been implemented
240
- if (serializedModule.requests[request] === "") {
241
- return {};
242
- }
243
-
244
- let resolvedPath = serializedModule.requests[request];
245
- if (resolvedPath !== "NOTALLOWEDCLIENTSIDE" && !serializedModules[resolvedPath]) {
246
- if (!asyncIsFine) {
247
- console.warn(`Accessed unexpected module %c${request}%c in %c${module.id}%c\n\tTreating it as an async require.\n\tAll modules require synchronously clientside must be required serverside at a module level.`,
248
- "color: red", "color: unset",
249
- "color: red", "color: unset",
250
- );
251
- }
252
- return rootRequire(resolvedPath);
253
- }
254
-
255
- let exportsOverride = undefined;
256
- if (resolvedPath === "NOTALLOWEDCLIENTSIDE" || !serializedModules[resolvedPath].allowclient) {
257
- let childId = resolvedPath === "NOTALLOWEDCLIENTSIDE" ? request : resolvedPath;
258
- if (serializedModules[resolvedPath]?.serveronly) {
259
- exportsOverride = new Proxy({}, {
260
- get(target, property) {
261
- if (property === "__esModule") return undefined;
262
- // NOTE: Return a toString that evaluates to "" so we can EXPLICITLY detect non-loaded modules
263
- if (property === unloadedModule) return true;
264
- if (property === "default") return exportsOverride;
265
-
266
- throw new Error(`Module ${childId} is serverside only. Tried to access ${property} from ${module.id}`);
267
- }
268
- });
269
- } else {
270
- exportsOverride = new Proxy({}, {
271
- get(target, property) {
272
- if (property === "__esModule") return undefined;
273
- // NOTE: Return a toString that evaluates to "" so we can EXPLICITLY detect non-loaded modules
274
- if (property === unloadedModule) return true;
275
- if (property === "default") return exportsOverride;
276
-
277
- serializedModule;
278
-
279
- console.warn(`Accessed non-whitelisted module %c${childId}%c, specifically property %c${String(property)}%c.\n\tAdd %cmodule.allowclient = true%c to the file to allow access.\n\t(IF it is a 3rd party library, use the global "setFlag" helper (in the file you imported the module) to set properties on other modules (it can even recursively set properties)).\n\n\tFrom ${module.id}`,
280
- "color: red", "color: unset",
281
- "color: red", "color: unset",
282
- "color: red", "color: unset",
283
- );
284
- return undefined;
285
- }
286
- });
287
- }
288
- }
289
-
290
- if (resolvedPath === "NOTALLOWEDCLIENTSIDE") {
291
- return exportsOverride;
292
- }
293
-
294
- let childModule = getModule(resolvedPath);
295
- module.children.push(childModule);
296
- if (exportsOverride !== undefined) {
297
- childModule.exports = exportsOverride;
298
- }
299
- return childModule.exports;
300
- };
301
- }
302
-
303
- /** Generates the module root function, which can be called to evaluate the module,
304
- * and has code equal to contents.
305
- * - filename is just for debugging / stack traces
306
- */
307
- function wrapSafe(filename, contents) {
308
- // TODO: Have the serverside inform us of the correct loader, or... have it actually emit a .json loader.
309
- if (filename.endsWith(".json")) {
310
- return (exports, require, module) => module.exports = contents && JSON.parse(contents);
311
- }
312
-
313
- // NOTE: debugName only matters during module evaluation. After that the sourcemap should work.
314
- let debugName = (
315
- filename
316
- .replace(/\\/g, "/")
317
- .split("/")
318
- .slice(-1)[0]
319
- .replace(/\./g, "_")
320
- .replace(/[^a-zA-Z_]/g, "")
321
- );
322
- // NOTE: eval is used instead of new Function, as new Function inject lines, which messes
323
- // up our sourcemaps.
324
- // NOTE: All on one line, so we don't break sourcemaps by TOO much. We could also parse
325
- // the sourcemap and adjust it, but... it is much easier to just not change the line counts.
326
- return eval(`(function ${debugName}(exports, require, module, __filename, __dirname, importDynamic) {${contents}\n })`);
327
- }
328
-
329
-
330
- const unloadedModule = Symbol("unloadedModule");
331
-
332
- let currentModuleEvaluationStack = [];
333
- // See https://nodejs.org/api/modules.html
334
- function getModule(resolvedId) {
335
- if (resolvedId === "") {
336
- return {};
337
- }
338
- if (resolvedId in moduleCache) {
339
- return moduleCache[resolvedId];
340
- }
341
-
342
- let serializedModule = serializedModules[resolvedId];
343
-
344
- let module = Object.create(null);
345
- moduleCache[resolvedId] = module;
346
- module.id = resolvedId;
347
- module.filename = serializedModule?.filename;
348
- module.exports = {};
349
- module.exports.default = module.exports;
350
- module.children = [];
351
-
352
- module.load = load;
353
-
354
- module.loaded = true;
355
- module.load();
356
-
357
- function load(filename) {
358
- let serializedModule = serializedModules[resolvedId];
359
- if (!module.loaded) {
360
- if (alreadyHave) {
361
- delete alreadyHave.seqNums[serializedModule.seqNum];
362
- }
363
- // NOTE: There is almost never recovery from module downloading errors, so just don't catch them
364
- void Promise.resolve().then(() => rootRequire(resolvedId, true)).then(() => {
365
- module.loaded = true;
366
- load();
367
- });
368
- return;
369
- }
370
-
371
- module.requires = serializedModule.requests;
372
- module.require = createRequire(module, serializedModule);
373
- // TODO: Once typescript supports dynamic import, map import() to importDynamic, so it
374
- // uses our import function, instead of the built in one.
375
- // (As apparently we can't just override import on a per module basis, because
376
- // we can't have an identify called "import"... which is annoying).
377
- let importDynamic = createRequire(module, serializedModule, true);
378
- module.import = importDynamic;
379
-
380
- let source = serializedModule.source;
381
-
382
- module.allowclient = !!serializedModule.source;
383
-
384
- // Import children, as the children may be allowed clientside, and may have side-effects!
385
- if (!source) {
386
- let requests = Object.keys(serializedModule.requests).filter(x => x !== "NOTALLOWEDCLIENTSIDE");
387
- source = requests.map(id => `require(${JSON.stringify(id)});\n`).join("");
388
- }
389
-
390
- module.size = source.length;
391
-
392
- let moduleFnc = wrapSafe(module.id, source);
393
-
394
- let dirname = module.filename.replace(/\\/g, "/").split("/").slice(0, -1).join("/");
395
-
396
- let time = Date.now();
397
- currentModuleEvaluationStack.push(module.filename);
398
- try {
399
- moduleFnc.call(
400
- {
401
- // NOTE: Adding __importStar to the module causes typescript to use our implementation,
402
- // which checks for unloadedModule and returns undefined in that case.
403
- __importStar(mod) {
404
- if (mod[unloadedModule]) return undefined;
405
- return mod;
406
- },
407
- __importDefault(mod) {
408
- return mod.default ? mod : { default: mod };
409
- },
410
- },
411
- module.exports,
412
- module.require,
413
- module,
414
- module.filename,
415
- dirname,
416
- importDynamic
417
- );
418
- time = Date.now() - time;
419
- // NOTE: This log statment is disabled as I believe it causes lag (when devtools is open).
420
- // As in, adding about 500ms to our load time, which is annoying when debugging.
421
- //console.debug(`Evaluated module ${module.filename} ${Math.ceil(source.length / 1024)}KB`);
422
- } finally {
423
- currentModuleEvaluationStack.pop();
424
- }
425
-
426
- }
427
-
428
- return module;
429
- }
430
-
431
- async function requestText(endpoint, values) {
432
- let url = new URL(endpoint);
433
-
434
- let json = JSON.stringify(values);
435
- if (json.length < 6000) {
436
- // NOTE: Try to use a GET, as GETs can be cached! However, if the data is too large,
437
- // we have to use a post, or else the request url will be too large
438
- for (let key in values) {
439
- url.searchParams.set(key, JSON.stringify(values[key]));
440
- }
441
- let response = await fetch(url.toString(), {
442
- method: "GET",
443
- credentials: "include",
444
- });
445
- return await response.text();
446
- } else {
447
- let response = await fetch(url.toString(), {
448
- method: "POST",
449
- body: json,
450
- credentials: "include",
451
- });
452
- return await response.text();
453
- }
454
- }
1
+ (function () {
2
+ //# sourceURL=require.js
3
+
4
+ // Globals
5
+ Object.assign(window, {
6
+ process: {
7
+ argv: [],
8
+ env: {
9
+ // Mirror the tnode.js setting
10
+ NODE_ENV: "production"
11
+ },
12
+ },
13
+ setImmediate(callback) {
14
+ setTimeout(callback, 0);
15
+ },
16
+ // Ignore flags for now, even though they should work fine if we just hardcoded compileFlags.ts here.
17
+ setFlag() { },
18
+ global: window,
19
+ });
20
+
21
+ // Not real modules, as we just define their exports
22
+ const builtInModuleExports = {
23
+ worker_threads: {
24
+ isMainThread: true
25
+ },
26
+ util: {
27
+ // https://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor
28
+ inherits(constructor, superConstructor) {
29
+ Object.setPrototypeOf(constructor.prototype, superConstructor.prototype);
30
+ }
31
+ },
32
+ buffer: { Buffer },
33
+ stream: {
34
+ // HACK: Needed to get SAX JS to work correctly.
35
+ Stream: function () { },
36
+ },
37
+ timers: {
38
+ // TODO: Add all members of timers
39
+ setImmediate: window.setImmediate,
40
+ },
41
+ child_process: {},
42
+ events: {},
43
+ };
44
+ global.builtInModuleExports = builtInModuleExports;
45
+
46
+
47
+ /** @type {{
48
+ [resolvePath: string]: {
49
+ // May be different then the module filename
50
+ filename: string;
51
+ // If a module is not allowed clientside it is likely requests will be empty,
52
+ // to save effort parsing requests for modules that only exist to give better
53
+ // error messages.
54
+ requests: {
55
+ // request => resolvedPath
56
+ [request: string]: string;
57
+ };
58
+ // NOTE: IF !allowclient && !serveronly, it might just mean we didn't add allowclient
59
+ // to the module yet. BUT, if serveronly, then we know for sure we don't want it client.
60
+ // So the messages and behavior will be different.
61
+ allowclient?: boolean;
62
+ serveronly?: boolean;
63
+
64
+ source?: string;
65
+ }
66
+ }} */
67
+ let serializedModules = Object.create(null);
68
+
69
+ let moduleCache = Object.create(null);
70
+ let alreadyHave = undefined;
71
+
72
+ let rootResolveCache = Object.create(null);
73
+
74
+ rootRequire.cache = moduleCache;
75
+ // Expose require for debugging, not so it can be called
76
+ window.require = rootRequire;
77
+ window.import = rootRequire;
78
+
79
+ window.r = function r(text) {
80
+ text = text.toLowerCase();
81
+ return Object
82
+ .values(moduleCache)
83
+ .filter(x => x.filename.toLowerCase().includes(text))
84
+ [0]
85
+ .exports;
86
+ };
87
+
88
+ let requireBatch;
89
+ function rootRequire(request, batch) {
90
+ if (!batch) {
91
+ if (request in rootResolveCache) {
92
+ let resolvedRequest = rootResolveCache[request];
93
+ if (resolvedRequest in rootRequire.cache) {
94
+ return rootRequire.cache[resolvedRequest].exports;
95
+ }
96
+ }
97
+
98
+
99
+ if (request in rootRequire.cache) {
100
+ return rootRequire.cache[request].exports;
101
+ }
102
+ }
103
+
104
+ if (request in builtInModuleExports) {
105
+ return builtInModuleExports[request];
106
+ }
107
+ if (batch) {
108
+ if (!requireBatch) {
109
+ requireBatch = requireBatch || {};
110
+ setTimeout(() => {
111
+ let requests = Object.keys(requireBatch);
112
+ let callbacks = Object.values(requireBatch).reduce((a, b) => a.concat(b), []);
113
+ requireBatch = undefined;
114
+ void rootRequireMultiple(requests, true).then(() => {
115
+ for (let callback of callbacks) {
116
+ callback();
117
+ }
118
+ }, err => { throw err; });
119
+ }, 0);
120
+ }
121
+ return new Promise(resolve => {
122
+ requireBatch[request] = requireBatch[request] || [];
123
+ requireBatch[request].push(resolve);
124
+ });
125
+ } else {
126
+ return rootRequireMultiple([request]).then(x => x[0].exports);
127
+ }
128
+ }
129
+ async function rootRequireMultiple(requests) {
130
+ console.log(`%cimport(${requests.join(", ")})`, "color: orange");
131
+
132
+ let time = Date.now();
133
+
134
+ let alreadyHaveRanges;
135
+ if (alreadyHave) {
136
+ let seqNums = Object.keys(alreadyHave.seqNums).map(x => +x);
137
+ seqNums.sort((a, b) => a - b);
138
+ let seqNumRanges = [];
139
+ alreadyHaveRanges = { requireSeqNumProcessId: alreadyHave.requireSeqNumProcessId, seqNumRanges };
140
+ for (let seqNum of seqNums) {
141
+ let prev = seqNumRanges[seqNumRanges.length - 1];
142
+ if (prev?.e === seqNum) {
143
+ prev.e++;
144
+ } else {
145
+ seqNumRanges.push({ s: seqNum, e: seqNum + 1 });
146
+ }
147
+ }
148
+ for (let range of seqNumRanges) {
149
+ if (range.s + 1 === range.e) {
150
+ delete range.e;
151
+ }
152
+ }
153
+ }
154
+
155
+ let args = [requests, alreadyHaveRanges];
156
+ // We have to add hardcoded support for droppermissions, because... this call
157
+ // doesn't have the conventional persisted code sending code, because... it's
158
+ // all on its own.
159
+ if (new URL(location).searchParams.get("droppermissions") !== null) {
160
+ args.push(true);
161
+ }
162
+ let requestUrl = location.origin + location.pathname + `?classGuid=RequireController-e2f811f3-14b8-4759-b0d6-73f14516cf1d&functionName=getModules`;
163
+ let rawText = await requestText(requestUrl, { args });
164
+ let resultObj;
165
+ try {
166
+ resultObj = JSON.parse(rawText);
167
+ } catch (e) {
168
+ console.log(rawText);
169
+ throw e;
170
+ }
171
+ let { modules, requestsResolvedPaths, requireSeqNumProcessId, error } = resultObj;
172
+
173
+ if (error) {
174
+ let errorObj = new Error();
175
+ errorObj.stack = error;
176
+ throw errorObj;
177
+ }
178
+
179
+ for (let i = 0; i < requests.length; i++) {
180
+ rootResolveCache[requests[i]] = requestsResolvedPaths[i];
181
+ }
182
+
183
+ // Store the function, so we only call it if it exists BEFORE we import
184
+ // (which means we already have something loading, so this is likely hot reloading...)
185
+ let observerOnHotReload = global.observerOnHotReload;
186
+ setTimeout(() => {
187
+ if (observerOnHotReload) {
188
+ observerOnHotReload();
189
+ }
190
+ }, 0);
191
+
192
+ time = Date.now() - time;
193
+ let moduleCount = Object.values(modules).filter(x => x.source).length;
194
+ let requireModuleCount = Object.values(modules).filter(x => !x.source).length;
195
+ let dependenciesOnlyText = requireModuleCount ? ` (+${requireModuleCount} dependencies only)` : "";
196
+ console.log(`%cimport(${requests.join(", ")}) download ${time}ms, ${Math.ceil(rawText.length / 1024)}KB, ${moduleCount} modules${dependenciesOnlyText}`, "color: green");
197
+
198
+ time = Date.now();
199
+
200
+ if (alreadyHave?.requireSeqNumProcessId !== requireSeqNumProcessId) {
201
+ alreadyHave = { requireSeqNumProcessId, seqNums: {} };
202
+ }
203
+
204
+ for (let id in modules) {
205
+ let module = modules[id];
206
+ alreadyHave.seqNums[module.seqNum] = 1;
207
+ serializedModules[id] = module;
208
+ }
209
+
210
+ try {
211
+ return requestsResolvedPaths.map(x => getModule(x));
212
+ } finally {
213
+ time = Date.now() - time;
214
+ console.log(`%cimport(${requests.join(", ")}) evaluate ${time}ms (${moduleCount} modules)`, "color: blue");
215
+ }
216
+ }
217
+
218
+ function createRequire(module, serializedModule, asyncIsFineOuter) {
219
+ require.cache = moduleCache;
220
+ require.resolve = function (request) {
221
+ // TODO: Maybe do a request, making this async, if it isn't found?
222
+ return serializedModule.requests[request];
223
+ };
224
+ return require;
225
+ function require(request, asyncIsFine) {
226
+ if (asyncIsFineOuter) {
227
+ asyncIsFine = true;
228
+ }
229
+ if (typeof asyncIsFine !== "boolean") {
230
+ asyncIsFine = false;
231
+ }
232
+ if (request in builtInModuleExports) {
233
+ return builtInModuleExports[request];
234
+ }
235
+
236
+ if (!(request in serializedModule.requests)) {
237
+ if (!asyncIsFine) {
238
+ console.warn(`Accessed unexpected module %c${request}%c in %c${module.id}%c\n\tTreating it as an async require.\n\tAll modules require synchronously clientside must be required serverside at a module level.`,
239
+ "color: red", "color: unset",
240
+ "color: red", "color: unset",
241
+ );
242
+ }
243
+ return rootRequire(request);
244
+ }
245
+
246
+ // Built in modules that we haven't been implemented
247
+ if (serializedModule.requests[request] === "") {
248
+ return {};
249
+ }
250
+
251
+ let resolvedPath = serializedModule.requests[request];
252
+ if (resolvedPath !== "NOTALLOWEDCLIENTSIDE" && !serializedModules[resolvedPath]) {
253
+ if (!asyncIsFine) {
254
+ console.warn(`Accessed unexpected module %c${request}%c in %c${module.id}%c\n\tTreating it as an async require.\n\tAll modules require synchronously clientside must be required serverside at a module level.`,
255
+ "color: red", "color: unset",
256
+ "color: red", "color: unset",
257
+ );
258
+ }
259
+ debugger;
260
+ return rootRequire(resolvedPath);
261
+ }
262
+
263
+ let exportsOverride = undefined;
264
+ if (resolvedPath === "NOTALLOWEDCLIENTSIDE" || !serializedModules[resolvedPath].allowclient) {
265
+ let childId = resolvedPath === "NOTALLOWEDCLIENTSIDE" ? request : resolvedPath;
266
+ if (serializedModules[resolvedPath]?.serveronly) {
267
+ exportsOverride = new Proxy({}, {
268
+ get(target, property) {
269
+ if (property === "__esModule") return undefined;
270
+ // NOTE: Return a toString that evaluates to "" so we can EXPLICITLY detect non-loaded modules
271
+ if (property === unloadedModule) return true;
272
+ if (property === "default") return exportsOverride;
273
+
274
+ throw new Error(`Module ${childId} is serverside only. Tried to access ${property} from ${module.id}`);
275
+ }
276
+ });
277
+ } else {
278
+ exportsOverride = new Proxy({}, {
279
+ get(target, property) {
280
+ if (property === "__esModule") return undefined;
281
+ // NOTE: Return a toString that evaluates to "" so we can EXPLICITLY detect non-loaded modules
282
+ if (property === unloadedModule) return true;
283
+ if (property === "default") return exportsOverride;
284
+
285
+ serializedModule;
286
+
287
+ console.warn(`Accessed non-whitelisted module %c${childId}%c, specifically property %c${String(property)}%c.\n\tAdd %cmodule.allowclient = true%c to the file to allow access.\n\t(IF it is a 3rd party library, use the global "setFlag" helper (in the file you imported the module) to set properties on other modules (it can even recursively set properties)).\n\n\tFrom ${module.id}`,
288
+ "color: red", "color: unset",
289
+ "color: red", "color: unset",
290
+ "color: red", "color: unset",
291
+ );
292
+ return undefined;
293
+ }
294
+ });
295
+ }
296
+ }
297
+
298
+ if (resolvedPath === "NOTALLOWEDCLIENTSIDE") {
299
+ return exportsOverride;
300
+ }
301
+
302
+ let childModule = getModule(resolvedPath);
303
+ module.children.push(childModule);
304
+ if (exportsOverride !== undefined) {
305
+ childModule.exports = exportsOverride;
306
+ }
307
+ return childModule.exports;
308
+ };
309
+ }
310
+
311
+ /** Generates the module root function, which can be called to evaluate the module,
312
+ * and has code equal to contents.
313
+ * - filename is just for debugging / stack traces
314
+ */
315
+ function wrapSafe(filename, contents) {
316
+ // TODO: Have the serverside inform us of the correct loader, or... have it actually emit a .json loader.
317
+ if (filename.endsWith(".json")) {
318
+ return (exports, require, module) => module.exports = contents && JSON.parse(contents);
319
+ }
320
+
321
+ // NOTE: debugName only matters during module evaluation. After that the sourcemap should work.
322
+ let debugName = (
323
+ filename
324
+ .replace(/\\/g, "/")
325
+ .split("/")
326
+ .slice(-1)[0]
327
+ .replace(/\./g, "_")
328
+ .replace(/[^a-zA-Z_]/g, "")
329
+ );
330
+ // NOTE: eval is used instead of new Function, as new Function inject lines, which messes
331
+ // up our sourcemaps.
332
+ // NOTE: All on one line, so we don't break sourcemaps by TOO much. We could also parse
333
+ // the sourcemap and adjust it, but... it is much easier to just not change the line counts.
334
+ return eval(`(function ${debugName}(exports, require, module, __filename, __dirname, importDynamic) {${contents}\n })`);
335
+ }
336
+
337
+
338
+ const unloadedModule = Symbol("unloadedModule");
339
+
340
+ let currentModuleEvaluationStack = [];
341
+ // See https://nodejs.org/api/modules.html
342
+ function getModule(resolvedId) {
343
+ if (resolvedId === "") {
344
+ return {};
345
+ }
346
+ if (resolvedId in moduleCache) {
347
+ return moduleCache[resolvedId];
348
+ }
349
+
350
+ let serializedModule = serializedModules[resolvedId];
351
+
352
+ let module = Object.create(null);
353
+ moduleCache[resolvedId] = module;
354
+ module.id = resolvedId;
355
+ module.filename = serializedModule?.filename;
356
+ module.exports = {};
357
+ module.exports.default = module.exports;
358
+ module.children = [];
359
+
360
+ module.load = load;
361
+
362
+ module.loaded = true;
363
+ module.load();
364
+
365
+ function load(filename) {
366
+ let serializedModule = serializedModules[resolvedId];
367
+ if (!module.loaded) {
368
+ if (alreadyHave) {
369
+ delete alreadyHave.seqNums[serializedModule.seqNum];
370
+ }
371
+ // NOTE: There is almost never recovery from module downloading errors, so just don't catch them
372
+ void Promise.resolve().then(() => rootRequire(resolvedId, true)).then(() => {
373
+ module.loaded = true;
374
+ load();
375
+ });
376
+ return;
377
+ }
378
+
379
+ module.requires = serializedModule.requests;
380
+ module.require = createRequire(module, serializedModule);
381
+ // TODO: Once typescript supports dynamic import, map import() to importDynamic, so it
382
+ // uses our import function, instead of the built in one.
383
+ // (As apparently we can't just override import on a per module basis, because
384
+ // we can't have an identify called "import"... which is annoying).
385
+ let importDynamic = createRequire(module, serializedModule, true);
386
+ module.import = importDynamic;
387
+
388
+ let source = serializedModule.source;
389
+
390
+ module.allowclient = !!serializedModule.source;
391
+
392
+ // Import children, as the children may be allowed clientside, and may have side-effects!
393
+ if (!source) {
394
+ let requests = Object.keys(serializedModule.requests).filter(x => x !== "NOTALLOWEDCLIENTSIDE");
395
+ source = requests.map(id => `require(${JSON.stringify(id)});\n`).join("");
396
+ }
397
+
398
+ module.size = source.length;
399
+
400
+ let moduleFnc = wrapSafe(module.id, source);
401
+
402
+ let dirname = module.filename.replace(/\\/g, "/").split("/").slice(0, -1).join("/");
403
+
404
+ let time = Date.now();
405
+ currentModuleEvaluationStack.push(module.filename);
406
+ try {
407
+ moduleFnc.call(
408
+ {
409
+ // NOTE: Adding __importStar to the module causes typescript to use our implementation,
410
+ // which checks for unloadedModule and returns undefined in that case.
411
+ __importStar(mod) {
412
+ if (mod[unloadedModule]) return undefined;
413
+ return mod;
414
+ },
415
+ __importDefault(mod) {
416
+ return mod.default ? mod : { default: mod };
417
+ },
418
+ },
419
+ module.exports,
420
+ module.require,
421
+ module,
422
+ module.filename,
423
+ dirname,
424
+ importDynamic
425
+ );
426
+ time = Date.now() - time;
427
+ // NOTE: This log statment is disabled as I believe it causes lag (when devtools is open).
428
+ // As in, adding about 500ms to our load time, which is annoying when debugging.
429
+ //console.debug(`Evaluated module ${module.filename} ${Math.ceil(source.length / 1024)}KB`);
430
+ } finally {
431
+ currentModuleEvaluationStack.pop();
432
+ }
433
+
434
+ }
435
+
436
+ return module;
437
+ }
438
+
439
+ async function requestText(endpoint, values) {
440
+ let url = new URL(endpoint);
441
+
442
+ let json = JSON.stringify(values);
443
+ if (json.length < 6000) {
444
+ // NOTE: Try to use a GET, as GETs can be cached! However, if the data is too large,
445
+ // we have to use a post, or else the request url will be too large
446
+ for (let key in values) {
447
+ url.searchParams.set(key, JSON.stringify(values[key]));
448
+ }
449
+ let response = await fetch(url.toString(), {
450
+ method: "GET",
451
+ credentials: "include",
452
+ });
453
+ return await response.text();
454
+ } else {
455
+ let response = await fetch(url.toString(), {
456
+ method: "POST",
457
+ body: json,
458
+ credentials: "include",
459
+ });
460
+ return await response.text();
461
+ }
462
+ }
455
463
  })();