querysub 0.433.0 → 0.436.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/.eslintrc.js +50 -50
- package/bin/deploy.js +0 -0
- package/bin/function.js +0 -0
- package/bin/server.js +0 -0
- package/costsBenefits.txt +115 -115
- package/deploy.ts +2 -2
- package/package.json +1 -1
- package/spec.txt +1192 -1192
- package/src/-a-archives/archives.ts +202 -202
- package/src/-a-archives/archivesBackBlaze.ts +1 -0
- package/src/-a-archives/archivesDisk.ts +454 -454
- package/src/-a-auth/certs.ts +540 -540
- package/src/-a-auth/node-forge-ed25519.d.ts +16 -16
- package/src/-b-authorities/dnsAuthority.ts +138 -138
- package/src/-c-identity/IdentityController.ts +258 -258
- package/src/-d-trust/NetworkTrust2.ts +180 -180
- package/src/-e-certs/EdgeCertController.ts +252 -252
- package/src/-e-certs/certAuthority.ts +201 -201
- package/src/-f-node-discovery/NodeDiscovery.ts +640 -640
- package/src/-g-core-values/NodeCapabilities.ts +200 -200
- package/src/-h-path-value-serialize/stringSerializer.ts +175 -175
- package/src/0-path-value-core/PathValueCommitter.ts +468 -468
- package/src/0-path-value-core/pathValueCore.ts +2 -2
- package/src/2-proxy/PathValueProxyWatcher.ts +2542 -2542
- package/src/2-proxy/TransactionDelayer.ts +94 -94
- package/src/2-proxy/pathDatabaseProxyBase.ts +36 -36
- package/src/2-proxy/pathValueProxy.ts +159 -159
- package/src/3-path-functions/PathFunctionRunnerMain.ts +87 -87
- package/src/3-path-functions/pathFunctionLoader.ts +516 -516
- package/src/3-path-functions/tests/rejectTest.ts +76 -76
- package/src/4-deploy/deployCheck.ts +6 -6
- package/src/4-dom/css.tsx +29 -29
- package/src/4-dom/cssTypes.d.ts +211 -211
- package/src/4-dom/qreact.tsx +2799 -2799
- package/src/4-dom/qreactTest.tsx +410 -410
- package/src/4-querysub/permissions.ts +335 -335
- package/src/4-querysub/querysubPrediction.ts +483 -483
- package/src/5-diagnostics/qreactDebug.tsx +346 -346
- package/src/TestController.ts +34 -34
- package/src/bits.ts +104 -104
- package/src/buffers.ts +69 -69
- package/src/diagnostics/ActionsHistory.ts +57 -57
- package/src/diagnostics/listenOnDebugger.ts +71 -71
- package/src/diagnostics/periodic.ts +111 -111
- package/src/diagnostics/trackResources.ts +91 -91
- package/src/diagnostics/watchdog.ts +120 -120
- package/src/errors.ts +133 -133
- package/src/forceProduction.ts +2 -2
- package/src/fs.ts +80 -80
- package/src/functional/diff.ts +857 -857
- package/src/functional/promiseCache.ts +78 -78
- package/src/functional/random.ts +8 -8
- package/src/functional/stats.ts +60 -60
- package/src/heapDumps.ts +665 -665
- package/src/https.ts +1 -1
- package/src/library-components/AspectSizedComponent.tsx +87 -87
- package/src/library-components/ButtonSelector.tsx +64 -64
- package/src/library-components/DropdownCustom.tsx +150 -150
- package/src/library-components/DropdownSelector.tsx +31 -31
- package/src/library-components/InlinePopup.tsx +66 -66
- package/src/misc/color.ts +29 -29
- package/src/misc/hash.ts +83 -83
- package/src/misc/ipPong.js +13 -13
- package/src/misc/networking.ts +1 -1
- package/src/misc/random.ts +44 -44
- package/src/misc.ts +196 -196
- package/src/path.ts +255 -255
- package/src/persistentLocalStore.ts +41 -41
- package/src/promise.ts +14 -14
- package/src/storage/fileSystemPointer.ts +71 -71
- package/src/test/heapProcess.ts +35 -35
- package/src/zip.ts +15 -15
- package/tsconfig.json +26 -26
- package/yarnSpec.txt +56 -56
package/src/4-dom/qreactTest.tsx
CHANGED
|
@@ -1,411 +1,411 @@
|
|
|
1
|
-
import { disableMeasurements, measureBlock, measureCode } from "socket-function/src/profiling/measure";
|
|
2
|
-
disableMeasurements();
|
|
3
|
-
|
|
4
|
-
import preact from "preact";
|
|
5
|
-
import { isNode, list } from "socket-function/src/misc";
|
|
6
|
-
import { ClientWatcher, clientWatcher } from "../1-path-client/pathValueClientWatcher";
|
|
7
|
-
import { isDeploy } from "../4-deploy/deployCheck";
|
|
8
|
-
import { logErrors } from "../errors";
|
|
9
|
-
import { watchFilesAndTriggerHotReloading } from "socket-function/hot/HotReloadController";
|
|
10
|
-
import { qreact } from "./qreact";
|
|
11
|
-
import { Querysub } from "../4-querysub/QuerysubController";
|
|
12
|
-
import { PermissionsCheck } from "../4-querysub/permissions";
|
|
13
|
-
import { delay } from "socket-function/src/batching";
|
|
14
|
-
import { formatTime } from "socket-function/src/formatting/format";
|
|
15
|
-
import { getPathFromStr } from "../path";
|
|
16
|
-
import { css } from "./css";
|
|
17
|
-
import { isSuperUserPERMISSIONS } from "../user-implementation/userData";
|
|
18
|
-
import { authorityLookup } from "../0-path-value-core/AuthorityLookup";
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
async function main() {
|
|
23
|
-
if (!isNode()) return;
|
|
24
|
-
if (isDeploy()) return;
|
|
25
|
-
if (module.hotreload) return;
|
|
26
|
-
const edgePort = 15060;
|
|
27
|
-
PermissionsCheck.DEBUG = true;
|
|
28
|
-
ClientWatcher.DEBUG_READS = true;
|
|
29
|
-
ClientWatcher.DEBUG_WRITES = true;
|
|
30
|
-
//debugCoreMode();
|
|
31
|
-
|
|
32
|
-
//SocketFunction.silent = false;
|
|
33
|
-
Error.stackTraceLimit = 20;
|
|
34
|
-
|
|
35
|
-
await Querysub.hostServer({
|
|
36
|
-
trustedDomains: ["querysub.com"],
|
|
37
|
-
port: edgePort,
|
|
38
|
-
rootPath: __dirname + "/../../",
|
|
39
|
-
clientsideEntryPoint: "./src/4-dom/qreactTest.tsx",
|
|
40
|
-
hotReload: true,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
class Nested extends qreact.Component<{
|
|
45
|
-
value: unknown;
|
|
46
|
-
}> {
|
|
47
|
-
render() {
|
|
48
|
-
return (
|
|
49
|
-
<>
|
|
50
|
-
value = {this.props.value}, {this.props.value}
|
|
51
|
-
<div>
|
|
52
|
-
{String(this.props.value)}
|
|
53
|
-
</div>
|
|
54
|
-
</>
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
class DynamicComponent extends qreact.Component<{
|
|
60
|
-
propValue: unknown;
|
|
61
|
-
}> {
|
|
62
|
-
state = {
|
|
63
|
-
value: "state",
|
|
64
|
-
noRoot: false,
|
|
65
|
-
children: {} as {
|
|
66
|
-
[num: number | string]: {
|
|
67
|
-
value: string;
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
nextChild: 0,
|
|
71
|
-
};
|
|
72
|
-
render() {
|
|
73
|
-
let base = <>
|
|
74
|
-
<div>Prop value {this.props.propValue}</div>
|
|
75
|
-
<div>State value <input value={this.state.value} onChange={e => this.state.value = e.currentTarget.value} /> = {this.state.value}</div>
|
|
76
|
-
<div>
|
|
77
|
-
No div root <input type="checkbox" checked={this.state.noRoot} onChange={e => this.state.noRoot = e.currentTarget.checked} />
|
|
78
|
-
</div>
|
|
79
|
-
<div>
|
|
80
|
-
<div>Children</div>
|
|
81
|
-
<button onClick={() => {
|
|
82
|
-
let nextChild = this.state.nextChild++;
|
|
83
|
-
this.state.children[nextChild] = { value: "prop" + nextChild, };
|
|
84
|
-
}}>
|
|
85
|
-
Add child
|
|
86
|
-
</button>
|
|
87
|
-
{Object.entries(this.state.children).map(([key, obj]) =>
|
|
88
|
-
<div class={css.marginLeft(10).hsla(200, 75, 75, 0.2)}>
|
|
89
|
-
<button onClick={() => delete this.state.children[key]}>Remove child</button>
|
|
90
|
-
<div>
|
|
91
|
-
Child prop: <input value={obj.value} onChange={e => obj.value = e.currentTarget.value} />
|
|
92
|
-
</div>
|
|
93
|
-
<DynamicComponent propValue={obj.value} />
|
|
94
|
-
</div>
|
|
95
|
-
)}
|
|
96
|
-
</div>
|
|
97
|
-
</>;
|
|
98
|
-
if (!this.state.noRoot) {
|
|
99
|
-
base = <div class={css.pad(10).hsla(160, 75, 75, 0.5)}>{base}</div>;
|
|
100
|
-
}
|
|
101
|
-
return base;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
class ValueRender extends qreact.Component<{
|
|
106
|
-
x: { value: number };
|
|
107
|
-
}> {
|
|
108
|
-
render() {
|
|
109
|
-
return (
|
|
110
|
-
<div>
|
|
111
|
-
x = {this.props.x.value}
|
|
112
|
-
<button onClick={() => this.props.x.value++}>Test</button>
|
|
113
|
-
<input type="number" value={this.props.x.value} onInput={e => this.props.x.value = e.currentTarget.valueAsNumber} />
|
|
114
|
-
</div>
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
class Intermediate extends qreact.Component<{
|
|
120
|
-
x: { value: number };
|
|
121
|
-
}> {
|
|
122
|
-
render() {
|
|
123
|
-
return (
|
|
124
|
-
<ValueRender x={this.props.x} />
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
class CircleComponent extends qreact.Component {
|
|
130
|
-
render() {
|
|
131
|
-
return (
|
|
132
|
-
<circle cx={200} cy={50} r={50} fill="red" />
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
class Test extends qreact.Component {
|
|
138
|
-
state = {
|
|
139
|
-
valueValue: { value: 0 },
|
|
140
|
-
};
|
|
141
|
-
render() {
|
|
142
|
-
return (
|
|
143
|
-
<div>
|
|
144
|
-
<button onClick={() => this.state.valueValue.value++}>Increment</button>
|
|
145
|
-
<div>Value = {this.state.valueValue.value}</div>
|
|
146
|
-
<Intermediate x={{ value: this.state.valueValue.value }} />
|
|
147
|
-
|
|
148
|
-
<svg>
|
|
149
|
-
<circle cx={100} cy={100} r={50} fill="red" />
|
|
150
|
-
<CircleComponent />
|
|
151
|
-
</svg>
|
|
152
|
-
</div>
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
class Benchmark1 extends qreact.Component<{
|
|
158
|
-
count: number;
|
|
159
|
-
}> {
|
|
160
|
-
render() {
|
|
161
|
-
return (
|
|
162
|
-
<div>
|
|
163
|
-
{list(this.props.count).map(i => <div>{i}</div>)}
|
|
164
|
-
</div>
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
class Benchmark2 extends qreact.Component<{
|
|
169
|
-
count: number;
|
|
170
|
-
}> {
|
|
171
|
-
render() {
|
|
172
|
-
return (
|
|
173
|
-
list(this.props.count).map(i => <div>{i}</div>)
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
class SmallNested extends qreact.Component<{
|
|
180
|
-
obj: { value: number };
|
|
181
|
-
}> {
|
|
182
|
-
render() {
|
|
183
|
-
return (
|
|
184
|
-
<div />
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
class Benchmark3 extends qreact.Component<{
|
|
189
|
-
count: number;
|
|
190
|
-
}> {
|
|
191
|
-
render() {
|
|
192
|
-
return (
|
|
193
|
-
list(this.props.count).map(i => <SmallNested obj={{ value: i }} />)
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
class SmallNested2 extends qreact.Component<{
|
|
199
|
-
obj: { value: number };
|
|
200
|
-
}> {
|
|
201
|
-
render() {
|
|
202
|
-
return (
|
|
203
|
-
<div class={css.flex.gap(10).wrap} onClick={() => this.props.obj.value++}>
|
|
204
|
-
{this.props.obj.value}
|
|
205
|
-
<img src="/widgets/HTML5Video/video-thumbnail.jpg" />
|
|
206
|
-
</div>
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
class Benchmark3p5 extends qreact.Component<{
|
|
211
|
-
count: number;
|
|
212
|
-
}> {
|
|
213
|
-
render() {
|
|
214
|
-
return (
|
|
215
|
-
list(this.props.count).map(i => <SmallNested2 obj={{ value: i }} />)
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
class Benchmark4 extends qreact.Component<{
|
|
221
|
-
count: number;
|
|
222
|
-
}> {
|
|
223
|
-
render() {
|
|
224
|
-
return (
|
|
225
|
-
<div class={css.flex.wrap}>
|
|
226
|
-
{list(this.props.count).map(i =>
|
|
227
|
-
<img src="/widgets/HTML5Video/video-thumbnail.jpg" />
|
|
228
|
-
)}
|
|
229
|
-
</div>
|
|
230
|
-
);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
async function browserMain() {
|
|
237
|
-
if (isNode()) return;
|
|
238
|
-
watchFilesAndTriggerHotReloading();
|
|
239
|
-
|
|
240
|
-
// NOTE: Annoying, but qreact can't emulate the special minified keys preact uses
|
|
241
|
-
qreact.createElement = preact.createElement as any;
|
|
242
|
-
qreact.Fragment = preact.Fragment as any;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
//ClientWatcher.DEBUG_READS = true;
|
|
246
|
-
//ClientWatcher.DEBUG_READS_EXPANDED = true;
|
|
247
|
-
//ClientWatcher.DEBUG_WRITES = true;
|
|
248
|
-
//ClientWatcher.DEBUG_WRITES_EXPANDED = true;
|
|
249
|
-
//Querysub.DEBUG_CALLS = true;
|
|
250
|
-
//PathValueProxyWatcher.TRACE = true;
|
|
251
|
-
//ClientWatcher.DEBUG_TRIGGERS = "light";
|
|
252
|
-
//ClientWatcher.DEBUG_TRIGGERS = "heavy";
|
|
253
|
-
//qreact.debug();
|
|
254
|
-
|
|
255
|
-
//preact.render(<Test />, document.getElementById("main")!);
|
|
256
|
-
//qreact.render(<DynamicComponent propValue={1} />, document.getElementById("main")!);
|
|
257
|
-
//qreact.render(<SyncedTest propValue={1} />, document.getElementById("main")!);
|
|
258
|
-
|
|
259
|
-
//*
|
|
260
|
-
await new Promise(resolve => setTimeout(resolve, 0));
|
|
261
|
-
await authorityLookup.startSyncing();
|
|
262
|
-
|
|
263
|
-
let benchmarkComponents = [
|
|
264
|
-
// ONLY run with devtools closed AND disableMeasurements (at the top of the file)! Otherwise the timings will be wrong.
|
|
265
|
-
// qreact is 3X slower
|
|
266
|
-
() => <Benchmark1 count={10000} />,
|
|
267
|
-
// qreact is 3X slower
|
|
268
|
-
() => <Benchmark2 count={10000} />,
|
|
269
|
-
// qreact is 30X slower
|
|
270
|
-
() => <Benchmark3 count={1000} />,
|
|
271
|
-
// qreact is 10X slower
|
|
272
|
-
() => <Benchmark3p5 count={1000} />,
|
|
273
|
-
// qreact is 1.5X slower
|
|
274
|
-
() => <Benchmark4 count={1000} />,
|
|
275
|
-
];
|
|
276
|
-
|
|
277
|
-
await measureCode(async function renderTest() {
|
|
278
|
-
const main = document.getElementById("main")!;
|
|
279
|
-
async function reset() {
|
|
280
|
-
main.replaceChildren();
|
|
281
|
-
await delay(0);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
for (let componentFactory of benchmarkComponents) {
|
|
285
|
-
let component = componentFactory();
|
|
286
|
-
let name = (component.type as any).name;
|
|
287
|
-
|
|
288
|
-
await reset();
|
|
289
|
-
let time = Date.now();
|
|
290
|
-
preact.render(component, main);
|
|
291
|
-
time = Date.now() - time;
|
|
292
|
-
preact.render(<div />, main);
|
|
293
|
-
console.log(`preact|${name} took ${formatTime(time)}`);
|
|
294
|
-
|
|
295
|
-
await reset();
|
|
296
|
-
time = Date.now();
|
|
297
|
-
await measureBlock(async () => {
|
|
298
|
-
qreact.render(component, main);
|
|
299
|
-
await clientWatcher.waitForTriggerFinished();
|
|
300
|
-
qreact.render(<div />, main);
|
|
301
|
-
await clientWatcher.waitForTriggerFinished();
|
|
302
|
-
}, "qreact|" + name);
|
|
303
|
-
time = Date.now() - time;
|
|
304
|
-
console.log(`qreact|${name} took ${formatTime(time)}`);
|
|
305
|
-
|
|
306
|
-
qreact.render(<div>done</div>, main);
|
|
307
|
-
}
|
|
308
|
-
}, { minTimeToLog: 0, thresholdInTable: 0 });
|
|
309
|
-
//*/
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
logErrors(main());
|
|
313
|
-
logErrors(browserMain());
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
let { data, functions } = Querysub.createSchema<{
|
|
317
|
-
values: {
|
|
318
|
-
[key: string]: string;
|
|
319
|
-
};
|
|
320
|
-
}>()({
|
|
321
|
-
domainName: "querysub.com",
|
|
322
|
-
functions: {
|
|
323
|
-
setValue(key: string, value: string) {
|
|
324
|
-
data().values[key] = value;
|
|
325
|
-
}
|
|
326
|
-
},
|
|
327
|
-
module,
|
|
328
|
-
moduleId: "qreactTest",
|
|
329
|
-
functionMetadata: {},
|
|
330
|
-
permissions: {
|
|
331
|
-
PERMISSIONS: isSuperUserPERMISSIONS
|
|
332
|
-
}
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
class SyncTest extends qreact.Component {
|
|
336
|
-
render() {
|
|
337
|
-
return (
|
|
338
|
-
<div>
|
|
339
|
-
<div>Regular <input value={data().values["a"]} onChange={e => functions.setValue("a", e.currentTarget.value)} /></div>
|
|
340
|
-
<div>Hot <input value={data().values["b"]} onInput={e => functions.setValue("b", e.currentTarget.value)} /></div>
|
|
341
|
-
<div>
|
|
342
|
-
Trigger sources {Array.from(Querysub.getTriggerReason()?.pathSources || []).map(x =>
|
|
343
|
-
<div>
|
|
344
|
-
{getPathFromStr(x.path).join(".")}
|
|
345
|
-
{x.source && <div class={css.marginLeft(10)}>{x.source}</div>}
|
|
346
|
-
</div>
|
|
347
|
-
)}
|
|
348
|
-
</div>
|
|
349
|
-
</div>
|
|
350
|
-
);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/*
|
|
355
|
-
async function browserMain2() {
|
|
356
|
-
if (isNode()) return;
|
|
357
|
-
|
|
358
|
-
watchFilesAndTriggerHotReloading();
|
|
359
|
-
|
|
360
|
-
Querysub.DEBUG_CALLS = true;
|
|
361
|
-
ClientWatcher.DEBUG_TRIGGERS = "heavy";
|
|
362
|
-
qreact.debug();
|
|
363
|
-
|
|
364
|
-
qreact.render(preact.createElement(SyncTest, {}), document.getElementById("main")!);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
async function main2() {
|
|
368
|
-
if (!isNode()) return;
|
|
369
|
-
if (isDeploy()) return;
|
|
370
|
-
if (module.hotreload) return;
|
|
371
|
-
const edgePort = 15060;
|
|
372
|
-
PermissionsCheck.DEBUG = true;
|
|
373
|
-
ClientWatcher.DEBUG_READS = true;
|
|
374
|
-
ClientWatcher.DEBUG_WRITES = true;
|
|
375
|
-
|
|
376
|
-
//SocketFunction.silent = false;
|
|
377
|
-
Error.stackTraceLimit = 20;
|
|
378
|
-
|
|
379
|
-
await Querysub.hostServer({
|
|
380
|
-
trustedDomains: ["querysub.com"],
|
|
381
|
-
port: edgePort,
|
|
382
|
-
rootPath: __dirname + "/../../",
|
|
383
|
-
clientsideEntryPoint: "./src/4-dom/qreactTest.tsx",
|
|
384
|
-
hotReload: true,
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
module.hotreload = isNode() && process.argv[1].includes("PathFunctionRunnerMain.ts");
|
|
389
|
-
module.noserverhotreload = false;
|
|
390
|
-
|
|
391
|
-
logErrors(main2());
|
|
392
|
-
logErrors(browserMain2());
|
|
393
|
-
*/
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
// async function main3() {
|
|
397
|
-
// let test = await proxyWatcher.dryRun({
|
|
398
|
-
// canWrite: true,
|
|
399
|
-
// watchFunction() {
|
|
400
|
-
// schema()["querysub.com"].rejectTest.value = 2;
|
|
401
|
-
// },
|
|
402
|
-
// });
|
|
403
|
-
// let buffer = await pathValueSerializer.serialize(test!);
|
|
404
|
-
// let test2 = await pathValueSerializer.deserialize(buffer);
|
|
405
|
-
// debugger;
|
|
406
|
-
// }
|
|
407
|
-
|
|
408
|
-
// main3().catch(e => console.error(e)).finally(() => process.exit());
|
|
409
|
-
|
|
410
|
-
|
|
1
|
+
import { disableMeasurements, measureBlock, measureCode } from "socket-function/src/profiling/measure";
|
|
2
|
+
disableMeasurements();
|
|
3
|
+
|
|
4
|
+
import preact from "preact";
|
|
5
|
+
import { isNode, list } from "socket-function/src/misc";
|
|
6
|
+
import { ClientWatcher, clientWatcher } from "../1-path-client/pathValueClientWatcher";
|
|
7
|
+
import { isDeploy } from "../4-deploy/deployCheck";
|
|
8
|
+
import { logErrors } from "../errors";
|
|
9
|
+
import { watchFilesAndTriggerHotReloading } from "socket-function/hot/HotReloadController";
|
|
10
|
+
import { qreact } from "./qreact";
|
|
11
|
+
import { Querysub } from "../4-querysub/QuerysubController";
|
|
12
|
+
import { PermissionsCheck } from "../4-querysub/permissions";
|
|
13
|
+
import { delay } from "socket-function/src/batching";
|
|
14
|
+
import { formatTime } from "socket-function/src/formatting/format";
|
|
15
|
+
import { getPathFromStr } from "../path";
|
|
16
|
+
import { css } from "./css";
|
|
17
|
+
import { isSuperUserPERMISSIONS } from "../user-implementation/userData";
|
|
18
|
+
import { authorityLookup } from "../0-path-value-core/AuthorityLookup";
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
async function main() {
|
|
23
|
+
if (!isNode()) return;
|
|
24
|
+
if (isDeploy()) return;
|
|
25
|
+
if (module.hotreload) return;
|
|
26
|
+
const edgePort = 15060;
|
|
27
|
+
PermissionsCheck.DEBUG = true;
|
|
28
|
+
ClientWatcher.DEBUG_READS = true;
|
|
29
|
+
ClientWatcher.DEBUG_WRITES = true;
|
|
30
|
+
//debugCoreMode();
|
|
31
|
+
|
|
32
|
+
//SocketFunction.silent = false;
|
|
33
|
+
Error.stackTraceLimit = 20;
|
|
34
|
+
|
|
35
|
+
await Querysub.hostServer({
|
|
36
|
+
trustedDomains: ["querysub.com"],
|
|
37
|
+
port: edgePort,
|
|
38
|
+
rootPath: __dirname + "/../../",
|
|
39
|
+
clientsideEntryPoint: "./src/4-dom/qreactTest.tsx",
|
|
40
|
+
hotReload: true,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class Nested extends qreact.Component<{
|
|
45
|
+
value: unknown;
|
|
46
|
+
}> {
|
|
47
|
+
render() {
|
|
48
|
+
return (
|
|
49
|
+
<>
|
|
50
|
+
value = {this.props.value}, {this.props.value}
|
|
51
|
+
<div>
|
|
52
|
+
{String(this.props.value)}
|
|
53
|
+
</div>
|
|
54
|
+
</>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
class DynamicComponent extends qreact.Component<{
|
|
60
|
+
propValue: unknown;
|
|
61
|
+
}> {
|
|
62
|
+
state = {
|
|
63
|
+
value: "state",
|
|
64
|
+
noRoot: false,
|
|
65
|
+
children: {} as {
|
|
66
|
+
[num: number | string]: {
|
|
67
|
+
value: string;
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
nextChild: 0,
|
|
71
|
+
};
|
|
72
|
+
render() {
|
|
73
|
+
let base = <>
|
|
74
|
+
<div>Prop value {this.props.propValue}</div>
|
|
75
|
+
<div>State value <input value={this.state.value} onChange={e => this.state.value = e.currentTarget.value} /> = {this.state.value}</div>
|
|
76
|
+
<div>
|
|
77
|
+
No div root <input type="checkbox" checked={this.state.noRoot} onChange={e => this.state.noRoot = e.currentTarget.checked} />
|
|
78
|
+
</div>
|
|
79
|
+
<div>
|
|
80
|
+
<div>Children</div>
|
|
81
|
+
<button onClick={() => {
|
|
82
|
+
let nextChild = this.state.nextChild++;
|
|
83
|
+
this.state.children[nextChild] = { value: "prop" + nextChild, };
|
|
84
|
+
}}>
|
|
85
|
+
Add child
|
|
86
|
+
</button>
|
|
87
|
+
{Object.entries(this.state.children).map(([key, obj]) =>
|
|
88
|
+
<div class={css.marginLeft(10).hsla(200, 75, 75, 0.2)}>
|
|
89
|
+
<button onClick={() => delete this.state.children[key]}>Remove child</button>
|
|
90
|
+
<div>
|
|
91
|
+
Child prop: <input value={obj.value} onChange={e => obj.value = e.currentTarget.value} />
|
|
92
|
+
</div>
|
|
93
|
+
<DynamicComponent propValue={obj.value} />
|
|
94
|
+
</div>
|
|
95
|
+
)}
|
|
96
|
+
</div>
|
|
97
|
+
</>;
|
|
98
|
+
if (!this.state.noRoot) {
|
|
99
|
+
base = <div class={css.pad(10).hsla(160, 75, 75, 0.5)}>{base}</div>;
|
|
100
|
+
}
|
|
101
|
+
return base;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
class ValueRender extends qreact.Component<{
|
|
106
|
+
x: { value: number };
|
|
107
|
+
}> {
|
|
108
|
+
render() {
|
|
109
|
+
return (
|
|
110
|
+
<div>
|
|
111
|
+
x = {this.props.x.value}
|
|
112
|
+
<button onClick={() => this.props.x.value++}>Test</button>
|
|
113
|
+
<input type="number" value={this.props.x.value} onInput={e => this.props.x.value = e.currentTarget.valueAsNumber} />
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
class Intermediate extends qreact.Component<{
|
|
120
|
+
x: { value: number };
|
|
121
|
+
}> {
|
|
122
|
+
render() {
|
|
123
|
+
return (
|
|
124
|
+
<ValueRender x={this.props.x} />
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
class CircleComponent extends qreact.Component {
|
|
130
|
+
render() {
|
|
131
|
+
return (
|
|
132
|
+
<circle cx={200} cy={50} r={50} fill="red" />
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
class Test extends qreact.Component {
|
|
138
|
+
state = {
|
|
139
|
+
valueValue: { value: 0 },
|
|
140
|
+
};
|
|
141
|
+
render() {
|
|
142
|
+
return (
|
|
143
|
+
<div>
|
|
144
|
+
<button onClick={() => this.state.valueValue.value++}>Increment</button>
|
|
145
|
+
<div>Value = {this.state.valueValue.value}</div>
|
|
146
|
+
<Intermediate x={{ value: this.state.valueValue.value }} />
|
|
147
|
+
|
|
148
|
+
<svg>
|
|
149
|
+
<circle cx={100} cy={100} r={50} fill="red" />
|
|
150
|
+
<CircleComponent />
|
|
151
|
+
</svg>
|
|
152
|
+
</div>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
class Benchmark1 extends qreact.Component<{
|
|
158
|
+
count: number;
|
|
159
|
+
}> {
|
|
160
|
+
render() {
|
|
161
|
+
return (
|
|
162
|
+
<div>
|
|
163
|
+
{list(this.props.count).map(i => <div>{i}</div>)}
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
class Benchmark2 extends qreact.Component<{
|
|
169
|
+
count: number;
|
|
170
|
+
}> {
|
|
171
|
+
render() {
|
|
172
|
+
return (
|
|
173
|
+
list(this.props.count).map(i => <div>{i}</div>)
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class SmallNested extends qreact.Component<{
|
|
180
|
+
obj: { value: number };
|
|
181
|
+
}> {
|
|
182
|
+
render() {
|
|
183
|
+
return (
|
|
184
|
+
<div />
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
class Benchmark3 extends qreact.Component<{
|
|
189
|
+
count: number;
|
|
190
|
+
}> {
|
|
191
|
+
render() {
|
|
192
|
+
return (
|
|
193
|
+
list(this.props.count).map(i => <SmallNested obj={{ value: i }} />)
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
class SmallNested2 extends qreact.Component<{
|
|
199
|
+
obj: { value: number };
|
|
200
|
+
}> {
|
|
201
|
+
render() {
|
|
202
|
+
return (
|
|
203
|
+
<div class={css.flex.gap(10).wrap} onClick={() => this.props.obj.value++}>
|
|
204
|
+
{this.props.obj.value}
|
|
205
|
+
<img src="/widgets/HTML5Video/video-thumbnail.jpg" />
|
|
206
|
+
</div>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
class Benchmark3p5 extends qreact.Component<{
|
|
211
|
+
count: number;
|
|
212
|
+
}> {
|
|
213
|
+
render() {
|
|
214
|
+
return (
|
|
215
|
+
list(this.props.count).map(i => <SmallNested2 obj={{ value: i }} />)
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
class Benchmark4 extends qreact.Component<{
|
|
221
|
+
count: number;
|
|
222
|
+
}> {
|
|
223
|
+
render() {
|
|
224
|
+
return (
|
|
225
|
+
<div class={css.flex.wrap}>
|
|
226
|
+
{list(this.props.count).map(i =>
|
|
227
|
+
<img src="/widgets/HTML5Video/video-thumbnail.jpg" />
|
|
228
|
+
)}
|
|
229
|
+
</div>
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
async function browserMain() {
|
|
237
|
+
if (isNode()) return;
|
|
238
|
+
watchFilesAndTriggerHotReloading();
|
|
239
|
+
|
|
240
|
+
// NOTE: Annoying, but qreact can't emulate the special minified keys preact uses
|
|
241
|
+
qreact.createElement = preact.createElement as any;
|
|
242
|
+
qreact.Fragment = preact.Fragment as any;
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
//ClientWatcher.DEBUG_READS = true;
|
|
246
|
+
//ClientWatcher.DEBUG_READS_EXPANDED = true;
|
|
247
|
+
//ClientWatcher.DEBUG_WRITES = true;
|
|
248
|
+
//ClientWatcher.DEBUG_WRITES_EXPANDED = true;
|
|
249
|
+
//Querysub.DEBUG_CALLS = true;
|
|
250
|
+
//PathValueProxyWatcher.TRACE = true;
|
|
251
|
+
//ClientWatcher.DEBUG_TRIGGERS = "light";
|
|
252
|
+
//ClientWatcher.DEBUG_TRIGGERS = "heavy";
|
|
253
|
+
//qreact.debug();
|
|
254
|
+
|
|
255
|
+
//preact.render(<Test />, document.getElementById("main")!);
|
|
256
|
+
//qreact.render(<DynamicComponent propValue={1} />, document.getElementById("main")!);
|
|
257
|
+
//qreact.render(<SyncedTest propValue={1} />, document.getElementById("main")!);
|
|
258
|
+
|
|
259
|
+
//*
|
|
260
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
261
|
+
await authorityLookup.startSyncing();
|
|
262
|
+
|
|
263
|
+
let benchmarkComponents = [
|
|
264
|
+
// ONLY run with devtools closed AND disableMeasurements (at the top of the file)! Otherwise the timings will be wrong.
|
|
265
|
+
// qreact is 3X slower
|
|
266
|
+
() => <Benchmark1 count={10000} />,
|
|
267
|
+
// qreact is 3X slower
|
|
268
|
+
() => <Benchmark2 count={10000} />,
|
|
269
|
+
// qreact is 30X slower
|
|
270
|
+
() => <Benchmark3 count={1000} />,
|
|
271
|
+
// qreact is 10X slower
|
|
272
|
+
() => <Benchmark3p5 count={1000} />,
|
|
273
|
+
// qreact is 1.5X slower
|
|
274
|
+
() => <Benchmark4 count={1000} />,
|
|
275
|
+
];
|
|
276
|
+
|
|
277
|
+
await measureCode(async function renderTest() {
|
|
278
|
+
const main = document.getElementById("main")!;
|
|
279
|
+
async function reset() {
|
|
280
|
+
main.replaceChildren();
|
|
281
|
+
await delay(0);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
for (let componentFactory of benchmarkComponents) {
|
|
285
|
+
let component = componentFactory();
|
|
286
|
+
let name = (component.type as any).name;
|
|
287
|
+
|
|
288
|
+
await reset();
|
|
289
|
+
let time = Date.now();
|
|
290
|
+
preact.render(component, main);
|
|
291
|
+
time = Date.now() - time;
|
|
292
|
+
preact.render(<div />, main);
|
|
293
|
+
console.log(`preact|${name} took ${formatTime(time)}`);
|
|
294
|
+
|
|
295
|
+
await reset();
|
|
296
|
+
time = Date.now();
|
|
297
|
+
await measureBlock(async () => {
|
|
298
|
+
qreact.render(component, main);
|
|
299
|
+
await clientWatcher.waitForTriggerFinished();
|
|
300
|
+
qreact.render(<div />, main);
|
|
301
|
+
await clientWatcher.waitForTriggerFinished();
|
|
302
|
+
}, "qreact|" + name);
|
|
303
|
+
time = Date.now() - time;
|
|
304
|
+
console.log(`qreact|${name} took ${formatTime(time)}`);
|
|
305
|
+
|
|
306
|
+
qreact.render(<div>done</div>, main);
|
|
307
|
+
}
|
|
308
|
+
}, { minTimeToLog: 0, thresholdInTable: 0 });
|
|
309
|
+
//*/
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
logErrors(main());
|
|
313
|
+
logErrors(browserMain());
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
let { data, functions } = Querysub.createSchema<{
|
|
317
|
+
values: {
|
|
318
|
+
[key: string]: string;
|
|
319
|
+
};
|
|
320
|
+
}>()({
|
|
321
|
+
domainName: "querysub.com",
|
|
322
|
+
functions: {
|
|
323
|
+
setValue(key: string, value: string) {
|
|
324
|
+
data().values[key] = value;
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
module,
|
|
328
|
+
moduleId: "qreactTest",
|
|
329
|
+
functionMetadata: {},
|
|
330
|
+
permissions: {
|
|
331
|
+
PERMISSIONS: isSuperUserPERMISSIONS
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
class SyncTest extends qreact.Component {
|
|
336
|
+
render() {
|
|
337
|
+
return (
|
|
338
|
+
<div>
|
|
339
|
+
<div>Regular <input value={data().values["a"]} onChange={e => functions.setValue("a", e.currentTarget.value)} /></div>
|
|
340
|
+
<div>Hot <input value={data().values["b"]} onInput={e => functions.setValue("b", e.currentTarget.value)} /></div>
|
|
341
|
+
<div>
|
|
342
|
+
Trigger sources {Array.from(Querysub.getTriggerReason()?.pathSources || []).map(x =>
|
|
343
|
+
<div>
|
|
344
|
+
{getPathFromStr(x.path).join(".")}
|
|
345
|
+
{x.source && <div class={css.marginLeft(10)}>{x.source}</div>}
|
|
346
|
+
</div>
|
|
347
|
+
)}
|
|
348
|
+
</div>
|
|
349
|
+
</div>
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/*
|
|
355
|
+
async function browserMain2() {
|
|
356
|
+
if (isNode()) return;
|
|
357
|
+
|
|
358
|
+
watchFilesAndTriggerHotReloading();
|
|
359
|
+
|
|
360
|
+
Querysub.DEBUG_CALLS = true;
|
|
361
|
+
ClientWatcher.DEBUG_TRIGGERS = "heavy";
|
|
362
|
+
qreact.debug();
|
|
363
|
+
|
|
364
|
+
qreact.render(preact.createElement(SyncTest, {}), document.getElementById("main")!);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
async function main2() {
|
|
368
|
+
if (!isNode()) return;
|
|
369
|
+
if (isDeploy()) return;
|
|
370
|
+
if (module.hotreload) return;
|
|
371
|
+
const edgePort = 15060;
|
|
372
|
+
PermissionsCheck.DEBUG = true;
|
|
373
|
+
ClientWatcher.DEBUG_READS = true;
|
|
374
|
+
ClientWatcher.DEBUG_WRITES = true;
|
|
375
|
+
|
|
376
|
+
//SocketFunction.silent = false;
|
|
377
|
+
Error.stackTraceLimit = 20;
|
|
378
|
+
|
|
379
|
+
await Querysub.hostServer({
|
|
380
|
+
trustedDomains: ["querysub.com"],
|
|
381
|
+
port: edgePort,
|
|
382
|
+
rootPath: __dirname + "/../../",
|
|
383
|
+
clientsideEntryPoint: "./src/4-dom/qreactTest.tsx",
|
|
384
|
+
hotReload: true,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
module.hotreload = isNode() && process.argv[1].includes("PathFunctionRunnerMain.ts");
|
|
389
|
+
module.noserverhotreload = false;
|
|
390
|
+
|
|
391
|
+
logErrors(main2());
|
|
392
|
+
logErrors(browserMain2());
|
|
393
|
+
*/
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
// async function main3() {
|
|
397
|
+
// let test = await proxyWatcher.dryRun({
|
|
398
|
+
// canWrite: true,
|
|
399
|
+
// watchFunction() {
|
|
400
|
+
// schema()["querysub.com"].rejectTest.value = 2;
|
|
401
|
+
// },
|
|
402
|
+
// });
|
|
403
|
+
// let buffer = await pathValueSerializer.serialize(test!);
|
|
404
|
+
// let test2 = await pathValueSerializer.deserialize(buffer);
|
|
405
|
+
// debugger;
|
|
406
|
+
// }
|
|
407
|
+
|
|
408
|
+
// main3().catch(e => console.error(e)).finally(() => process.exit());
|
|
409
|
+
|
|
410
|
+
|
|
411
411
|
// yarn test typenode ./src/4-dom/qreactTest.tsx
|