socket-function 0.9.3 → 0.9.5

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 -280
  3. package/SocketFunctionTypes.ts +90 -90
  4. package/hot/HotReloadController.ts +105 -105
  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 +1 -1
  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 +464 -462
  15. package/spec.txt +115 -115
  16. package/src/CallFactory.ts +389 -389
  17. package/src/JSONLACKS/JSONLACKS.generated.js +17 -17
  18. package/src/JSONLACKS/JSONLACKS.pegjs +247 -247
  19. package/src/JSONLACKS/JSONLACKS.ts +441 -429
  20. package/src/args.ts +21 -21
  21. package/src/batching.ts +177 -170
  22. package/src/caching.ts +359 -318
  23. package/src/callHTTPHandler.ts +203 -203
  24. package/src/callManager.ts +134 -134
  25. package/src/certStore.ts +29 -29
  26. package/src/fixLargeNetworkCalls.ts +8 -8
  27. package/src/formatting/colors.ts +78 -78
  28. package/src/formatting/format.ts +160 -160
  29. package/src/formatting/logColors.ts +17 -17
  30. package/src/misc.ts +315 -302
  31. package/src/nodeCache.ts +92 -92
  32. package/src/nodeProxy.ts +54 -54
  33. package/src/profiling/getOwnTime.ts +107 -142
  34. package/src/profiling/measure.ts +289 -273
  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 +254 -250
  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 -52
  45. package/tsconfig.json +26 -26
@@ -1,19 +1,19 @@
1
- /// <reference path=".//RequireController.ts" />
2
- import debugbreak from "debugbreak";
3
- import { compileTransformBefore } from "typenode";
4
-
5
- compileTransformBefore((contents: string, path: string, module: NodeJS.Module): string => {
6
- if (path.endsWith(".css")) {
7
- module.allowclient = true;
8
- function injectCSS(contents: string) {
9
- if (typeof document === "undefined") {
10
- return;
11
- }
12
- let style = document.createElement("style");
13
- style.innerHTML = contents;
14
- document.head.appendChild(style);
15
- }
16
- return `(${injectCSS.toString()})(${JSON.stringify(contents)})`;
17
- }
18
- return contents;
19
- });
1
+ /// <reference path=".//RequireController.ts" />
2
+ import debugbreak from "debugbreak";
3
+ import { compileTransformBefore } from "typenode";
4
+
5
+ compileTransformBefore((contents: string, path: string, module: NodeJS.Module): string => {
6
+ if (path.endsWith(".css")) {
7
+ module.allowclient = true;
8
+ function injectCSS(contents: string) {
9
+ if (typeof document === "undefined") {
10
+ return;
11
+ }
12
+ let style = document.createElement("style");
13
+ style.innerHTML = contents;
14
+ document.head.appendChild(style);
15
+ }
16
+ return `(${injectCSS.toString()})(${JSON.stringify(contents)})`;
17
+ }
18
+ return contents;
19
+ });
@@ -1,253 +1,253 @@
1
- /// <reference path="../../typenode/index.d.ts" />
2
- import debugbreak from "debugbreak";
3
- import fs from "fs";
4
- import { SocketFunction } from "../SocketFunction";
5
- import { setHTTPResultHeaders } from "../src/callHTTPHandler";
6
- import { isNodeTrue } from "../src/misc";
7
-
8
- module.allowclient = true;
9
-
10
- declare global {
11
- namespace NodeJS {
12
- interface Module {
13
- /** Indicates the module is allowed clientside. */
14
- allowclient?: boolean;
15
-
16
- /** Causes the module to not preload, requiring `await import()` for it to load correctly
17
- * - Shouldn't be set recursively, otherwise nested packages will break.
18
- */
19
- lazyload?: boolean;
20
-
21
- /** Indicates the module is definitely not allowed clientside */
22
- serveronly?: boolean;
23
-
24
- // TODO: Move seqNum into the actual compilation, and make it increment,
25
- // so the clientside can properly handle race conditions during hot reloading.
26
- // And... maybe it is useful in other cases?
27
- /** Used internally by RequireController */
28
- requireControllerSeqNum?: number;
29
- }
30
- }
31
- interface Window {
32
- clientsideBootTime: number;
33
- }
34
- }
35
-
36
- export interface SerializedModule {
37
- originalId: string;
38
- filename: string;
39
- // If a module is not allowed clientside it is likely requests will be empty,
40
- // to save effort parsing requests for modules that only exist to give better
41
- // error messages.
42
- requests: {
43
- // request => resolvedPath
44
- [request: string]: string;
45
- };
46
- // NOTE: IF !allowclient && !serveronly, it might just mean we didn't add allowclient
47
- // to the module yet. BUT, if serveronly, then we know for sure we don't want it client.
48
- // So the messages and behavior will be different.
49
- allowclient?: boolean;
50
- serveronly?: boolean;
51
- // Just for errors mostly
52
- alwayssend?: boolean;
53
-
54
- /** Only set if allowclient. */
55
- source?: string;
56
-
57
- seqNum: number;
58
- }
59
-
60
- let nextModuleSeqNum = 1;
61
-
62
- const requireSeqNumProcessId = "requireSeqNumProcessId_" + Date.now() + "_" + Math.random();
63
-
64
- const htmlFile = isNodeTrue() && fs.readFileSync(__dirname + "/require.html").toString();
65
- const jsFile = isNodeTrue() && fs.readFileSync(__dirname + "/require.js").toString();
66
- const bufferShim = isNodeTrue() && fs.readFileSync(__dirname + "/buffer.js").toString();
67
-
68
- const resolvedHTMLFile = isNodeTrue() && (
69
- htmlFile
70
- .replace(`<script src="./buffer.js"></script>`, `<script>${bufferShim}</script>`)
71
- .replace(`<script src="./require.js"></script>`, `<script>${jsFile}</script>`)
72
- );
73
-
74
- class RequireControllerBase {
75
- public rootResolvePath = "";
76
-
77
- public async requireHTML(bootRequirePath?: string) {
78
- let result = resolvedHTMLFile;
79
- if (bootRequirePath) {
80
- result = result.replace(`<!-- ENTRY_TEMPLATE -->`, `<script>require(${JSON.stringify(bootRequirePath)});</script>`);
81
- }
82
- return setHTTPResultHeaders(Buffer.from(result), { "Content-Type": "text/html" });
83
- }
84
-
85
- public async bufferJS() {
86
- return setHTTPResultHeaders(Buffer.from(bufferShim), { "Content-Type": "text/javascript" });
87
- }
88
- public async requireJS() {
89
- return setHTTPResultHeaders(Buffer.from(jsFile), { "Content-Type": "text/javascript" });
90
- }
91
-
92
- public async getModules(
93
- pathRequests: string[],
94
- alreadyHave?: {
95
- requireSeqNumProcessId: string;
96
- // NOTE: Highly optimized, as otherwise this can easily be KBs (I was seeing 9KB),
97
- // which is uploaded, and so can be quite slow on slow connections.
98
- seqNumRanges: {
99
- s: number;
100
- // undefined means s + 1 (so just a single number)
101
- e?: number;
102
- }[];
103
- },
104
- ): Promise<{
105
- requestsResolvedPaths: string[];
106
- modules: {
107
- [resolvedPath: string]: SerializedModule;
108
- };
109
- requireSeqNumProcessId: string;
110
- }> {
111
- let seqNums: { [seqNum: number]: 1 } = {};
112
- if (alreadyHave?.requireSeqNumProcessId === requireSeqNumProcessId) {
113
- for (let { s, e } of alreadyHave.seqNumRanges) {
114
- if (e === undefined) {
115
- e = s + 1;
116
- }
117
- for (let i = s; i < e; i++) {
118
- seqNums[i] = 1;
119
- }
120
- }
121
- }
122
-
123
- let modules: {
124
- [resolvedPath: string]: SerializedModule;
125
- } = Object.create(null);
126
- function addModule(module: NodeJS.Module, rootImport = false) {
127
- if (!rootImport && module.lazyload) return;
128
- if (!module.requireControllerSeqNum) {
129
- module.requireControllerSeqNum = nextModuleSeqNum++;
130
- }
131
- if (seqNums[module.requireControllerSeqNum]) {
132
- return;
133
- }
134
- if (module.filename in modules) return;
135
-
136
- // TODO: Remove unused exports. We know why the module is being requested, so we can
137
- // actually very effectively know which exports it has which will never be used.
138
- // - Of course, we would need to make the module specially, so if any new modules
139
- // use it we can know... what was removed? It becomes complicated with
140
- // lazy modules, but... it is still very important.
141
-
142
- // IMPORTANT! Use module.filename, to strip the ".CLIENT_NAMEPSACE" extension
143
- modules[module.filename] = {
144
- originalId: module.id,
145
- filename: module.filename,
146
- // NOTE: Due to recursive sets of allowclient, it is very possible for allowclient && serveronly to be set.
147
- allowclient: module.allowclient && !module.serveronly,
148
- serveronly: module.serveronly,
149
- requests: Object.create(null),
150
- seqNum: module.requireControllerSeqNum,
151
- };
152
- let moduleObj = modules[module.filename];
153
- if (moduleObj.allowclient) {
154
- moduleObj.source = module.moduleContents;
155
- if (module.filename.endsWith(".json") && !moduleObj.source) {
156
- moduleObj.source = module.moduleContents = fs.readFileSync(module.filename).toString();
157
- }
158
- }
159
-
160
- // NOTE: Iterate on children even if it isn't allowed client, as the module may have children
161
- // that are allowed clientside, and that have side-effects! (Mostly for static resources)
162
- // - Surprisingly, this only increases the returned size by about 8% (probably more like 16%
163
- // if we turn source maps off), so... it's fine. And with compression most of the extra
164
- // size will go away, as paths are highly repetitive.
165
- // - And now it increases the size by much less, as we ignore any subtree which are entirely
166
- // not allowed on the client.
167
- for (let request in module.requires) {
168
- let requireResolvedPath = module.requires[request];
169
- let requiredModule = require.cache[requireResolvedPath];
170
-
171
- if (requiredModule) {
172
- addModule(requiredModule);
173
- moduleObj.requests[request] = requiredModule.filename;
174
- } else {
175
- moduleObj.requests[request] = "";
176
- }
177
- }
178
- }
179
-
180
- let searchPaths: string[] = [];
181
- {
182
- searchPaths.push(this.rootResolvePath);
183
- let pathParts = this.rootResolvePath.replaceAll("\\", "/").split("/");
184
- for (let i = 0; i < pathParts.length; i++) {
185
- // Skip empty path parts, to preventing the case where the path ends
186
- // with a /, which would result in "D:/test//node_modules"
187
- if (!pathParts[i]) continue;
188
- searchPaths.push(pathParts.slice(0, i + 1).join("/") + "/node_modules");
189
- }
190
- }
191
-
192
-
193
- let requestsResolvedPaths: string[] = [];
194
- for (let pathRequest of pathRequests) {
195
- let resolvedPath = "";
196
- try {
197
- resolvedPath = require.resolve(pathRequest, { paths: searchPaths });
198
- } catch { }
199
- requestsResolvedPaths.push(resolvedPath);
200
-
201
- function createNotFoundModule(error: string): NodeJS.Module {
202
- console.warn(error);
203
- return {
204
- exports: {},
205
- children: [],
206
- filename: resolvedPath,
207
- id: resolvedPath,
208
- isPreloading: false,
209
- require: null as any,
210
- loaded: true,
211
- load: null as any,
212
- parent: undefined,
213
- path: "",
214
- paths: [],
215
- requires: {},
216
- allowclient: true,
217
- moduleContents: `console.warn(${JSON.stringify(error)})`,
218
- };
219
- }
220
-
221
- // TODO: We could use import() here... but that would only make the root call asynchronous,
222
- // which wouldn't prevent synchronous blocking by that much anyway...
223
- //require(rootPath);
224
- let clientModule = require.cache[resolvedPath];
225
- if (!clientModule) {
226
- clientModule = createNotFoundModule(`Module ${pathRequest} (resolved to ${JSON.stringify(resolvedPath)}) was not included serverside. Resolve root ${JSON.stringify(this.rootResolvePath)} (set by call to setRequireBootRequire), resolve search paths: ${JSON.stringify(searchPaths)})}`);
227
- }
228
- if (!clientModule.allowclient) {
229
- clientModule = createNotFoundModule(`Module ${pathRequest} (resolved to ${resolvedPath}) is not allowed clientside (set module.allowclient in it, or call setFlag when it is imported).`);
230
- }
231
-
232
- addModule(clientModule, true);
233
- }
234
-
235
- return { requestsResolvedPaths, modules, requireSeqNumProcessId };
236
- }
237
- }
238
-
239
- let baseController = new RequireControllerBase();
240
- export function setRequireBootRequire(path: string) {
241
- baseController.rootResolvePath = path;
242
- }
243
-
244
- export const RequireController = SocketFunction.register(
245
- "RequireController-e2f811f3-14b8-4759-b0d6-73f14516cf1d",
246
- baseController,
247
- () => ({
248
- getModules: {},
249
- requireHTML: {},
250
- bufferJS: {},
251
- requireJS: {},
252
- })
1
+ /// <reference path="../../typenode/index.d.ts" />
2
+ import debugbreak from "debugbreak";
3
+ import fs from "fs";
4
+ import { SocketFunction } from "../SocketFunction";
5
+ import { setHTTPResultHeaders } from "../src/callHTTPHandler";
6
+ import { isNodeTrue } from "../src/misc";
7
+
8
+ module.allowclient = true;
9
+
10
+ declare global {
11
+ namespace NodeJS {
12
+ interface Module {
13
+ /** Indicates the module is allowed clientside. */
14
+ allowclient?: boolean;
15
+
16
+ /** Causes the module to not preload, requiring `await import()` for it to load correctly
17
+ * - Shouldn't be set recursively, otherwise nested packages will break.
18
+ */
19
+ lazyload?: boolean;
20
+
21
+ /** Indicates the module is definitely not allowed clientside */
22
+ serveronly?: boolean;
23
+
24
+ // TODO: Move seqNum into the actual compilation, and make it increment,
25
+ // so the clientside can properly handle race conditions during hot reloading.
26
+ // And... maybe it is useful in other cases?
27
+ /** Used internally by RequireController */
28
+ requireControllerSeqNum?: number;
29
+ }
30
+ }
31
+ interface Window {
32
+ clientsideBootTime: number;
33
+ }
34
+ }
35
+
36
+ export interface SerializedModule {
37
+ originalId: string;
38
+ filename: string;
39
+ // If a module is not allowed clientside it is likely requests will be empty,
40
+ // to save effort parsing requests for modules that only exist to give better
41
+ // error messages.
42
+ requests: {
43
+ // request => resolvedPath
44
+ [request: string]: string;
45
+ };
46
+ // NOTE: IF !allowclient && !serveronly, it might just mean we didn't add allowclient
47
+ // to the module yet. BUT, if serveronly, then we know for sure we don't want it client.
48
+ // So the messages and behavior will be different.
49
+ allowclient?: boolean;
50
+ serveronly?: boolean;
51
+ // Just for errors mostly
52
+ alwayssend?: boolean;
53
+
54
+ /** Only set if allowclient. */
55
+ source?: string;
56
+
57
+ seqNum: number;
58
+ }
59
+
60
+ let nextModuleSeqNum = 1;
61
+
62
+ const requireSeqNumProcessId = "requireSeqNumProcessId_" + Date.now() + "_" + Math.random();
63
+
64
+ const htmlFile = isNodeTrue() && fs.readFileSync(__dirname + "/require.html").toString();
65
+ const jsFile = isNodeTrue() && fs.readFileSync(__dirname + "/require.js").toString();
66
+ const bufferShim = isNodeTrue() && fs.readFileSync(__dirname + "/buffer.js").toString();
67
+
68
+ const resolvedHTMLFile = isNodeTrue() && (
69
+ htmlFile
70
+ .replace(`<script src="./buffer.js"></script>`, `<script>${bufferShim}</script>`)
71
+ .replace(`<script src="./require.js"></script>`, `<script>${jsFile}</script>`)
72
+ );
73
+
74
+ class RequireControllerBase {
75
+ public rootResolvePath = "";
76
+
77
+ public async requireHTML(bootRequirePath?: string) {
78
+ let result = resolvedHTMLFile;
79
+ if (bootRequirePath) {
80
+ result = result.replace(`<!-- ENTRY_TEMPLATE -->`, `<script>require(${JSON.stringify(bootRequirePath)});</script>`);
81
+ }
82
+ return setHTTPResultHeaders(Buffer.from(result), { "Content-Type": "text/html" });
83
+ }
84
+
85
+ public async bufferJS() {
86
+ return setHTTPResultHeaders(Buffer.from(bufferShim), { "Content-Type": "text/javascript" });
87
+ }
88
+ public async requireJS() {
89
+ return setHTTPResultHeaders(Buffer.from(jsFile), { "Content-Type": "text/javascript" });
90
+ }
91
+
92
+ public async getModules(
93
+ pathRequests: string[],
94
+ alreadyHave?: {
95
+ requireSeqNumProcessId: string;
96
+ // NOTE: Highly optimized, as otherwise this can easily be KBs (I was seeing 9KB),
97
+ // which is uploaded, and so can be quite slow on slow connections.
98
+ seqNumRanges: {
99
+ s: number;
100
+ // undefined means s + 1 (so just a single number)
101
+ e?: number;
102
+ }[];
103
+ },
104
+ ): Promise<{
105
+ requestsResolvedPaths: string[];
106
+ modules: {
107
+ [resolvedPath: string]: SerializedModule;
108
+ };
109
+ requireSeqNumProcessId: string;
110
+ }> {
111
+ let seqNums: { [seqNum: number]: 1 } = {};
112
+ if (alreadyHave?.requireSeqNumProcessId === requireSeqNumProcessId) {
113
+ for (let { s, e } of alreadyHave.seqNumRanges) {
114
+ if (e === undefined) {
115
+ e = s + 1;
116
+ }
117
+ for (let i = s; i < e; i++) {
118
+ seqNums[i] = 1;
119
+ }
120
+ }
121
+ }
122
+
123
+ let modules: {
124
+ [resolvedPath: string]: SerializedModule;
125
+ } = Object.create(null);
126
+ function addModule(module: NodeJS.Module, rootImport = false) {
127
+ if (!rootImport && module.lazyload) return;
128
+ if (!module.requireControllerSeqNum) {
129
+ module.requireControllerSeqNum = nextModuleSeqNum++;
130
+ }
131
+ if (seqNums[module.requireControllerSeqNum]) {
132
+ return;
133
+ }
134
+ if (module.filename in modules) return;
135
+
136
+ // TODO: Remove unused exports. We know why the module is being requested, so we can
137
+ // actually very effectively know which exports it has which will never be used.
138
+ // - Of course, we would need to make the module specially, so if any new modules
139
+ // use it we can know... what was removed? It becomes complicated with
140
+ // lazy modules, but... it is still very important.
141
+
142
+ // IMPORTANT! Use module.filename, to strip the ".CLIENT_NAMEPSACE" extension
143
+ modules[module.filename] = {
144
+ originalId: module.id,
145
+ filename: module.filename,
146
+ // NOTE: Due to recursive sets of allowclient, it is very possible for allowclient && serveronly to be set.
147
+ allowclient: module.allowclient && !module.serveronly,
148
+ serveronly: module.serveronly,
149
+ requests: Object.create(null),
150
+ seqNum: module.requireControllerSeqNum,
151
+ };
152
+ let moduleObj = modules[module.filename];
153
+ if (moduleObj.allowclient) {
154
+ moduleObj.source = module.moduleContents;
155
+ if (module.filename.endsWith(".json") && !moduleObj.source) {
156
+ moduleObj.source = module.moduleContents = fs.readFileSync(module.filename).toString();
157
+ }
158
+ }
159
+
160
+ // NOTE: Iterate on children even if it isn't allowed client, as the module may have children
161
+ // that are allowed clientside, and that have side-effects! (Mostly for static resources)
162
+ // - Surprisingly, this only increases the returned size by about 8% (probably more like 16%
163
+ // if we turn source maps off), so... it's fine. And with compression most of the extra
164
+ // size will go away, as paths are highly repetitive.
165
+ // - And now it increases the size by much less, as we ignore any subtree which are entirely
166
+ // not allowed on the client.
167
+ for (let request in module.requires) {
168
+ let requireResolvedPath = module.requires[request];
169
+ let requiredModule = require.cache[requireResolvedPath];
170
+
171
+ if (requiredModule) {
172
+ addModule(requiredModule);
173
+ moduleObj.requests[request] = requiredModule.filename;
174
+ } else {
175
+ moduleObj.requests[request] = "";
176
+ }
177
+ }
178
+ }
179
+
180
+ let searchPaths: string[] = [];
181
+ {
182
+ searchPaths.push(this.rootResolvePath);
183
+ let pathParts = this.rootResolvePath.replaceAll("\\", "/").split("/");
184
+ for (let i = 0; i < pathParts.length; i++) {
185
+ // Skip empty path parts, to preventing the case where the path ends
186
+ // with a /, which would result in "D:/test//node_modules"
187
+ if (!pathParts[i]) continue;
188
+ searchPaths.push(pathParts.slice(0, i + 1).join("/") + "/node_modules");
189
+ }
190
+ }
191
+
192
+
193
+ let requestsResolvedPaths: string[] = [];
194
+ for (let pathRequest of pathRequests) {
195
+ let resolvedPath = "";
196
+ try {
197
+ resolvedPath = require.resolve(pathRequest, { paths: searchPaths });
198
+ } catch { }
199
+ requestsResolvedPaths.push(resolvedPath);
200
+
201
+ function createNotFoundModule(error: string): NodeJS.Module {
202
+ console.warn(error);
203
+ return {
204
+ exports: {},
205
+ children: [],
206
+ filename: resolvedPath,
207
+ id: resolvedPath,
208
+ isPreloading: false,
209
+ require: null as any,
210
+ loaded: true,
211
+ load: null as any,
212
+ parent: undefined,
213
+ path: "",
214
+ paths: [],
215
+ requires: {},
216
+ allowclient: true,
217
+ moduleContents: `console.warn(${JSON.stringify(error)})`,
218
+ };
219
+ }
220
+
221
+ // TODO: We could use import() here... but that would only make the root call asynchronous,
222
+ // which wouldn't prevent synchronous blocking by that much anyway...
223
+ //require(rootPath);
224
+ let clientModule = require.cache[resolvedPath];
225
+ if (!clientModule) {
226
+ clientModule = createNotFoundModule(`Module ${pathRequest} (resolved to ${JSON.stringify(resolvedPath)}) was not included serverside. Resolve root ${JSON.stringify(this.rootResolvePath)} (set by call to setRequireBootRequire), resolve search paths: ${JSON.stringify(searchPaths)})}`);
227
+ }
228
+ if (!clientModule.allowclient) {
229
+ clientModule = createNotFoundModule(`Module ${pathRequest} (resolved to ${resolvedPath}) is not allowed clientside (set module.allowclient in it, or call setFlag when it is imported).`);
230
+ }
231
+
232
+ addModule(clientModule, true);
233
+ }
234
+
235
+ return { requestsResolvedPaths, modules, requireSeqNumProcessId };
236
+ }
237
+ }
238
+
239
+ let baseController = new RequireControllerBase();
240
+ export function setRequireBootRequire(path: string) {
241
+ baseController.rootResolvePath = path;
242
+ }
243
+
244
+ export const RequireController = SocketFunction.register(
245
+ "RequireController-e2f811f3-14b8-4759-b0d6-73f14516cf1d",
246
+ baseController,
247
+ () => ({
248
+ getModules: {},
249
+ requireHTML: {},
250
+ bufferJS: {},
251
+ requireJS: {},
252
+ })
253
253
  );