querysub 0.403.0 → 0.405.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.
Files changed (108) hide show
  1. package/.cursorrules +2 -0
  2. package/bin/audit-imports.js +4 -0
  3. package/bin/join.js +1 -1
  4. package/package.json +7 -4
  5. package/spec.txt +77 -0
  6. package/src/-a-archives/archiveCache.ts +9 -4
  7. package/src/-a-archives/archivesBackBlaze.ts +1039 -1039
  8. package/src/-a-auth/certs.ts +0 -12
  9. package/src/-c-identity/IdentityController.ts +12 -3
  10. package/src/-f-node-discovery/NodeDiscovery.ts +32 -26
  11. package/src/-g-core-values/NodeCapabilities.ts +12 -2
  12. package/src/0-path-value-core/AuthorityLookup.ts +239 -0
  13. package/src/0-path-value-core/LockWatcher2.ts +150 -0
  14. package/src/0-path-value-core/PathRouter.ts +543 -0
  15. package/src/0-path-value-core/PathRouterRouteOverride.ts +72 -0
  16. package/src/0-path-value-core/PathRouterServerAuthoritySpec.tsx +73 -0
  17. package/src/0-path-value-core/PathValueCommitter.ts +222 -488
  18. package/src/0-path-value-core/PathValueController.ts +277 -239
  19. package/src/0-path-value-core/PathWatcher.ts +534 -0
  20. package/src/0-path-value-core/ShardPrefixes.ts +31 -0
  21. package/src/0-path-value-core/ValidStateComputer.ts +303 -0
  22. package/src/0-path-value-core/archiveLocks/ArchiveLocks.ts +1 -1
  23. package/src/0-path-value-core/archiveLocks/ArchiveLocks2.ts +80 -44
  24. package/src/0-path-value-core/archiveLocks/archiveSnapshots.ts +13 -16
  25. package/src/0-path-value-core/auditLogs.ts +2 -0
  26. package/src/0-path-value-core/hackedPackedPathParentFiltering.ts +97 -0
  27. package/src/0-path-value-core/pathValueArchives.ts +491 -492
  28. package/src/0-path-value-core/pathValueCore.ts +195 -1496
  29. package/src/0-path-value-core/startupAuthority.ts +74 -0
  30. package/src/1-path-client/RemoteWatcher.ts +90 -82
  31. package/src/1-path-client/pathValueClientWatcher.ts +808 -815
  32. package/src/2-proxy/PathValueProxyWatcher.ts +10 -8
  33. package/src/2-proxy/archiveMoveHarness.ts +182 -214
  34. package/src/2-proxy/garbageCollection.ts +9 -8
  35. package/src/2-proxy/schema2.ts +21 -1
  36. package/src/3-path-functions/PathFunctionHelpers.ts +206 -180
  37. package/src/3-path-functions/PathFunctionRunner.ts +943 -766
  38. package/src/3-path-functions/PathFunctionRunnerMain.ts +5 -3
  39. package/src/3-path-functions/pathFunctionLoader.ts +2 -2
  40. package/src/3-path-functions/syncSchema.ts +596 -521
  41. package/src/4-deploy/deployFunctions.ts +19 -4
  42. package/src/4-deploy/deployGetFunctionsInner.ts +8 -2
  43. package/src/4-deploy/deployMain.ts +51 -68
  44. package/src/4-deploy/edgeClientWatcher.tsx +6 -1
  45. package/src/4-deploy/edgeNodes.ts +2 -2
  46. package/src/4-dom/qreact.tsx +2 -4
  47. package/src/4-dom/qreactTest.tsx +7 -13
  48. package/src/4-querysub/Querysub.ts +21 -8
  49. package/src/4-querysub/QuerysubController.ts +45 -29
  50. package/src/4-querysub/permissions.ts +2 -2
  51. package/src/4-querysub/querysubPrediction.ts +80 -70
  52. package/src/4-querysub/schemaHelpers.ts +5 -1
  53. package/src/5-diagnostics/GenericFormat.tsx +14 -9
  54. package/src/archiveapps/archiveGCEntry.tsx +9 -2
  55. package/src/archiveapps/archiveJoinEntry.ts +96 -84
  56. package/src/bits.ts +19 -0
  57. package/src/config.ts +21 -3
  58. package/src/config2.ts +23 -48
  59. package/src/deployManager/components/DeployPage.tsx +7 -3
  60. package/src/deployManager/machineSchema.ts +4 -1
  61. package/src/diagnostics/ActionsHistory.ts +3 -8
  62. package/src/diagnostics/AuditLogPage.tsx +2 -3
  63. package/src/diagnostics/FunctionCallInfo.tsx +141 -0
  64. package/src/diagnostics/FunctionCallInfoState.ts +162 -0
  65. package/src/diagnostics/MachineThreadInfo.tsx +1 -1
  66. package/src/diagnostics/NodeViewer.tsx +37 -48
  67. package/src/diagnostics/SyncTestPage.tsx +241 -0
  68. package/src/diagnostics/auditImportViolations.ts +185 -0
  69. package/src/diagnostics/listenOnDebugger.ts +3 -3
  70. package/src/diagnostics/logs/IndexedLogs/BufferUnitSet.ts +10 -4
  71. package/src/diagnostics/logs/IndexedLogs/IndexedLogs.ts +2 -2
  72. package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +24 -22
  73. package/src/diagnostics/logs/IndexedLogs/moveIndexLogsToPublic.ts +1 -1
  74. package/src/diagnostics/logs/diskLogGlobalContext.ts +1 -0
  75. package/src/diagnostics/logs/errorNotifications2/logWatcher.ts +1 -3
  76. package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleEntryEditor.tsx +34 -16
  77. package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleEntryReadMode.tsx +4 -6
  78. package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleInstanceTableView.tsx +36 -5
  79. package/src/diagnostics/logs/lifeCycleAnalysis/LifeCyclePage.tsx +19 -5
  80. package/src/diagnostics/logs/lifeCycleAnalysis/LifeCycleRenderer.tsx +15 -7
  81. package/src/diagnostics/logs/lifeCycleAnalysis/NestedLifeCycleInfo.tsx +28 -106
  82. package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleMatching.ts +2 -0
  83. package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleMisc.ts +0 -0
  84. package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycleSearch.tsx +18 -7
  85. package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycles.tsx +3 -0
  86. package/src/diagnostics/managementPages.tsx +10 -3
  87. package/src/diagnostics/misc-pages/ArchiveViewer.tsx +20 -26
  88. package/src/diagnostics/misc-pages/ArchiveViewerTree.tsx +6 -4
  89. package/src/diagnostics/misc-pages/ComponentSyncStats.tsx +2 -2
  90. package/src/diagnostics/misc-pages/LocalWatchViewer.tsx +7 -9
  91. package/src/diagnostics/misc-pages/SnapshotViewer.tsx +23 -12
  92. package/src/diagnostics/misc-pages/archiveViewerShared.tsx +1 -1
  93. package/src/diagnostics/pathAuditer.ts +486 -0
  94. package/src/diagnostics/pathAuditerCallback.ts +20 -0
  95. package/src/diagnostics/watchdog.ts +8 -1
  96. package/src/library-components/URLParam.ts +1 -1
  97. package/src/misc/hash.ts +1 -0
  98. package/src/path.ts +21 -7
  99. package/src/server.ts +54 -47
  100. package/src/user-implementation/loginEmail.tsx +1 -1
  101. package/tempnotes.txt +65 -0
  102. package/test.ts +298 -97
  103. package/src/0-path-value-core/NodePathAuthorities.ts +0 -1057
  104. package/src/0-path-value-core/PathController.ts +0 -1
  105. package/src/5-diagnostics/diskValueAudit.ts +0 -218
  106. package/src/5-diagnostics/memoryValueAudit.ts +0 -438
  107. package/src/archiveapps/archiveMergeEntry.tsx +0 -48
  108. package/src/archiveapps/lockTest.ts +0 -127
@@ -1,18 +1,24 @@
1
1
  import { magenta } from "socket-function/src/formatting/logColors";
2
2
  import { FunctionSpec, preloadFunctions } from "../3-path-functions/PathFunctionRunner";
3
3
  import { Querysub } from "../4-querysub/QuerysubController";
4
- import { errorify } from "../errors";
4
+ import { errorify, timeoutToError } from "../errors";
5
5
  import { runPromise } from "../functional/runCommand";
6
6
  import path from "path";
7
7
  import { preloadUI } from "./edgeNodes";
8
8
  import { proxyWatcher } from "../2-proxy/PathValueProxyWatcher";
9
9
  import { replaceFunctions } from "../3-path-functions/PathFunctionHelpers";
10
10
  import { setLiveDeployedHash } from "./deploySchema";
11
+ import { timeInMinute } from "socket-function/src/misc";
12
+ import { setShardPrefixes } from "../0-path-value-core/ShardPrefixes";
11
13
 
12
- export async function deployGetFunctions(): Promise<FunctionSpec[]> {
14
+ export async function deployGetFunctions(): Promise<{
15
+ functionSpecs: FunctionSpec[];
16
+ prefixes: string[];
17
+ }> {
13
18
  let innerPath = path.resolve(__dirname + "/deployGetFunctionsInner.ts").replaceAll("\\", "/");
14
- let result = await runPromise(`yarn typenode ${innerPath}`);
19
+ let result = await timeoutToError(timeInMinute * 7, runPromise(`yarn typenode ${innerPath}`), () => new Error("deployGetFunctions timed out"));
15
20
  let functionSpecs: FunctionSpec[] = [];
21
+ let prefixes: string[] = [];
16
22
  for (let line of result.split("\n")) {
17
23
  if (line.startsWith("ERROR:")) {
18
24
  throw errorify(line.slice("ERROR:".length));
@@ -21,8 +27,11 @@ export async function deployGetFunctions(): Promise<FunctionSpec[]> {
21
27
  let spec = JSON.parse(line.slice("FUNCTION_SPEC:".length));
22
28
  functionSpecs.push(spec);
23
29
  }
30
+ if (line.startsWith("PREFIX:")) {
31
+ prefixes.push(line.slice("PREFIX:".length));
32
+ }
24
33
  }
25
- return functionSpecs;
34
+ return { functionSpecs, prefixes };
26
35
  }
27
36
 
28
37
  export type DeployProgress = {
@@ -31,6 +40,7 @@ export type DeployProgress = {
31
40
 
32
41
  export async function deployFunctions(config: {
33
42
  functionSpecs: FunctionSpec[];
43
+ prefixes: string[];
34
44
  notifyRefreshDelay: number;
35
45
  deployOnlyCode?: boolean;
36
46
  deployOnlyUI?: boolean;
@@ -75,5 +85,10 @@ export async function deployFunctions(config: {
75
85
  });
76
86
  config.progress?.({ section: "Deploying Functions", progress: 1 });
77
87
 
88
+ config.progress?.({ section: "Deploying Prefixes", progress: 0 });
89
+ // NOTE: This is only used by the path value server, and if it's out of sync with the code, it doesn't really matter. The path value server only uses the prefixes on startup, and it only needs prefixes at least newer than the ones last used by the gc code. And the gc code gets it's prefixes from the same source, so... We can technically write this anywhere we want, or just randomly not write it, and it would be fine (If we never update it, then the client accesses will get more and more inefficient and start accessing every single path value server, but it won't break anything).
90
+ await setShardPrefixes(config.prefixes);
91
+ config.progress?.({ section: "Deploying Prefixes", progress: 1 });
92
+
78
93
  console.log(magenta(`FINISHED DEPLOY (${gitRef})`));
79
94
  }
@@ -3,12 +3,13 @@ import { deployBlock } from "./deployBlock";
3
3
  import { SocketFunction } from "socket-function/SocketFunction";
4
4
  import { getThreadKeyCert } from "../-a-auth/certs";
5
5
  import { getDomain, isPublic } from "../config";
6
- import { LOCAL_DOMAIN } from "../0-path-value-core/PathController";
7
- import { getSchemaObject, getModuleRelativePath, PERMISSIONS_FUNCTION_ID, getExportPath } from "../3-path-functions/syncSchema";
6
+ import { getSchemaObject, getModuleRelativePath, PERMISSIONS_FUNCTION_ID, getExportPath, getPrefixesForDeploy } from "../3-path-functions/syncSchema";
8
7
  import { getPathStr2 } from "../path";
9
8
  import { FunctionSpec } from "../3-path-functions/PathFunctionRunner";
10
9
  import fs from "fs";
11
10
  import { getGitRefLive, getGitURLLive } from "./git";
11
+ import { LOCAL_DOMAIN } from "../0-path-value-core/PathRouter";
12
+ import { delay } from "socket-function/src/batching";
12
13
 
13
14
  async function main() {
14
15
  let domainName = getDomain();
@@ -24,6 +25,7 @@ async function main() {
24
25
  let folderRoot = path.resolve(".").replaceAll("\\", "/");
25
26
  const deployPath = path.resolve("./deploy.ts");
26
27
  await import(deployPath);
28
+ await delay(1);
27
29
 
28
30
  const querysubRoot = path.resolve(__dirname + "/../").replaceAll("\\", "/");
29
31
 
@@ -91,6 +93,10 @@ async function main() {
91
93
  console.log(`FUNCTION_SPEC:${JSON.stringify(spec)}`);
92
94
  }
93
95
  }
96
+
97
+ for (let prefix of getPrefixesForDeploy()) {
98
+ console.log(`PREFIX:${prefix}`);
99
+ }
94
100
  }
95
101
 
96
102
  main().catch(e => console.error("ERROR:" + String(e?.stack || e).replaceAll("\n", "\\n"))).finally(() => process.exit(0));
@@ -1,69 +1,52 @@
1
- import "../inject";
2
-
3
- import { FunctionSpec, preloadFunctions } from "../3-path-functions/PathFunctionRunner";
4
- import path from "path";
5
- import { getExportPath, getSchemaObject, PERMISSIONS_FUNCTION_ID } from "../3-path-functions/syncSchema";
6
- import { getModuleRelativePath } from "../3-path-functions/syncSchema";
7
- import fs from "fs";
8
- import { SocketFunction } from "socket-function/SocketFunction";
9
- import { getThreadKeyCert } from "../-a-auth/certs";
10
- import { replaceFunctions } from "../3-path-functions/PathFunctionHelpers";
11
- import { getPathStr2 } from "../path";
12
- import { setIsDeploy } from "./deployCheck";
13
-
14
- import yargs from "yargs";
15
- import { getDomain, isPublic } from "../config";
16
- import { deployBlock } from "./deployBlock";
17
- import { LOCAL_DOMAIN } from "../0-path-value-core/PathController";
18
- import { blue, magenta, red } from "socket-function/src/formatting/logColors";
19
- import { getGitRefLive, getGitURLLive } from "./git";
20
- import { setLiveDeployedHash } from "./deploySchema";
21
- import { proxyWatcher } from "../2-proxy/PathValueProxyWatcher";
22
- import debugbreak from "debugbreak";
23
- import { timeInHour } from "socket-function/src/misc";
24
- import { preloadUI } from "./edgeNodes";
25
- import { shutdown } from "../diagnostics/periodic";
26
- import { delay } from "socket-function/src/batching";
27
- import { waitForImportBlockers } from "../3-path-functions/pathFunctionLoader";
28
- import { deployFunctions, deployGetFunctions } from "./deployFunctions";
29
- import { Querysub } from "../4-querysub/QuerysubController";
30
-
31
- let yargObj = yargs(process.argv)
32
- .option("deployonlycode", { type: "boolean", desc: "Only deploy code, not ui" })
33
- .option("deployonlyui", { type: "boolean", desc: "Only deploy ui, not code" })
34
- .option("notifyrefreshdelay", { type: "number", default: timeInHour * 12, desc: "The time clients have to refresh their UI after a deploy." })
35
- .option("dryrun", { type: "boolean", desc: "Dry run, don't actually deploy" })
36
- .argv
37
- ;
38
-
39
- setIsDeploy();
40
-
41
- export async function deployMain() {
42
- //SocketFunction.logMessages = true;
43
- //quietCoreMode();
44
- //ClientWatcher.DEBUG_READS = true;
45
- //ClientWatcher.DEBUG_WRITES = true;
46
-
47
- await Querysub.hostService("deployMain");
48
-
49
- const currentFunctions = await deployGetFunctions();
50
- for (let fnc of currentFunctions) {
51
- console.log(blue(`${fnc.DomainName}.${fnc.ModuleId}.${fnc.FunctionId}`));
52
- }
53
- if (yargObj.dryrun) {
54
- console.log(red("Dry run, not actually deploying"));
55
- return;
56
- }
57
-
58
- await deployFunctions({
59
- functionSpecs: currentFunctions,
60
- notifyRefreshDelay: yargObj.notifyrefreshdelay,
61
- deployOnlyCode: yargObj.deployonlycode,
62
- deployOnlyUI: yargObj.deployonlyui,
63
- });
64
-
65
- await shutdown();
66
- }
67
-
68
-
1
+ import "../inject";
2
+
3
+ import { setIsDeploy } from "./deployCheck";
4
+
5
+ import yargs from "yargs";
6
+ import { blue, red } from "socket-function/src/formatting/logColors";
7
+ import { timeInHour } from "socket-function/src/misc";
8
+ import { shutdown } from "../diagnostics/periodic";
9
+ import { deployFunctions, deployGetFunctions } from "./deployFunctions";
10
+ import { Querysub } from "../4-querysub/QuerysubController";
11
+ import { setShardPrefixes } from "../0-path-value-core/ShardPrefixes";
12
+
13
+ let yargObj = yargs(process.argv)
14
+ .option("deployonlycode", { type: "boolean", desc: "Only deploy code, not ui" })
15
+ .option("deployonlyui", { type: "boolean", desc: "Only deploy ui, not code" })
16
+ .option("notifyrefreshdelay", { type: "number", default: timeInHour * 12, desc: "The time clients have to refresh their UI after a deploy." })
17
+ .option("dryrun", { type: "boolean", desc: "Dry run, don't actually deploy" })
18
+ .argv
19
+ ;
20
+
21
+ setIsDeploy();
22
+
23
+ export async function deployMain() {
24
+ //SocketFunction.logMessages = true;
25
+ //quietCoreMode();
26
+ //ClientWatcher.DEBUG_READS = true;
27
+ //ClientWatcher.DEBUG_WRITES = true;
28
+
29
+ await Querysub.hostService("deployMain");
30
+
31
+ const { functionSpecs, prefixes } = await deployGetFunctions();
32
+ for (let fnc of functionSpecs) {
33
+ console.log(blue(`${fnc.DomainName}.${fnc.ModuleId}.${fnc.FunctionId}`));
34
+ }
35
+ if (yargObj.dryrun) {
36
+ console.log(red("Dry run, not actually deploying"));
37
+ return;
38
+ }
39
+
40
+ await deployFunctions({
41
+ functionSpecs: functionSpecs,
42
+ notifyRefreshDelay: yargObj.notifyrefreshdelay,
43
+ deployOnlyCode: yargObj.deployonlycode,
44
+ deployOnlyUI: yargObj.deployonlyui,
45
+ prefixes: prefixes,
46
+ });
47
+
48
+ await shutdown();
49
+ }
50
+
51
+
69
52
  deployMain().catch(e => console.error(e)).finally(() => process.exit());
@@ -6,7 +6,6 @@ import { throttleFunction, timeInMinute, timeInSecond } from "socket-function/sr
6
6
  import { isNode } from "typesafecss";
7
7
  import { logErrors, timeoutToError } from "../errors";
8
8
  import { blue, red, yellow } from "socket-function/src/formatting/logColors";
9
- import { showModal } from "../5-diagnostics/Modal";
10
9
  import { qreact } from "../4-dom/qreact";
11
10
  import { liveHashOverrideURL } from "./edgeBootstrap";
12
11
  import { css } from "typesafecss";
@@ -17,6 +16,11 @@ import { lazy } from "socket-function/src/caching";
17
16
  import { Button } from "../library-components/Button";
18
17
  import { updateRootDiscoveryLocation } from "../-f-node-discovery/NodeDiscovery";
19
18
 
19
+ setImmediate(() => {
20
+ // Modal
21
+ import("../5-diagnostics/Modal");
22
+ });
23
+
20
24
  const SWITCH_SERVER_TIMEOUT = timeInSecond * 15;
21
25
  const MAX_DISPLAY_INTERVAL = timeInMinute * 5;
22
26
  const FINAL_DELAY = timeInSecond * 30;
@@ -78,6 +82,7 @@ function onLiveHashChange(liveHash: string, refreshThresholdTime: number) {
78
82
 
79
83
  // Start notification loop
80
84
  void (async () => {
85
+ const { showModal } = await import("../5-diagnostics/Modal");
81
86
  // Show notifications at intervals
82
87
  for (let delayTime of delays) {
83
88
  await delayTime;
@@ -116,7 +116,7 @@ export async function registerEdgeNode(config: {
116
116
 
117
117
  await waitForFirstTimeSync();
118
118
 
119
- if (!isLocal() && !noSyncing()) {
119
+ if (isPublic() && !noSyncing()) {
120
120
  let loadedHash = "";
121
121
  let firstLoad = new PromiseObj<void>();
122
122
  Querysub.createWatcher(() => {
@@ -342,7 +342,7 @@ class EdgeNodeControllerBase {
342
342
  public async preloadUI(config: {
343
343
  hash: string;
344
344
  }) {
345
- if (isLocal()) return;
345
+ if (!isPublic()) return;
346
346
  const { hash } = config;
347
347
  if (!registeredEdgeNode || !canHaveChildren(registeredEdgeNode)) {
348
348
  throw new Error(`Somehow we have no registered edge node. How did we even expose this controller?`);
@@ -1,9 +1,6 @@
1
1
  import type preact from "preact";
2
2
  import { compareArray, isNode, sort, timeInSecond } from "socket-function/src/misc";
3
- import { isDeploy } from "../4-deploy/deployCheck";
4
- import { PermissionsCheck } from "../4-querysub/permissions";
5
3
  import { ClientWatcher, clientWatcher } from "../1-path-client/pathValueClientWatcher";
6
- import { LOCAL_DOMAIN } from "../0-path-value-core/PathController";
7
4
  import { rawSchema } from "../2-proxy/pathDatabaseProxyBase";
8
5
  import { SyncWatcher, atomic, atomicObjectWrite, atomicObjectWriteNoFreeze, doProxyOptions, doUnatomicWrites, proxyWatcher, registerSchemaPrefix, unregisterSchemaPrefix } from "../2-proxy/PathValueProxyWatcher";
9
6
  import { createPathValueProxy, getProxyPath, isValueProxy, isValueProxy2 } from "../2-proxy/pathValueProxy";
@@ -2798,4 +2795,5 @@ function triggerGlobalAfterRenderWatch(component: QRenderClass) {
2798
2795
  // NOTE: Import Querysub at the end, so we can export qreact before we require it. That way Querysub
2799
2796
  // can statically access qreact.
2800
2797
  import { Querysub } from "../4-querysub/Querysub";
2801
- import { logDisk } from "../diagnostics/logs/diskLogger";
2798
+ import { logDisk } from "../diagnostics/logs/diskLogger"; import { LOCAL_DOMAIN } from "../0-path-value-core/PathRouter";
2799
+
@@ -1,8 +1,8 @@
1
- import { disableMeasurements, measureBlock, measureCode, measureFnc } from "socket-function/src/profiling/measure";
1
+ import { disableMeasurements, measureBlock, measureCode } from "socket-function/src/profiling/measure";
2
2
  disableMeasurements();
3
3
 
4
4
  import preact from "preact";
5
- import { isNode, list, timeInHour } from "socket-function/src/misc";
5
+ import { isNode, list } from "socket-function/src/misc";
6
6
  import { ClientWatcher, clientWatcher } from "../1-path-client/pathValueClientWatcher";
7
7
  import { isDeploy } from "../4-deploy/deployCheck";
8
8
  import { logErrors } from "../errors";
@@ -10,18 +10,12 @@ import { watchFilesAndTriggerHotReloading } from "socket-function/hot/HotReloadC
10
10
  import { qreact } from "./qreact";
11
11
  import { Querysub } from "../4-querysub/QuerysubController";
12
12
  import { PermissionsCheck } from "../4-querysub/permissions";
13
- import { PathValueProxyWatcher, proxyWatcher } from "../2-proxy/PathValueProxyWatcher";
14
- import { setFlag } from "socket-function/require/compileFlags";
15
- import { rawSchema } from "../2-proxy/pathDatabaseProxyBase";
16
- import { LOCAL_DOMAIN } from "../0-path-value-core/PathController";
17
- import { batchFunction, delay } from "socket-function/src/batching";
13
+ import { delay } from "socket-function/src/batching";
18
14
  import { formatTime } from "socket-function/src/formatting/format";
19
- import { pathValueAuthority2 } from "../0-path-value-core/NodePathAuthorities";
20
- import { schema } from "../3-path-functions/tests/rejectTest";
21
- import { pathValueSerializer } from "../-h-path-value-serialize/PathValueSerializer";
22
15
  import { getPathFromStr } from "../path";
23
- import { PromiseObj } from "../promise";
24
16
  import { css } from "./css";
17
+ import { isSuperUserPERMISSIONS } from "../user-implementation/userData";
18
+ import { authorityLookup } from "../0-path-value-core/AuthorityLookup";
25
19
 
26
20
 
27
21
 
@@ -264,7 +258,7 @@ async function browserMain() {
264
258
 
265
259
  //*
266
260
  await new Promise(resolve => setTimeout(resolve, 0));
267
- await pathValueAuthority2.waitUntilRoutingIsReady();
261
+ await authorityLookup.startSyncing();
268
262
 
269
263
  let benchmarkComponents = [
270
264
  // ONLY run with devtools closed AND disableMeasurements (at the top of the file)! Otherwise the timings will be wrong.
@@ -334,7 +328,7 @@ let { data, functions } = Querysub.createSchema<{
334
328
  moduleId: "qreactTest",
335
329
  functionMetadata: {},
336
330
  permissions: {
337
- PERMISSIONS: () => true
331
+ PERMISSIONS: isSuperUserPERMISSIONS
338
332
  }
339
333
  });
340
334
 
@@ -18,8 +18,7 @@ import { RequireController, setRequireBootRequire } from "socket-function/requir
18
18
  import { cache, cacheLimited, lazy } from "socket-function/src/caching";
19
19
  import { getOwnMachineId, getOwnThreadId, getThreadKeyCert, verifyMachineIdForPublicKey } from "../-a-auth/certs";
20
20
  import { getHostedIP, getSNICerts, publishMachineARecords } from "../-e-certs/EdgeCertController";
21
- import { LOCAL_DOMAIN, nodePathAuthority } from "../0-path-value-core/NodePathAuthorities";
22
- import { debugCoreMode, registerGetCompressNetwork, encodeParentFilter, authorityStorage } from "../0-path-value-core/pathValueCore";
21
+ import { debugCoreMode, registerGetCompressNetwork, authorityStorage } from "../0-path-value-core/pathValueCore";
23
22
  import { clientWatcher, ClientWatcher } from "../1-path-client/pathValueClientWatcher";
24
23
  import { SyncWatcher, proxyWatcher, specialObjectWriteValue, isSynced, PathValueProxyWatcher, atomic, doAtomicWrites, noAtomicSchema, undeleteFromLookup, registerSchemaPrefix, WatcherOptions, doProxyOptions } from "../2-proxy/PathValueProxyWatcher";
25
24
  import { isInProxyDatabase, rawSchema } from "../2-proxy/pathDatabaseProxyBase";
@@ -178,7 +177,6 @@ export class Querysub {
178
177
  public static WILDCARD_NUM = "*" as any as number;
179
178
  public static createLocalSchema = createLocalSchema;
180
179
  public static flushDelayedFunctions = () => flushDelayedFunctions();
181
- public static LOCAL_DOMAIN = LOCAL_DOMAIN;
182
180
  public static DEBUG_CALLS = false;
183
181
  public static DEBUG_PREDICTIONS = false;
184
182
  public static PREDICT_CALLS = true;
@@ -201,6 +199,11 @@ export class Querysub {
201
199
  */
202
200
  public static MAX_FUTURE_CALL_TIME = 10_000;
203
201
 
202
+ /** NOTE: Is required for the function runner to work. Eventually, we should allow you to request the full history on just specific paths.
203
+ * - It's not *actually* the full history, As the underlying path value storage will delete values that are past the golden threshold anyways.
204
+ */
205
+ public static SEND_FULL_HISTORY_ON_INITIAL_SYNC = false;
206
+
204
207
 
205
208
  public static COMPRESS_NETWORK = true;
206
209
 
@@ -210,6 +213,7 @@ export class Querysub {
210
213
 
211
214
  public static getCallTime = getSyncedTime;
212
215
  public static getFunctionCallTime = getSyncedTime;
216
+ // NOTE: This is just an ID inside of a call that will be unique. It's not the call ID that the function uses when it's running. That's something that's different, and that's defined in PathFunctionHelpers
213
217
  public static getCallId = () => Querysub.getCallerMachineId() + "_" + Querysub.getCallTime();
214
218
  // Returns a random value between 0 and 1. The value depends on the callId, and index (being identical for
215
219
  // the same callid and index).
@@ -284,7 +288,7 @@ export class Querysub {
284
288
  await measureBlock(async () => {
285
289
  await waitForFirstTimeSync();
286
290
  }, "waitForFirstTimeSync");
287
- await nodePathAuthority.waitUntilRoutingIsReady();
291
+ await authorityLookup.startSyncing();
288
292
  }
289
293
 
290
294
  public static createWatcher(watcher: (obj: SyncWatcher) => void, options?: Partial<WatcherOptions<unknown>>): {
@@ -788,6 +792,8 @@ export class Querysub {
788
792
 
789
793
 
790
794
  RequireController.injectHTMLBeforeStartup(async () => {
795
+ const { getEdgeBootstrapScript } = await import("../4-deploy/edgeBootstrap");
796
+ const { getEdgeNodeConfigURL } = await import("../4-deploy/edgeNodes");
791
797
  let edgeBootstrapFile = await getEdgeBootstrapScript({
792
798
  edgeNodeConfigURL: await getEdgeNodeConfigURL(),
793
799
  });
@@ -830,6 +836,7 @@ export class Querysub {
830
836
  let { ip, ipDomain } = await publishMachineARecords();
831
837
 
832
838
  if (!isBootstrapOnly()) {
839
+ const { registerEdgeNode } = await import("../4-deploy/edgeNodes");
833
840
  await registerEdgeNode({
834
841
  host: ipDomain + ":" + port,
835
842
  entryPaths,
@@ -1050,9 +1057,14 @@ export class Querysub {
1050
1057
  * (otherwise likely does filtering serverside, which is still somewhat efficient).
1051
1058
  */
1052
1059
  startFraction?: number;
1053
- /** Value between 0 and 1 */
1060
+ /** Value between 0 and 1.
1061
+ * BOTH start and end must be provided, otherwise if only one is provided we will ignore it.
1062
+ */
1054
1063
  endFraction?: number;
1055
1064
  }): (keyof T)[] {
1065
+ if (!isNode()) {
1066
+ console.warn(`keys() is unlikely to work clientside. If we need to emulate how the server does the filtering, we should add an additional function to help with that. But there are issues with how query sub proxies watches, which make proxying partial key watches too difficult. ALSO, this is mostly for watching very large data streams with dynamic sharding (in FunctionRunner), and so shouldn't be needed clientside (the application can handle filtering at a schema level if it really wants something similar to this).`);
1067
+ }
1056
1068
  let { startFraction, endFraction } = config || {};
1057
1069
  if (startFraction === undefined || endFraction === undefined) {
1058
1070
  return Object.keys(obj);
@@ -1284,6 +1296,7 @@ setImmediate(() => {
1284
1296
  setImmediate(async () => {
1285
1297
  // Import, so it registers addStatPeriodic
1286
1298
  await import("../5-diagnostics/nodeMetadata");
1299
+ await import("../diagnostics/pathAuditer");
1287
1300
  });
1288
1301
 
1289
1302
  setImmediate(async () => {
@@ -1300,10 +1313,7 @@ registerGetCompressNetwork(() => Querysub.COMPRESS_NETWORK);
1300
1313
  import "../diagnostics/watchdog";
1301
1314
  import "../diagnostics/trackResources";
1302
1315
  import "../diagnostics/benchmark";
1303
- import { getEdgeNodeConfigURL, registerEdgeNode } from "../4-deploy/edgeNodes";
1304
- import { getEdgeBootstrapScript } from "../4-deploy/edgeBootstrap";
1305
1316
  import { formatNumber, formatTime } from "socket-function/src/formatting/format";
1306
- import { css } from "../4-dom/css";
1307
1317
  import { getCountPerPaint } from "../functional/onNextPaint";
1308
1318
  import { addEpsilons } from "../bits";
1309
1319
  import { blue, magenta } from "socket-function/src/formatting/logColors";
@@ -1312,4 +1322,7 @@ import { getRecords, setRecord } from "../-b-authorities/dnsAuthority";
1312
1322
  import { testTCPIsListening } from "socket-function/src/networking";
1313
1323
  import { getNodeId, getNodeIdLocation } from "socket-function/src/nodeCache";
1314
1324
  import { onAllPredictionsFinished } from "../-0-hooks/hooks";
1325
+ import { LOCAL_DOMAIN } from "../0-path-value-core/PathRouter";
1326
+ import { authorityLookup } from "../0-path-value-core/AuthorityLookup";
1327
+ import { encodeParentFilter } from "../0-path-value-core/hackedPackedPathParentFiltering";
1315
1328
 
@@ -1,22 +1,23 @@
1
1
  import { SocketFunction } from "socket-function/SocketFunction";
2
2
  import { cache, lazy } from "socket-function/src/caching";
3
- import { appendToPathStr, getPathDepth, getPathFromStr, getPathIndex, getPathStr1, getPathStr2, getPathStr3, hack_getPackedPathSuffix, removePathLastPart } from "../path";
4
- import { CHILD_CHECK_PREFIX, FunctionMetadata } from "../3-path-functions/syncSchema";
5
- import { RemoteWatcher, remoteWatcher } from "../1-path-client/RemoteWatcher";
3
+ import { appendToPathStr, getPathDepth, getPathStr1, getPathStr3 } from "../path";
4
+ import { FunctionMetadata } from "../3-path-functions/syncSchema";
5
+ import { RemoteWatcher } from "../1-path-client/RemoteWatcher";
6
6
  import { getProxyPath } from "../2-proxy/pathValueProxy";
7
- import { atomic, atomicObjectWrite, proxyWatcher } from "../2-proxy/PathValueProxyWatcher";
8
- import { CallSpec, DEPTH_TO_DATA, FunctionSpec, commitCall, debugCallSpec, functionSchema, getDevFunctionSpecFromCall } from "../3-path-functions/PathFunctionRunner";
9
- import { PathValueController } from "../0-path-value-core/PathValueController";
10
- import { epochTime, MAX_ACCEPTED_CHANGE_AGE, PathValue, pathWatcher, Time, WatchConfig, compareTime, debugTime, getNextTime, MAX_CHANGE_AGE } from "../0-path-value-core/pathValueCore";
7
+ import { atomic, proxyWatcher } from "../2-proxy/PathValueProxyWatcher";
8
+ import { CallSpec, DEPTH_TO_DATA, commitCall, debugCallSpec, functionSchema, getDevFunctionSpecFromCall } from "../3-path-functions/PathFunctionRunner";
9
+ import { PathValueController, PathValueControllerBase } from "../0-path-value-core/PathValueController";
10
+ import { epochTime, MAX_ACCEPTED_CHANGE_AGE, PathValue, WatchConfig, debugTime, MAX_CHANGE_AGE } from "../0-path-value-core/pathValueCore";
11
+ import { pathWatcher } from "../0-path-value-core/PathWatcher";
11
12
  import { IdentityController_getMachineId, IdentityController_getPubKeyShort, IdentityController_getSecureIP } from "../-c-identity/IdentityController";
12
13
  import { getControllerNodeId } from "../-g-core-values/NodeCapabilities";
13
14
  import { getModuleFromConfig, watchModuleHotreloads } from "../3-path-functions/pathFunctionLoader";
14
15
  import { errorToUndefined, ignoreErrors, logErrors } from "../errors";
15
16
  import { blue, green, magenta, red } from "socket-function/src/formatting/logColors";
16
17
  import { PermissionsCheck } from "./permissions";
17
- import { parseArgs, writeCall } from "../3-path-functions/PathFunctionHelpers";
18
+ import { writeCall } from "../3-path-functions/PathFunctionHelpers";
18
19
  import { delay } from "socket-function/src/batching";
19
- import { isNode, isNodeTrue, timeInMinute, timeInSecond } from "socket-function/src/misc";
20
+ import { isNodeTrue } from "socket-function/src/misc";
20
21
  import { registerResource } from "../diagnostics/trackResources";
21
22
 
22
23
  // Always whitelist preact, as most of the time we want it clientside
@@ -24,27 +25,21 @@ import "preact";
24
25
  import { setFlag } from "socket-function/require/compileFlags";
25
26
  import { CallerContextBase } from "socket-function/SocketFunctionTypes";
26
27
  import { isTrustedByNode } from "../-d-trust/NetworkTrust2";
27
- import { pathValueSerializer } from "../-h-path-value-serialize/PathValueSerializer";
28
28
  import { Querysub, id } from "./Querysub";
29
- import { measureBlock } from "socket-function/src/profiling/measure";
30
- import debugbreak from "debugbreak";
31
29
  import { isDefined } from "../misc";
32
30
  import { isClient, isServer } from "../config2";
33
31
  import { PromiseObj } from "../promise";
34
32
  import { LoggingClient } from "../0-path-value-core/LoggingClient";
35
33
  import * as prediction from "./querysubPrediction";
36
- import { getCallResultPath } from "./querysubPrediction";
37
- import { nodePathAuthority, pathValueAuthority2 } from "../0-path-value-core/NodePathAuthorities";
38
- import { assertIsManagementUser } from "../diagnostics/managementPages";
39
- import { getBrowserUrlNode } from "../-f-node-discovery/NodeDiscovery";
40
34
  setFlag(require, "preact", "allowclient", true);
41
35
 
42
36
  import yargs from "yargs";
43
37
  import { mergeFilterables, parseFilterable, serializeFilterable } from "../misc/filterable";
44
38
  import { isManagementUser, onAllPredictionsFinished } from "../-0-hooks/hooks";
45
- import { getDomain, isBootstrapOnly, isLocal } from "../config";
46
- import { logDisk } from "../diagnostics/logs/diskLogger";
39
+ import { getDomain, isBootstrapOnly } from "../config";
47
40
  import { flushPredictionQueueBase, runInPredictionQueue, syncHasPendingPredictionsBase } from "./predictionQueue";
41
+ import { PathRouter } from "../0-path-value-core/PathRouter";
42
+ import { authorityLookup } from "../0-path-value-core/AuthorityLookup";
48
43
 
49
44
  let yargObj = isNodeTrue() && yargs(process.argv)
50
45
  .option("fncfilter", { type: "string", default: "", desc: `Sets the filterable state for function calls, causing them to target specific FunctionRunners. If no FunctionRunner matches, all functions will fail to run. For example: "devtestserver" will match a FunctionRunner that uses the "devtestserver" filter. Merges with the existing filterable state if a client sets it explicitly.` })
@@ -59,7 +54,7 @@ export { Querysub, id };
59
54
  // TODO: Eventually this will be split by domain, which required nodeIds to be split by domain, so that getControllerNodeId can check nodeIds on a specific domain.
60
55
  export async function querysubNodeId() {
61
56
  if (isClient()) {
62
- return nodePathAuthority.getSingleReadNodePromise(getPathStr1(getDomain()));
57
+ return PathRouter.getReadyAuthority(getPathStr1(getDomain()))?.nodeId;
63
58
  } else {
64
59
  return getControllerNodeId(QuerysubController);
65
60
  }
@@ -482,12 +477,14 @@ export class QuerysubControllerBase {
482
477
 
483
478
  console.info("Disallowing PathValue watches due to disallowed permissions", { count: newPathsNotAllowed.length, callerId });
484
479
 
485
- ignoreErrors(pathValueSerializer.serialize(undefinedValues, { compress: Querysub.COMPRESS_NETWORK }).then(buffers =>
486
- PathValueController.nodes[callerId].forwardWrites(
487
- buffers,
488
- Array.from(newParentPathsNotAllowed),
489
- )
490
- ));
480
+ ignoreErrors(PathValueControllerBase.sendValues({
481
+ nodeId: callerId,
482
+ pathValues: undefinedValues,
483
+ initialTriggers: {
484
+ values: new Set(undefinedValues.map(value => value.path)),
485
+ parentPaths: new Set(newParentPathsNotAllowed)
486
+ },
487
+ }));
491
488
  }
492
489
 
493
490
  if (removedPaths.size > 0) {
@@ -497,8 +494,10 @@ export class QuerysubControllerBase {
497
494
  if (allowedPaths.size > 0) {
498
495
  let [newParentPathsAllowed, newPathsAllowed] = splitParentPaths(allowedPaths);
499
496
  let watchConfig: WatchConfig = { paths: newPathsAllowed, parentPaths: newParentPathsAllowed };
500
- pathWatcher.watchPath({ callback: callerId, ...watchConfig });
501
- remoteWatcher.watchLatest(watchConfig);
497
+ pathWatcher.watchPath({
498
+ nodeId: callerId,
499
+ ...watchConfig
500
+ });
502
501
  }
503
502
  };
504
503
  }
@@ -541,6 +540,13 @@ export class QuerysubControllerBase {
541
540
  }
542
541
  Querysub.assertDomainAllowed(getPathStr1(call.DomainName));
543
542
 
543
+ console.info(`Querysub starting to add function call`, {
544
+ callId: call.CallId,
545
+ timeId: call.runAtTime.time,
546
+ functionId: call.FunctionId,
547
+ moduleId: call.ModuleId,
548
+ });
549
+
544
550
  let caller = SocketFunction.getCaller();
545
551
  let callerMachineId = IdentityController_getMachineId(caller);
546
552
  let callerCreatorId = IdentityController_getPubKeyShort(caller);
@@ -608,6 +614,9 @@ export class QuerysubControllerBase {
608
614
  throw new Error(`Caller does not have permission to call ${call.DomainName}.${call.ModuleId}`);
609
615
  }
610
616
 
617
+ console.info(`Querysub committing call`, {
618
+ callId: call.CallId,
619
+ });
611
620
  commitCall(call);
612
621
  // NOTE: We don't wait for our writes to actually commit, because... there isn't any reason they shouldn't
613
622
  // except the server being down, in which case, the client will gracefully timeout when it doesn't receive the confirmation
@@ -654,11 +663,17 @@ export class QuerysubControllerBase {
654
663
 
655
664
  // NOTE: Maybe remove this? It's very useful for debugging though...
656
665
  public async debugGetSingleReadNode(path: string) {
657
- return pathValueAuthority2.getSingleReadNodeSync(path);
666
+ return PathRouter.getReadyAuthority(path)?.nodeId;
658
667
  }
659
668
 
660
669
  public async debugGetPathAuthorities(nodeId: string) {
661
- return pathValueAuthority2.getAuthorityPaths(nodeId);
670
+ let authorities = await authorityLookup.getTopology();
671
+ return authorities.find(x => x.nodeId === nodeId)?.authoritySpec;
672
+ }
673
+
674
+ public async debugGetTopologyEntry(nodeId: string) {
675
+ let topology = await authorityLookup.getTopology();
676
+ return topology.find(x => x.nodeId === nodeId);
662
677
  }
663
678
  }
664
679
 
@@ -672,6 +687,7 @@ export const QuerysubController = SocketFunction.register(
672
687
  addCall: { compress: true, },
673
688
  debugGetSingleReadNode: {},
674
689
  debugGetPathAuthorities: {},
690
+ debugGetTopologyEntry: {},
675
691
  getModulePath: {},
676
692
  getDevFunctionSpecFromCall: {},
677
693
  }),
@@ -13,7 +13,7 @@ import { isClient } from "../config2";
13
13
  import { sort } from "socket-function/src/misc";
14
14
  import { Querysub } from "./QuerysubController";
15
15
  import { CALL_PERMISSIONS_KEY } from "./permissionsShared";
16
- import { getDomain, isLocal } from "../config";
16
+ import { getDomain, isLocal, isPublic } from "../config";
17
17
 
18
18
  function watchModule(config: FunctionSpec): NodeJS.Module | undefined {
19
19
  let module = getModuleFromConfig(config);
@@ -52,7 +52,7 @@ export class PermissionsCheck {
52
52
  });
53
53
 
54
54
  private getModulePermissions(domainName: string) {
55
- if (isLocal() && domainName === getDomain()) {
55
+ if (!isPublic() && domainName === getDomain()) {
56
56
  return function (moduleId: string): {
57
57
  schema: SchemaObject;
58
58
  fnc: FunctionSpec;