socket-function 0.116.0 → 0.118.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.
package/SocketFunction.ts CHANGED
@@ -129,7 +129,7 @@ export class SocketFunction {
129
129
  Statics
130
130
  >(
131
131
  classGuid: string,
132
- instance: ClassInstance,
132
+ instance: ClassInstance | (() => ClassInstance),
133
133
  shapeFnc: () => Shape,
134
134
  defaultHooksFnc?: () => SocketExposedShape[""] & {
135
135
  onMount?: () => MaybePromise<void>;
@@ -147,6 +147,7 @@ export class SocketFunction {
147
147
  noFunctionMeasure?: boolean;
148
148
  }
149
149
  ): SocketRegistered<ExtractShape<ClassInstance, Shape>> & Statics {
150
+ let instanceFnc = lazy(typeof instance === "function" ? instance : () => instance);
150
151
  void Promise.resolve().then(() => {
151
152
  let onMount = getDefaultHooks?.().onMount;
152
153
  if (onMount) {
@@ -183,7 +184,7 @@ export class SocketFunction {
183
184
  // by now. This is IMPORTANT, as it allows permissions functions to be moved
184
185
  // to a common module, instead of all being inline.
185
186
  void Promise.resolve().then(() => {
186
- registerClass(classGuid, instance as SocketExposedInterface, getShape(), {
187
+ registerClass(classGuid, instanceFnc() as SocketExposedInterface, getShape(), {
187
188
  noFunctionMeasure: config?.noFunctionMeasure,
188
189
  });
189
190
  });
@@ -1,202 +1,202 @@
1
- /// <reference path="../../typenode/index.d.ts" />
2
- /// <reference path="../require/RequireController.ts" />
3
- module.allowclient = true;
4
-
5
- import { SocketFunction } from "../SocketFunction";
6
- import { cache, lazy } from "../src/caching";
7
- import * as fs from "fs";
8
- import debugbreak from "debugbreak";
9
- import { isNode } from "../src/misc";
10
- import { magenta, red } from "../src/formatting/logColors";
11
- import { formatTime } from "../src/formatting/format";
12
-
13
- /** Enables some hot reload functionality.
14
- * - Triggers a refresh clientside
15
- * - Triggers a reload server, for modules marked with `module.hotreload`
16
- */
17
- export function watchFilesAndTriggerHotReloading(noAutomaticBrowserWatch = false) {
18
- SocketFunction.expose(HotReloadController);
19
- if (!isNode()) {
20
- if (!noAutomaticBrowserWatch) {
21
- HotReloadController.nodes[SocketFunction.browserNodeId()]
22
- .watchFiles()
23
- .catch(e => console.error("watchFiles error", e))
24
- ;
25
- }
26
- }
27
- setInterval(() => {
28
- for (let module of Object.values(require.cache)) {
29
- if (!module) continue;
30
- hotReloadModule(module);
31
- }
32
- }, 5000);
33
- }
34
-
35
- declare global {
36
- namespace NodeJS {
37
- interface Module {
38
- /** Causes us to hotreload the file. Applies both serverside and clientside.
39
- * - If not set for any files clientside, we will refresh.
40
- * - If not set for any files serverside, we will do nothing (and just leave old code running).
41
- */
42
- hotreload?: boolean;
43
- /** Overrides hotreload to disable hot reloading. Useful if you add "hotreload.flag" to a directory
44
- * (which sets hotreload on all files in and under that directory), but want a specific file
45
- * to not hotreload.
46
- * - Also useful if you want files to hotreload clientside, but not serverside.
47
- */
48
- noserverhotreload?: boolean;
49
- }
50
- }
51
- var isHotReloading: (() => boolean) | undefined;
52
- }
53
-
54
- let isHotReloadingValue = false;
55
- export function isHotReloading() {
56
- return isHotReloadingValue;
57
- }
58
- globalThis.isHotReloading = isHotReloading;
59
- export function hotReloadingGuard(): true {
60
- return !isHotReloading() as any;
61
- }
62
- export function setExternalHotReloading(value: boolean) {
63
- isHotReloadingValue = value;
64
- }
65
- let hotReloadCallbacks: ((modules: NodeJS.Module[]) => void)[] = [];
66
- export function onHotReload(callback: (modules: NodeJS.Module[]) => void) {
67
- hotReloadCallbacks.push(callback);
68
- }
69
-
70
- const hotReloadModule = cache((module: NodeJS.Module) => {
71
- if (!module.updateContents) return;
72
- let interval = 1000;
73
- let fast = false;
74
- if (module.hotreload) {
75
- interval = 10;
76
- fast = true;
77
- }
78
- fs.watchFile(module.filename, { persistent: false, interval }, (curr, prev) => {
79
- if (curr.mtime.getTime() === prev.mtime.getTime()) return;
80
- console.log(`Hot reloading due to change: ${module.filename}`);
81
- module.updateContents?.();
82
- if (isNode() && !module.noserverhotreload) {
83
- if (
84
- module.hotreload
85
- // A fairly big hack (as this could just be in a string, or something similar), but... it also VERY useful
86
- || module.moduleContents?.includes("\nmodule.hotreload = true;" + "\n")
87
- || module.moduleContents?.includes("\r\nmodule.hotreload = true;" + "\r\n")
88
- ) {
89
- console.log(`Serverside reloading ${module.id}`);
90
- isHotReloadingValue = true;
91
- try {
92
- module.loaded = false;
93
- module.load(module.id);
94
- } catch (e) {
95
- console.error(red(`Error hot reloading ${module.id}`));
96
- console.error(e);
97
- } finally {
98
- setTimeout(() => {
99
- isHotReloadingValue = false;
100
- }, 1000);
101
- }
102
- }
103
- for (let callback of hotReloadCallbacks) {
104
- callback([module]);
105
- }
106
- }
107
- if (module.allowclient) {
108
- triggerClientSideReload({
109
- files: [module.filename],
110
- changeTime: curr.mtimeMs,
111
- fast,
112
- });
113
- }
114
- });
115
- });
116
- let reloadTriggering = false;
117
- let clientWatcherNodes = new Set<string>();
118
- function triggerClientSideReload(config: {
119
- files: string[];
120
- changeTime: number;
121
- fast?: boolean;
122
- }) {
123
- if (reloadTriggering) return;
124
- reloadTriggering = true;
125
- setTimeout(async () => {
126
- reloadTriggering = false;
127
- for (let clientNodeId of clientWatcherNodes) {
128
- console.log(`Notifying client of hot reload: ${clientNodeId}`);
129
- HotReloadController.nodes[clientNodeId].fileUpdated(config.files, config.changeTime).catch(() => {
130
- console.log(`Removing erroring client: ${clientNodeId}`);
131
- clientWatcherNodes.delete(clientNodeId);
132
- });
133
- }
134
- }, config.fast ? 10 : 300);
135
- }
136
-
137
- class HotReloadControllerBase {
138
- // TODO: Also hot reload when we reconnect to the server, as it is likely setup will need to
139
- // be rerun in that case as well (for example, we need to call watchFiles again!)
140
- async watchFiles() {
141
- let callerId = SocketFunction.getCaller().nodeId;
142
- clientWatcherNodes.add(callerId);
143
- }
144
- async fileUpdated(files: string[], changeTime: number) {
145
- try {
146
- console.groupCollapsed(magenta(`Trigger hotreload for files ${formatTime(Date.now() - changeTime)} after file change`));
147
- for (let file of files) {
148
- console.log(file);
149
- }
150
- console.groupEnd();
151
- let modules: NodeJS.Module[] = [];
152
- for (let file of files) {
153
- file = location.origin + "/" + file;
154
- let module = require.cache[file];
155
- if (!module) {
156
- console.log(`Module not found: ${file}, reloading page to ensure new version is loaded`);
157
- document.location.reload();
158
- return;
159
- }
160
- if (!module.hotreload) {
161
- console.log(`Module not hotreloadable: ${file}, reloading page to ensure new version is loaded`);
162
- document.location.reload();
163
- return;
164
- }
165
- modules.push(module);
166
- }
167
- for (let module of modules) {
168
- module.loaded = false;
169
- }
170
- isHotReloadingValue = true;
171
- try {
172
- await Promise.all(modules.map(module => module.load(module.filename)));
173
- } finally {
174
- setTimeout(() => {
175
- isHotReloadingValue = false;
176
- }, 1000);
177
- }
178
-
179
- for (let callback of hotReloadCallbacks) {
180
- callback(modules);
181
- }
182
- console.log(magenta(`Hot reload complete ${formatTime(Date.now() - changeTime)} after file change`));
183
- } catch (e: any) {
184
- console.error(`Hot reload failed ${e.stack}`);
185
- }
186
- }
187
- }
188
-
189
- export const HotReloadController = SocketFunction.register(
190
- "HotReloadController-032b2250-3aac-4187-8c95-75412742b8f5",
191
- new HotReloadControllerBase(),
192
- () => ({
193
- watchFiles: {},
194
- fileUpdated: {}
195
- }),
196
- () => ({
197
-
198
- }),
199
- {
200
- noAutoExpose: true,
201
- }
1
+ /// <reference path="../../typenode/index.d.ts" />
2
+ /// <reference path="../require/RequireController.ts" />
3
+ module.allowclient = true;
4
+
5
+ import { SocketFunction } from "../SocketFunction";
6
+ import { cache, lazy } from "../src/caching";
7
+ import * as fs from "fs";
8
+ import debugbreak from "debugbreak";
9
+ import { isNode } from "../src/misc";
10
+ import { magenta, red } from "../src/formatting/logColors";
11
+ import { formatTime } from "../src/formatting/format";
12
+
13
+ /** Enables some hot reload functionality.
14
+ * - Triggers a refresh clientside
15
+ * - Triggers a reload server, for modules marked with `module.hotreload`
16
+ */
17
+ export function watchFilesAndTriggerHotReloading(noAutomaticBrowserWatch = false) {
18
+ SocketFunction.expose(HotReloadController);
19
+ if (!isNode()) {
20
+ if (!noAutomaticBrowserWatch) {
21
+ HotReloadController.nodes[SocketFunction.browserNodeId()]
22
+ .watchFiles()
23
+ .catch(e => console.error("watchFiles error", e))
24
+ ;
25
+ }
26
+ }
27
+ setInterval(() => {
28
+ for (let module of Object.values(require.cache)) {
29
+ if (!module) continue;
30
+ hotReloadModule(module);
31
+ }
32
+ }, 5000);
33
+ }
34
+
35
+ declare global {
36
+ namespace NodeJS {
37
+ interface Module {
38
+ /** Causes us to hotreload the file. Applies both serverside and clientside.
39
+ * - If not set for any files clientside, we will refresh.
40
+ * - If not set for any files serverside, we will do nothing (and just leave old code running).
41
+ */
42
+ hotreload?: boolean;
43
+ /** Overrides hotreload to disable hot reloading. Useful if you add "hotreload.flag" to a directory
44
+ * (which sets hotreload on all files in and under that directory), but want a specific file
45
+ * to not hotreload.
46
+ * - Also useful if you want files to hotreload clientside, but not serverside.
47
+ */
48
+ noserverhotreload?: boolean;
49
+ }
50
+ }
51
+ var isHotReloading: (() => boolean) | undefined;
52
+ }
53
+
54
+ let isHotReloadingValue = false;
55
+ export function isHotReloading() {
56
+ return isHotReloadingValue;
57
+ }
58
+ globalThis.isHotReloading = isHotReloading;
59
+ export function hotReloadingGuard(): true {
60
+ return !isHotReloading() as any;
61
+ }
62
+ export function setExternalHotReloading(value: boolean) {
63
+ isHotReloadingValue = value;
64
+ }
65
+ let hotReloadCallbacks: ((modules: NodeJS.Module[]) => void)[] = [];
66
+ export function onHotReload(callback: (modules: NodeJS.Module[]) => void) {
67
+ hotReloadCallbacks.push(callback);
68
+ }
69
+
70
+ const hotReloadModule = cache((module: NodeJS.Module) => {
71
+ if (!module.updateContents) return;
72
+ let interval = 1000;
73
+ let fast = false;
74
+ if (module.hotreload) {
75
+ interval = 10;
76
+ fast = true;
77
+ }
78
+ fs.watchFile(module.filename, { persistent: false, interval }, (curr, prev) => {
79
+ if (curr.mtime.getTime() === prev.mtime.getTime()) return;
80
+ console.log(`Hot reloading due to change: ${module.filename}`);
81
+ module.updateContents?.();
82
+ if (isNode() && !module.noserverhotreload) {
83
+ if (
84
+ module.hotreload
85
+ // A fairly big hack (as this could just be in a string, or something similar), but... it also VERY useful
86
+ || module.moduleContents?.includes("\nmodule.hotreload = true;" + "\n")
87
+ || module.moduleContents?.includes("\r\nmodule.hotreload = true;" + "\r\n")
88
+ ) {
89
+ console.log(`Serverside reloading ${module.id}`);
90
+ isHotReloadingValue = true;
91
+ try {
92
+ module.loaded = false;
93
+ module.load(module.id);
94
+ } catch (e) {
95
+ console.error(red(`Error hot reloading ${module.id}`));
96
+ console.error(e);
97
+ } finally {
98
+ setTimeout(() => {
99
+ isHotReloadingValue = false;
100
+ }, 1000);
101
+ }
102
+ }
103
+ for (let callback of hotReloadCallbacks) {
104
+ callback([module]);
105
+ }
106
+ }
107
+ if (module.allowclient) {
108
+ triggerClientSideReload({
109
+ files: [module.filename],
110
+ changeTime: curr.mtimeMs,
111
+ fast,
112
+ });
113
+ }
114
+ });
115
+ });
116
+ let reloadTriggering = false;
117
+ let clientWatcherNodes = new Set<string>();
118
+ function triggerClientSideReload(config: {
119
+ files: string[];
120
+ changeTime: number;
121
+ fast?: boolean;
122
+ }) {
123
+ if (reloadTriggering) return;
124
+ reloadTriggering = true;
125
+ setTimeout(async () => {
126
+ reloadTriggering = false;
127
+ for (let clientNodeId of clientWatcherNodes) {
128
+ console.log(`Notifying client of hot reload: ${clientNodeId}`);
129
+ HotReloadController.nodes[clientNodeId].fileUpdated(config.files, config.changeTime).catch(() => {
130
+ console.log(`Removing erroring client: ${clientNodeId}`);
131
+ clientWatcherNodes.delete(clientNodeId);
132
+ });
133
+ }
134
+ }, config.fast ? 10 : 300);
135
+ }
136
+
137
+ class HotReloadControllerBase {
138
+ // TODO: Also hot reload when we reconnect to the server, as it is likely setup will need to
139
+ // be rerun in that case as well (for example, we need to call watchFiles again!)
140
+ async watchFiles() {
141
+ let callerId = SocketFunction.getCaller().nodeId;
142
+ clientWatcherNodes.add(callerId);
143
+ }
144
+ async fileUpdated(files: string[], changeTime: number) {
145
+ try {
146
+ console.groupCollapsed(magenta(`Trigger hotreload for files ${formatTime(Date.now() - changeTime)} after file change`));
147
+ for (let file of files) {
148
+ console.log(file);
149
+ }
150
+ console.groupEnd();
151
+ let modules: NodeJS.Module[] = [];
152
+ for (let file of files) {
153
+ file = "https://" + (BOOTED_EDGE_NODE?.host || location.host) + "/" + file;
154
+ let module = require.cache[file];
155
+ if (!module) {
156
+ console.log(`Module not found: ${file}, reloading page to ensure new version is loaded`);
157
+ document.location.reload();
158
+ return;
159
+ }
160
+ if (!module.hotreload) {
161
+ console.log(`Module not hotreloadable: ${file}, reloading page to ensure new version is loaded`);
162
+ document.location.reload();
163
+ return;
164
+ }
165
+ modules.push(module);
166
+ }
167
+ for (let module of modules) {
168
+ module.loaded = false;
169
+ }
170
+ isHotReloadingValue = true;
171
+ try {
172
+ await Promise.all(modules.map(module => module.load(module.filename)));
173
+ } finally {
174
+ setTimeout(() => {
175
+ isHotReloadingValue = false;
176
+ }, 1000);
177
+ }
178
+
179
+ for (let callback of hotReloadCallbacks) {
180
+ callback(modules);
181
+ }
182
+ console.log(magenta(`Hot reload complete ${formatTime(Date.now() - changeTime)} after file change`));
183
+ } catch (e: any) {
184
+ console.error(`Hot reload failed ${e.stack}`);
185
+ }
186
+ }
187
+ }
188
+
189
+ export const HotReloadController = SocketFunction.register(
190
+ "HotReloadController-032b2250-3aac-4187-8c95-75412742b8f5",
191
+ new HotReloadControllerBase(),
192
+ () => ({
193
+ watchFiles: {},
194
+ fileUpdated: {}
195
+ }),
196
+ () => ({
197
+
198
+ }),
199
+ {
200
+ noAutoExpose: true,
201
+ }
202
202
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "socket-function",
3
- "version": "0.116.0",
3
+ "version": "0.118.0",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {