socket-function 0.64.0 → 0.65.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.
@@ -81,7 +81,7 @@ const hotReloadModule = cache((module: NodeJS.Module) => {
81
81
  || module.moduleContents?.includes("\nmodule.hotreload = true;" + "\n")
82
82
  || module.moduleContents?.includes("\r\nmodule.hotreload = true;" + "\r\n")
83
83
  ) {
84
- console.log(`Reloading ${module.id}`);
84
+ console.log(`Serverside reloading ${module.id}`);
85
85
  isHotReloadingValue = true;
86
86
  try {
87
87
  module.loaded = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "socket-function",
3
- "version": "0.64.0",
3
+ "version": "0.65.0",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {
@@ -5,8 +5,9 @@ import { SocketFunction } from "../SocketFunction";
5
5
  import { getCurrentHTTPRequest, setHTTPResultHeaders } from "../src/callHTTPHandler";
6
6
  import { formatNumberSuffixed, isNode, isNodeTrue, sha256Hash, sha256HashPromise } from "../src/misc";
7
7
  import zlib from "zlib";
8
- import { cacheLimited } from "../src/caching";
8
+ import { cacheLimited, lazy } from "../src/caching";
9
9
  import { formatNumber } from "../src/formatting/format";
10
+ import { requireMain } from "./require";
10
11
 
11
12
  const COMPRESS_CACHE_SIZE = 1024 * 1024 * 128;
12
13
 
@@ -98,17 +99,21 @@ let nextModuleSeqNum = 1;
98
99
 
99
100
  const requireSeqNumProcessId = "requireSeqNumProcessId_" + Date.now() + "_" + Math.random();
100
101
 
101
- const htmlFile = isNodeTrue() && fs.readFileSync(__dirname + "/require.html").toString();
102
- const jsFile = isNodeTrue() && fs.readFileSync(__dirname + "/require.js").toString();
103
- const bufferShim = isNodeTrue() && fs.readFileSync(__dirname + "/buffer.js").toString();
104
102
  const BEFORE_ENTRY_TEMPLATE = "<!-- BEFORE_ENTRY_TEMPLATE -->";
105
103
  const ENTRY_TEMPLATE = "<!-- ENTRY_TEMPLATE -->";
106
104
 
107
- const resolvedHTMLFile = isNodeTrue() && (
108
- htmlFile
109
- .replace(`<script src="./buffer.js"></script>`, `<script>${bufferShim}</script>`)
110
- .replace(`<script src="./require.js"></script>`, `<script>${jsFile}</script>`)
111
- );
105
+ const resolvedHTMLFile = lazy(() => {
106
+ const bufferShim = fs.readFileSync(__dirname + "/buffer.js").toString();
107
+ return fs.readFileSync(__dirname + "/require.html").toString()
108
+ .replace(BEFORE_ENTRY_TEMPLATE,
109
+ `
110
+ <script>${bufferShim}</script>
111
+ <script>(${requireMain.toString()})()</script>
112
+
113
+ ${BEFORE_ENTRY_TEMPLATE}
114
+ `
115
+ );
116
+ });
112
117
 
113
118
  let beforeEntryText: (string | (() => Promise<string>))[] = [];
114
119
  function injectHTMLBeforeStartup(text: string | (() => Promise<string>)) {
@@ -116,7 +121,7 @@ function injectHTMLBeforeStartup(text: string | (() => Promise<string>)) {
116
121
  }
117
122
 
118
123
  type GetModulesResult = ReturnType<RequireControllerBase["getModules"]> extends Promise<infer T> ? T : never;
119
- type GetModulesArgs = Parameters<RequireControllerBase["getModules"]>;
124
+ export type GetModulesArgs = Parameters<RequireControllerBase["getModules"]>;
120
125
  let mapGetModules: {
121
126
  remap(result: GetModulesResult, args: GetModulesArgs): Promise<GetModulesResult>
122
127
  }[] = [];
@@ -131,7 +136,7 @@ class RequireControllerBase {
131
136
  requireCalls?: string[];
132
137
  }) {
133
138
  let { requireCalls } = config || {};
134
- let result = resolvedHTMLFile;
139
+ let result = resolvedHTMLFile();
135
140
  if (beforeEntryText.length > 0) {
136
141
  let resolved: string[] = [];
137
142
  for (let text of beforeEntryText) {
@@ -164,13 +169,6 @@ class RequireControllerBase {
164
169
  return setHTTPResultHeaders(Buffer.from(result), { "Content-Type": "text/html" });
165
170
  }
166
171
 
167
- public async bufferJS() {
168
- return setHTTPResultHeaders(Buffer.from(bufferShim), { "Content-Type": "text/javascript" });
169
- }
170
- public async requireJS() {
171
- return setHTTPResultHeaders(Buffer.from(jsFile), { "Content-Type": "text/javascript" });
172
- }
173
-
174
172
  public async getModules(
175
173
  pathRequests: string[],
176
174
  alreadyHave?: {
@@ -6,9 +6,6 @@
6
6
  <body>
7
7
  <div id="main"></div>
8
8
 
9
- <script src="./buffer.js"></script>
10
- <script src="./require.js"></script>
11
-
12
9
  <!-- BEFORE_ENTRY_TEMPLATE -->
13
10
  <!-- ENTRY_TEMPLATE -->
14
11
  </body>
@@ -1,11 +1,14 @@
1
- (function () {
1
+ import { GetModulesArgs, SerializedModule } from "./RequireController";
2
+
3
+ export function requireMain() {
2
4
  //# sourceURL=require.js
3
5
 
6
+ const g = globalThis as any;
4
7
  let startTime = Date.now();
5
- globalThis.BOOT_TIME = startTime;
8
+ g.BOOT_TIME = startTime;
6
9
 
7
- Symbol.dispose = Symbol.dispose || Symbol("dispose");
8
- Symbol.asyncDispose = Symbol.asyncDispose || Symbol("asyncDispose");
10
+ (Symbol as any).dispose = Symbol.dispose || Symbol("dispose");
11
+ (Symbol as any).asyncDispose = Symbol.asyncDispose || Symbol("asyncDispose");
9
12
 
10
13
  // Globals
11
14
  Object.assign(window, {
@@ -17,11 +20,11 @@
17
20
  },
18
21
  versions: {},
19
22
  },
20
- setImmediate(callback) {
23
+ setImmediate(callback: () => void) {
21
24
  setTimeout(callback, 0);
22
25
  },
23
26
  // Ignore flags for now, even though they should work fine if we just hardcoded compileFlags.ts here.
24
- setFlag() {},
27
+ setFlag() { },
25
28
  global: window,
26
29
  });
27
30
 
@@ -32,7 +35,7 @@
32
35
  },
33
36
  util: {
34
37
  // https://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor
35
- inherits(constructor, superConstructor) {
38
+ inherits(constructor: any, superConstructor: any) {
36
39
  Object.setPrototypeOf(constructor.prototype, superConstructor.prototype);
37
40
  },
38
41
  TextDecoder: TextDecoder,
@@ -41,8 +44,8 @@
41
44
  buffer: { Buffer },
42
45
  stream: {
43
46
  // HACK: Needed to get SAX JS to work correctly.
44
- Stream: function () {},
45
- Transform: function () {},
47
+ Stream: function () { },
48
+ Transform: function () { },
46
49
  },
47
50
  timers: {
48
51
  // TODO: Add all members of timers
@@ -51,7 +54,7 @@
51
54
  child_process: {},
52
55
  events: {},
53
56
  };
54
- global.builtInModuleExports = builtInModuleExports;
57
+ g.builtInModuleExports = builtInModuleExports;
55
58
 
56
59
  let lastTime = 0;
57
60
  function nextTime() {
@@ -88,23 +91,42 @@
88
91
  }} */
89
92
  let serializedModules = Object.create(null);
90
93
 
91
- let moduleCache = Object.create(null);
92
- let alreadyHave = undefined;
94
+ type ModuleType = {
95
+ id: string;
96
+ filename: string;
97
+ exports: unknown;
98
+ children: ModuleType[];
99
+ flags: { [key: string]: boolean };
100
+ load: () => void;
101
+ loaded: boolean;
102
+ isPreloading: boolean;
103
+ evalStartTime: number;
104
+ evalEndTime: number;
105
+ source: string;
106
+ allowclient: boolean;
107
+ size: number;
108
+ };
109
+
110
+ let moduleCache: { [id: string]: ModuleType } = Object.create(null);
111
+ let alreadyHave: {
112
+ requireSeqNumProcessId: string;
113
+ seqNums: { [seqNum: string]: true | 1 | 0 | undefined };
114
+ } | undefined;
93
115
 
94
116
  let rootResolveCache = Object.create(null);
95
117
 
96
118
  rootRequire.cache = moduleCache;
97
119
  // Expose require for debugging, not so it can be called
98
- window.require = rootRequire;
99
- window.import = rootRequire;
120
+ g.require = rootRequire;
121
+ g.import = rootRequire;
100
122
 
101
- window.r = function r(text) {
123
+ g.r = function r(text: string) {
102
124
  text = text.toLowerCase();
103
125
  return Object.values(moduleCache).filter((x) => x.filename.toLowerCase().includes(text))[0].exports;
104
126
  };
105
127
 
106
- let requireBatch;
107
- function rootRequire(request, batch) {
128
+ let requireBatch: { [request: string]: (() => void)[] } | undefined;
129
+ function rootRequire(request: string, batch?: boolean): unknown {
108
130
  if (!batch) {
109
131
  if (request in rootResolveCache) {
110
132
  let resolvedRequest = rootResolveCache[request];
@@ -119,16 +141,16 @@
119
141
  }
120
142
 
121
143
  if (request in builtInModuleExports) {
122
- return builtInModuleExports[request];
144
+ return builtInModuleExports[request as keyof typeof builtInModuleExports];
123
145
  }
124
146
  if (batch) {
125
147
  if (!requireBatch) {
126
- requireBatch = requireBatch || {};
127
148
  setTimeout(() => {
149
+ requireBatch = requireBatch || {};
128
150
  let requests = Object.keys(requireBatch);
129
151
  let callbacks = Object.values(requireBatch).reduce((a, b) => a.concat(b), []);
130
152
  requireBatch = undefined;
131
- void rootRequireMultiple(requests, true).then(
153
+ void rootRequireMultiple(requests).then(
132
154
  () => {
133
155
  for (let callback of callbacks) {
134
156
  callback();
@@ -140,7 +162,8 @@
140
162
  );
141
163
  }, 0);
142
164
  }
143
- return new Promise((resolve) => {
165
+ return new Promise<void>((resolve) => {
166
+ if (!requireBatch) throw new Error("Impossible");
144
167
  requireBatch[request] = requireBatch[request] || [];
145
168
  requireBatch[request].push(resolve);
146
169
  });
@@ -148,7 +171,7 @@
148
171
  return rootRequireMultiple([request]).then((x) => x[0].exports);
149
172
  }
150
173
  }
151
- async function rootRequireMultiple(requests) {
174
+ async function rootRequireMultiple(requests: string[]) {
152
175
  console.log(`%cimport(${requests.join(", ")}) at ${Date.now() - startTime}ms`, "color: orange");
153
176
 
154
177
  let time = Date.now();
@@ -157,7 +180,7 @@
157
180
  if (alreadyHave) {
158
181
  let seqNums = Object.keys(alreadyHave.seqNums).map((x) => +x);
159
182
  seqNums.sort((a, b) => a - b);
160
- let seqNumRanges = [];
183
+ let seqNumRanges: { s: number; e?: number }[] = [];
161
184
  alreadyHaveRanges = { requireSeqNumProcessId: alreadyHave.requireSeqNumProcessId, seqNumRanges };
162
185
  for (let seqNum of seqNums) {
163
186
  let prev = seqNumRanges[seqNumRanges.length - 1];
@@ -174,17 +197,40 @@
174
197
  }
175
198
  }
176
199
 
177
- let args = [requests, alreadyHaveRanges];
200
+ let domainOrigin = "";
201
+ let originalRequests = requests;
202
+ if (requests.some(x => x.startsWith("https://"))) {
203
+ requests = requests.map((request) => {
204
+ if (!request.startsWith("https://")) {
205
+ throw new Error(`Mixed domains with non-domain requests is not supported presently. Requests: ${requests.join(" | ")}`);
206
+ }
207
+ let url = new URL(request);
208
+ if (domainOrigin && domainOrigin !== url.origin) {
209
+ // TODO: If this happens, we can probably just split the call up into multiple calls?
210
+ throw new Error(`Mixed domains in require call is not supported presently. Requests: ${requests.join(" | ")}`);
211
+ }
212
+ domainOrigin = url.origin + "/";
213
+ // By stripping by length, we can turn https://example.com/./test => "./test"
214
+ // (where as if we used pathname, it would turn into "/test"
215
+ return request.slice(domainOrigin.length);
216
+ });
217
+ }
218
+
219
+ let args: GetModulesArgs = [requests, alreadyHaveRanges];
178
220
  // We have to add hardcoded support for droppermissions, because... this call
179
221
  // doesn't have the conventional persisted code sending code, because... it's
180
222
  // all on its own.
181
- if (new URL(location).searchParams.get("droppermissions") !== null) {
223
+ let searchParams = new URLSearchParams(location.search);
224
+ if (searchParams.get("droppermissions") !== null) {
182
225
  args.push(true);
183
226
  }
184
- let requestUrl =
185
- location.origin +
186
- location.pathname +
187
- `?classGuid=RequireController-e2f811f3-14b8-4759-b0d6-73f14516cf1d&functionName=getModules`;
227
+
228
+ let requestUrlBase = location.origin + location.pathname;
229
+ if (domainOrigin) {
230
+ requestUrlBase = domainOrigin;
231
+ }
232
+ let requestUrl = requestUrlBase + `?classGuid=RequireController-e2f811f3-14b8-4759-b0d6-73f14516cf1d&functionName=getModules`;
233
+
188
234
  let remapImportRequestsClientside = globalThis.remapImportRequestsClientside;
189
235
  if (remapImportRequestsClientside) {
190
236
  for (let fnc of remapImportRequestsClientside) {
@@ -192,7 +238,12 @@
192
238
  }
193
239
  }
194
240
  let rawText = await requestText(requestUrl, { args });
195
- let resultObj;
241
+ let resultObj: {
242
+ modules: { [id: string]: SerializedModule };
243
+ requestsResolvedPaths: string[];
244
+ requireSeqNumProcessId: string;
245
+ error?: string;
246
+ };
196
247
  try {
197
248
  resultObj = JSON.parse(rawText);
198
249
  } catch (e) {
@@ -207,13 +258,37 @@
207
258
  throw errorObj;
208
259
  }
209
260
 
261
+
262
+ if (Object.keys(modules).length === 1 && "" in modules) {
263
+ eval(modules[""].source || "");
264
+ throw new Error(`Failed to find modules for ${originalRequests.join(", ")} (mapped to ${requests.join(", ")})`);
265
+ }
266
+
267
+
268
+ if (domainOrigin) {
269
+ function fixDomain(request: string) {
270
+ if (!request) return request;
271
+ return domainOrigin + request;
272
+ }
273
+ requests = requests.map(fixDomain);
274
+ for (let [id, module] of Object.entries(modules)) {
275
+ delete modules[id];
276
+ modules[fixDomain(id)] = module;
277
+ module.filename = fixDomain(module.filename);
278
+ module.requests = Object.fromEntries(Object.entries(module.requests).map(([k, v]) => [k, fixDomain(v)]));
279
+ module.originalId = fixDomain(module.originalId);
280
+ }
281
+ requestsResolvedPaths = requestsResolvedPaths.map(fixDomain);
282
+ }
283
+
284
+
210
285
  for (let i = 0; i < requests.length; i++) {
211
286
  rootResolveCache[requests[i]] = requestsResolvedPaths[i];
212
287
  }
213
288
 
214
289
  // Store the function, so we only call it if it exists BEFORE we import
215
290
  // (which means we already have something loading, so this is likely hot reloading...)
216
- let observerOnHotReload = global.observerOnHotReload;
291
+ let observerOnHotReload = g.observerOnHotReload;
217
292
  setTimeout(() => {
218
293
  if (observerOnHotReload) {
219
294
  observerOnHotReload();
@@ -234,8 +309,9 @@
234
309
  time = Date.now();
235
310
 
236
311
  if (alreadyHave?.requireSeqNumProcessId !== requireSeqNumProcessId) {
237
- alreadyHave = { requireSeqNumProcessId, seqNums: {} };
312
+ alreadyHave = undefined;
238
313
  }
314
+ alreadyHave = alreadyHave || { requireSeqNumProcessId, seqNums: {} };
239
315
 
240
316
  for (let id in modules) {
241
317
  let module = modules[id];
@@ -248,23 +324,22 @@
248
324
  } finally {
249
325
  time = Date.now() - time;
250
326
  console.log(
251
- `%cimport(${requests.join(", ")}) finished evaluate ${time}ms (${moduleCount} modules) at ${
252
- Date.now() - startTime
327
+ `%cimport(${requests.join(", ")}) finished evaluate ${time}ms (${moduleCount} modules) at ${Date.now() - startTime
253
328
  }ms`,
254
329
  "color: lightblue"
255
330
  );
256
331
  }
257
332
  }
258
333
 
259
- function createRequire(module, serializedModule, asyncIsFineOuter) {
334
+ function createRequire(module: ModuleType, serializedModule: SerializedModule, asyncIsFineOuter?: boolean) {
260
335
  require.cache = moduleCache;
261
- require.resolve = function (request) {
336
+ require.resolve = function (request: string) {
262
337
  // TODO: Maybe do a request, making this async, if it isn't found?
263
338
  return serializedModule.requests[request];
264
339
  };
265
340
  let moduleFolder = module.filename.replace(/\\/g, "/").split("/").slice(0, -1).join("/") + "/";
266
341
  return require;
267
- function require(request, asyncIsFine) {
342
+ function require(request: string, asyncIsFine?: boolean) {
268
343
  if (asyncIsFineOuter) {
269
344
  asyncIsFine = true;
270
345
  }
@@ -275,7 +350,7 @@
275
350
  asyncIsFine = true;
276
351
  }
277
352
  if (request in builtInModuleExports) {
278
- return builtInModuleExports[request];
353
+ return builtInModuleExports[request as keyof typeof builtInModuleExports];
279
354
  }
280
355
 
281
356
  let resolvedPath;
@@ -322,7 +397,7 @@
322
397
  return rootRequire(resolvedPath);
323
398
  }
324
399
 
325
- let exportsOverride = undefined;
400
+ let exportsOverride: unknown | undefined;
326
401
  if (resolvedPath === "NOTALLOWEDCLIENTSIDE" || !serializedModules[resolvedPath].allowclient) {
327
402
  let childId = resolvedPath === "NOTALLOWEDCLIENTSIDE" ? request : resolvedPath;
328
403
  if (serializedModules[resolvedPath]?.serveronly) {
@@ -336,7 +411,7 @@
336
411
  if (property === "default") return exportsOverride;
337
412
 
338
413
  throw new Error(
339
- `Module ${childId} is serverside only. Tried to access ${property} from ${module.id}`
414
+ `Module ${childId} is serverside only. Tried to access ${String(property)} from ${module.id}`
340
415
  );
341
416
  },
342
417
  }
@@ -354,8 +429,7 @@
354
429
  console.warn(
355
430
  `Accessed non-whitelisted module %c${childId}%c, specifically property %c${String(
356
431
  property
357
- )}%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 ${
358
- module.id
432
+ )}%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
359
433
  }`,
360
434
  "color: red",
361
435
  "color: unset",
@@ -395,10 +469,10 @@
395
469
  * and has code equal to contents.
396
470
  * - filename is just for debugging / stack traces
397
471
  */
398
- function wrapSafe(filename, contents) {
472
+ function wrapSafe(filename: string, contents: string) {
399
473
  // TODO: Have the serverside inform us of the correct loader, or... have it actually emit a .json loader.
400
474
  if (filename.endsWith(".json")) {
401
- return (exports, require, module) => (module.exports = contents && JSON.parse(contents));
475
+ return (exports: unknown, require: unknown, module: ModuleType) => (module.exports = contents && JSON.parse(contents));
402
476
  }
403
477
 
404
478
  // NOTE: debugName only matters during module evaluation. After that the sourcemap should work.
@@ -419,9 +493,9 @@
419
493
 
420
494
  const unloadedModule = Symbol("unloadedModule");
421
495
 
422
- let currentModuleEvaluationStack = [];
496
+ let currentModuleEvaluationStack: string[] = [];
423
497
  // See https://nodejs.org/api/modules.html
424
- function getModule(resolvedId) {
498
+ function getModule(resolvedId: string) {
425
499
  if (resolvedId === "") {
426
500
  return {};
427
501
  }
@@ -447,7 +521,7 @@
447
521
  module.loaded = true;
448
522
  module.load();
449
523
 
450
- function load(filename) {
524
+ function load() {
451
525
  let serializedModule = serializedModules[resolvedId];
452
526
  if (!module.loaded) {
453
527
  if (alreadyHave) {
@@ -500,11 +574,11 @@
500
574
  {
501
575
  // NOTE: Adding __importStar to the module causes typescript to use our implementation,
502
576
  // which checks for unloadedModule and returns undefined in that case.
503
- __importStar(mod) {
577
+ __importStar(mod: any) {
504
578
  if (mod[unloadedModule]) return undefined;
505
579
  return mod;
506
580
  },
507
- __importDefault(mod) {
581
+ __importDefault(mod: any) {
508
582
  return mod.default ? mod : { default: mod };
509
583
  },
510
584
  },
@@ -529,7 +603,7 @@
529
603
  return module;
530
604
  }
531
605
 
532
- async function requestText(endpoint, values) {
606
+ async function requestText(endpoint: string, values: any) {
533
607
  let url = new URL(endpoint);
534
608
 
535
609
  let json = JSON.stringify(values);
@@ -553,4 +627,4 @@
553
627
  return await response.text();
554
628
  }
555
629
  }
556
- })();
630
+ }