socket-function 1.2.1 → 1.2.4
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.d.ts +1 -1
- package/SocketFunctionTypes.d.ts +1 -1
- package/hot/HotReloadController.d.ts +3 -3
- package/index.d.ts +25 -10
- package/package.json +1 -1
- package/require/CSSShim.d.ts +1 -1
- package/require/RequireController.d.ts +2 -2
- package/require/compileFlags.d.ts +1 -1
- package/require/require.d.ts +1 -1
- package/src/callManager.d.ts +1 -1
- package/test.ts +5 -11
- package/time/trueTimeShim.d.ts +16 -1
- package/time/trueTimeShim.ts +121 -34
- package/dist/SetProcessVariables.ts.cache +0 -9
- package/dist/SocketFunction.ts.cache +0 -467
- package/hot/dist/HotReloadController.ts.cache +0 -252
- package/require/dist/RequireController.ts.cache +0 -386
- package/require/dist/compileFlags.ts.cache +0 -41
- package/require/dist/extMapper.ts.cache +0 -368
- package/require/dist/require.ts.cache +0 -676
- package/src/JSONLACKS/dist/JSONLACKS.ts.cache +0 -469
- package/src/dist/CallFactory.ts.cache +0 -930
- package/src/dist/Zip.ts.cache +0 -156
- package/src/dist/batching.ts.cache +0 -377
- package/src/dist/bits.ts.cache +0 -121
- package/src/dist/buffers.ts.cache +0 -76
- package/src/dist/caching.ts.cache +0 -302
- package/src/dist/callHTTPHandler.ts.cache +0 -264
- package/src/dist/callManager.ts.cache +0 -159
- package/src/dist/certStore.ts.cache +0 -59
- package/src/dist/createSingleton.ts.cache +0 -62
- package/src/dist/fixLargeNetworkCalls.ts.cache +0 -17
- package/src/dist/forwardPort.ts.cache +0 -222
- package/src/dist/https.ts.cache +0 -141
- package/src/dist/misc.ts.cache +0 -499
- package/src/dist/nodeCache.ts.cache +0 -136
- package/src/dist/nodeProxy.ts.cache +0 -57
- package/src/dist/protocolNegotiation.ts.cache +0 -101
- package/src/dist/tlsParsing.ts.cache +0 -85
- package/src/dist/types.ts.cache +0 -9
- package/src/dist/webSocketServer.ts.cache +0 -365
- package/src/dist/websocketFactory.ts.cache +0 -53
- package/src/formatting/dist/colors.ts.cache +0 -98
- package/src/formatting/dist/format.ts.cache +0 -396
- package/src/formatting/dist/logColors.ts.cache +0 -28
- package/src/lz4/dist/LZ4.ts.cache +0 -53
- package/src/profiling/dist/getOwnTime.ts.cache +0 -100
- package/src/profiling/dist/measure.ts.cache +0 -338
- package/src/profiling/dist/stats.ts.cache +0 -202
- package/src/profiling/dist/statsFormat.ts.cache +0 -45
- package/time/dist/trueTimeShim.ts.cache +0 -656
package/SocketFunction.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
/// <reference path="require/RequireController.d.ts" />
|
|
1
2
|
/// <reference types="node" />
|
|
2
3
|
/// <reference types="node" />
|
|
3
|
-
/// <reference types="socket-function/require/requirecontroller" />
|
|
4
4
|
import { SocketExposedInterface, SocketFunctionHook, SocketFunctionClientHook, SocketExposedShape, SocketRegistered, CallerContext, FullCallType, SocketRegisterType } from "./SocketFunctionTypes";
|
|
5
5
|
import { SocketServerConfig } from "./src/webSocketServer";
|
|
6
6
|
import { Args, MaybePromise } from "./src/types";
|
package/SocketFunctionTypes.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/// <reference
|
|
2
|
-
/// <reference
|
|
1
|
+
/// <reference path="../../typenode/index.d.ts" />
|
|
2
|
+
/// <reference path="../require/RequireController.d.ts" />
|
|
3
3
|
/** Enables some hot reload functionality.
|
|
4
4
|
* - Triggers a refresh clientside
|
|
5
5
|
* - Triggers a reload server, for modules marked with `module.hotreload`
|
|
@@ -28,7 +28,7 @@ export declare function isHotReloading(): boolean;
|
|
|
28
28
|
export declare function hotReloadingGuard(): true;
|
|
29
29
|
export declare function setExternalHotReloading(value: boolean): void;
|
|
30
30
|
export declare function onHotReload(callback: (modules: NodeJS.Module[]) => void): void;
|
|
31
|
-
export declare const HotReloadController: import("
|
|
31
|
+
export declare const HotReloadController: import("../SocketFunctionTypes").SocketRegistered<{
|
|
32
32
|
watchFiles: () => Promise<void>;
|
|
33
33
|
fileUpdated: (files: string[], changeTime: number) => Promise<void>;
|
|
34
34
|
}>;
|
package/index.d.ts
CHANGED
|
@@ -7,9 +7,9 @@ declare module "socket-function/SetProcessVariables" {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
declare module "socket-function/SocketFunction" {
|
|
10
|
+
/// <reference path="require/RequireController.d.ts" />
|
|
10
11
|
/// <reference types="node" />
|
|
11
12
|
/// <reference types="node" />
|
|
12
|
-
/// <reference types="socket-function/require/requirecontroller" />
|
|
13
13
|
import { SocketExposedInterface, SocketFunctionHook, SocketFunctionClientHook, SocketExposedShape, SocketRegistered, CallerContext, FullCallType, SocketRegisterType } from "socket-function/SocketFunctionTypes";
|
|
14
14
|
import { SocketServerConfig } from "socket-function/src/webSocketServer";
|
|
15
15
|
import { Args, MaybePromise } from "socket-function/src/types";
|
|
@@ -128,7 +128,7 @@ declare module "socket-function/SocketFunction" {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
declare module "socket-function/SocketFunctionTypes" {
|
|
131
|
-
/// <reference
|
|
131
|
+
/// <reference path="require/RequireController.d.ts" />
|
|
132
132
|
import { getCallObj } from "socket-function/src/nodeProxy";
|
|
133
133
|
import { Args, MaybePromise } from "socket-function/src/types";
|
|
134
134
|
export declare const socket: unique symbol;
|
|
@@ -218,8 +218,8 @@ declare module "socket-function/SocketFunctionTypes" {
|
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
declare module "socket-function/hot/HotReloadController" {
|
|
221
|
-
/// <reference
|
|
222
|
-
/// <reference
|
|
221
|
+
/// <reference path="../../typenode/index.d.ts" />
|
|
222
|
+
/// <reference path="../require/RequireController.d.ts" />
|
|
223
223
|
/** Enables some hot reload functionality.
|
|
224
224
|
* - Triggers a refresh clientside
|
|
225
225
|
* - Triggers a reload server, for modules marked with `module.hotreload`
|
|
@@ -307,15 +307,15 @@ declare module "socket-function/mobx/promiseToObservable" {
|
|
|
307
307
|
}
|
|
308
308
|
|
|
309
309
|
declare module "socket-function/require/CSSShim" {
|
|
310
|
-
/// <reference
|
|
310
|
+
/// <reference path="RequireController.d.ts" />
|
|
311
311
|
export {};
|
|
312
312
|
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
declare module "socket-function/require/RequireController" {
|
|
316
|
+
/// <reference path="../../typenode/index.d.ts" />
|
|
316
317
|
/// <reference types="node" />
|
|
317
318
|
/// <reference types="node" />
|
|
318
|
-
/// <reference types="typenode" />
|
|
319
319
|
declare global {
|
|
320
320
|
namespace NodeJS {
|
|
321
321
|
interface Module {
|
|
@@ -430,8 +430,8 @@ declare module "socket-function/require/RequireController" {
|
|
|
430
430
|
}
|
|
431
431
|
|
|
432
432
|
declare module "socket-function/require/compileFlags" {
|
|
433
|
+
/// <reference path="RequireController.d.ts" />
|
|
433
434
|
/// <reference types="node" />
|
|
434
|
-
/// <reference types="socket-function/require/requirecontroller" />
|
|
435
435
|
/**
|
|
436
436
|
* Adds a global function setFlag(require, "typescript", flag) which sets a flag on the client
|
|
437
437
|
* - Ex, setFlag(require, "typescript", "allowclient") so allowclient = true on the typescript module.
|
|
@@ -453,7 +453,7 @@ declare module "socket-function/require/extMapper" {
|
|
|
453
453
|
}
|
|
454
454
|
|
|
455
455
|
declare module "socket-function/require/require" {
|
|
456
|
-
/// <reference
|
|
456
|
+
/// <reference path="../src/src.d.ts" />
|
|
457
457
|
declare global {
|
|
458
458
|
var onProgressHandler: undefined | ((progress: {
|
|
459
459
|
type: string;
|
|
@@ -789,7 +789,7 @@ declare module "socket-function/src/callHTTPHandler" {
|
|
|
789
789
|
}
|
|
790
790
|
|
|
791
791
|
declare module "socket-function/src/callManager" {
|
|
792
|
-
/// <reference
|
|
792
|
+
/// <reference path="../hot/HotReloadController.d.ts" />
|
|
793
793
|
import { CallerContext, CallType, ClientHookContext, FullCallType, FunctionFlags, HookContext, SocketExposedInterface, SocketExposedShape, SocketFunctionClientHook, SocketFunctionHook, SocketRegistered } from "socket-function/SocketFunctionTypes";
|
|
794
794
|
export declare function getCallFlags(call: CallType): FunctionFlags | undefined;
|
|
795
795
|
export declare function shouldCompressCall(call: CallType): boolean | "LZ4" | undefined;
|
|
@@ -1560,13 +1560,28 @@ declare module "socket-function/time/trueTimeShim" {
|
|
|
1560
1560
|
fromTime: number;
|
|
1561
1561
|
toTime: number;
|
|
1562
1562
|
};
|
|
1563
|
+
export declare function computeTweenedOffset(components: {
|
|
1564
|
+
systemTime: number;
|
|
1565
|
+
fromOffset: number;
|
|
1566
|
+
toOffset: number;
|
|
1567
|
+
fromTime: number;
|
|
1568
|
+
}): number;
|
|
1563
1569
|
export declare function getTimeComponents(): {
|
|
1564
1570
|
systemTime: number;
|
|
1565
1571
|
offset: number;
|
|
1566
1572
|
};
|
|
1567
1573
|
export declare function getTrueTime(): number;
|
|
1568
1574
|
export declare function getTrueTimeOffset(): number;
|
|
1569
|
-
export
|
|
1575
|
+
export type TrueTimeProof = {
|
|
1576
|
+
systemTime: number;
|
|
1577
|
+
fromOffset: number;
|
|
1578
|
+
toOffset: number;
|
|
1579
|
+
fromTime: number;
|
|
1580
|
+
toTime: number;
|
|
1581
|
+
offset: number;
|
|
1582
|
+
measurement?: TimeOffsetProof;
|
|
1583
|
+
};
|
|
1584
|
+
export declare function getTrueTimeProof(): TrueTimeProof | undefined;
|
|
1570
1585
|
export declare function waitForFirstTimeSync(): Promise<void> | undefined;
|
|
1571
1586
|
declare global {
|
|
1572
1587
|
var TRUE_TIME_ALREADY_SHIMMED: boolean;
|
package/package.json
CHANGED
package/require/CSSShim.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/// <reference
|
|
1
|
+
/// <reference path="RequireController.d.ts" />
|
|
2
2
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
/// <reference path="../../typenode/index.d.ts" />
|
|
1
2
|
/// <reference types="node" />
|
|
2
3
|
/// <reference types="node" />
|
|
3
|
-
/// <reference types="typenode" />
|
|
4
4
|
declare global {
|
|
5
5
|
namespace NodeJS {
|
|
6
6
|
interface Module {
|
|
@@ -85,7 +85,7 @@ declare global {
|
|
|
85
85
|
/** @deprecated, not needed, as this defaults to ".", which is a lot easier to reason about anyways. */
|
|
86
86
|
export declare function setRequireBootRequire(dir: string): void;
|
|
87
87
|
export declare function allowAllNodeModules(): void;
|
|
88
|
-
export declare const RequireController: import("
|
|
88
|
+
export declare const RequireController: import("../SocketFunctionTypes").SocketRegistered<{
|
|
89
89
|
rootResolvePath: "Function has implementation but is not exposed in the SocketFunction.register call";
|
|
90
90
|
requireHTML: (config?: {
|
|
91
91
|
requireCalls?: string[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
/// <reference path="RequireController.d.ts" />
|
|
1
2
|
/// <reference types="node" />
|
|
2
|
-
/// <reference types="socket-function/require/requirecontroller" />
|
|
3
3
|
/**
|
|
4
4
|
* Adds a global function setFlag(require, "typescript", flag) which sets a flag on the client
|
|
5
5
|
* - Ex, setFlag(require, "typescript", "allowclient") so allowclient = true on the typescript module.
|
package/require/require.d.ts
CHANGED
package/src/callManager.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/// <reference
|
|
1
|
+
/// <reference path="../hot/HotReloadController.d.ts" />
|
|
2
2
|
import { CallerContext, CallType, ClientHookContext, FullCallType, FunctionFlags, HookContext, SocketExposedInterface, SocketExposedShape, SocketFunctionClientHook, SocketFunctionHook, SocketRegistered } from "../SocketFunctionTypes";
|
|
3
3
|
export declare function getCallFlags(call: CallType): FunctionFlags | undefined;
|
|
4
4
|
export declare function shouldCompressCall(call: CallType): boolean | "LZ4" | undefined;
|
package/test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getTimeComponentsDetailed, waitForFirstTimeSync } from "./time/trueTimeShim";
|
|
1
|
+
import { computeTweenedOffset, getTimeComponentsDetailed, waitForFirstTimeSync } from "./time/trueTimeShim";
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
|
|
@@ -19,7 +19,6 @@ async function sampleMode() {
|
|
|
19
19
|
toOffset: number;
|
|
20
20
|
fromTime: number;
|
|
21
21
|
toTime: number;
|
|
22
|
-
fraction: number;
|
|
23
22
|
};
|
|
24
23
|
|
|
25
24
|
const samples: Sample[] = [];
|
|
@@ -28,11 +27,8 @@ async function sampleMode() {
|
|
|
28
27
|
for (let i = 0; i < SAMPLE_COUNT; i++) {
|
|
29
28
|
const detailed = getTimeComponentsDetailed();
|
|
30
29
|
|
|
31
|
-
// Calculate
|
|
32
|
-
const
|
|
33
|
-
const duration = detailed.toTime - detailed.fromTime;
|
|
34
|
-
const fraction = duration > 0 ? Math.min(1, elapsed / duration) : 0;
|
|
35
|
-
const offset = detailed.fromOffset + (detailed.toOffset - detailed.fromOffset) * fraction;
|
|
30
|
+
// Calculate the tween using the same systemTime
|
|
31
|
+
const offset = computeTweenedOffset(detailed);
|
|
36
32
|
|
|
37
33
|
samples.push({
|
|
38
34
|
id: TEST_RUN_ID,
|
|
@@ -42,7 +38,6 @@ async function sampleMode() {
|
|
|
42
38
|
toOffset: detailed.toOffset,
|
|
43
39
|
fromTime: detailed.fromTime,
|
|
44
40
|
toTime: detailed.toTime,
|
|
45
|
-
fraction,
|
|
46
41
|
});
|
|
47
42
|
|
|
48
43
|
if (SAMPLE_INTERVAL_MS > 0) {
|
|
@@ -88,7 +83,6 @@ async function verifyMode() {
|
|
|
88
83
|
toOffset: number;
|
|
89
84
|
fromTime: number;
|
|
90
85
|
toTime: number;
|
|
91
|
-
fraction: number;
|
|
92
86
|
file: string;
|
|
93
87
|
};
|
|
94
88
|
|
|
@@ -126,13 +120,13 @@ async function verifyMode() {
|
|
|
126
120
|
console.error(` systemTime: ${prev.systemTime}`);
|
|
127
121
|
console.error(` offset: ${prev.offset}`);
|
|
128
122
|
console.error(` trueTime: ${prevTrueTime}`);
|
|
129
|
-
console.error(`
|
|
123
|
+
console.error(` tween: ${prev.fromOffset} -> ${prev.toOffset}`);
|
|
130
124
|
console.error(` timeWindow: ${prev.fromTime} -> ${prev.toTime}`);
|
|
131
125
|
console.error(` Current [ID: ${sample.id}, file: ${sample.file}]:`);
|
|
132
126
|
console.error(` systemTime: ${sample.systemTime}`);
|
|
133
127
|
console.error(` offset: ${sample.offset}`);
|
|
134
128
|
console.error(` trueTime: ${trueTime}`);
|
|
135
|
-
console.error(`
|
|
129
|
+
console.error(` tween: ${sample.fromOffset} -> ${sample.toOffset}`);
|
|
136
130
|
console.error(` timeWindow: ${sample.fromTime} -> ${sample.toTime}`);
|
|
137
131
|
console.error(` Difference: ${trueTime - lastTrueTime}ms`);
|
|
138
132
|
}
|
package/time/trueTimeShim.d.ts
CHANGED
|
@@ -15,13 +15,28 @@ export declare function getTimeComponentsDetailed(): {
|
|
|
15
15
|
fromTime: number;
|
|
16
16
|
toTime: number;
|
|
17
17
|
};
|
|
18
|
+
export declare function computeTweenedOffset(components: {
|
|
19
|
+
systemTime: number;
|
|
20
|
+
fromOffset: number;
|
|
21
|
+
toOffset: number;
|
|
22
|
+
fromTime: number;
|
|
23
|
+
}): number;
|
|
18
24
|
export declare function getTimeComponents(): {
|
|
19
25
|
systemTime: number;
|
|
20
26
|
offset: number;
|
|
21
27
|
};
|
|
22
28
|
export declare function getTrueTime(): number;
|
|
23
29
|
export declare function getTrueTimeOffset(): number;
|
|
24
|
-
export
|
|
30
|
+
export type TrueTimeProof = {
|
|
31
|
+
systemTime: number;
|
|
32
|
+
fromOffset: number;
|
|
33
|
+
toOffset: number;
|
|
34
|
+
fromTime: number;
|
|
35
|
+
toTime: number;
|
|
36
|
+
offset: number;
|
|
37
|
+
measurement?: TimeOffsetProof;
|
|
38
|
+
};
|
|
39
|
+
export declare function getTrueTimeProof(): TrueTimeProof | undefined;
|
|
25
40
|
export declare function waitForFirstTimeSync(): Promise<void> | undefined;
|
|
26
41
|
declare global {
|
|
27
42
|
var TRUE_TIME_ALREADY_SHIMMED: boolean;
|
package/time/trueTimeShim.ts
CHANGED
|
@@ -18,10 +18,18 @@ const FETCH_RETRY_MAX_DELAY = 1000 * 30;
|
|
|
18
18
|
const FETCH_MAX_FAILURES = 8;
|
|
19
19
|
const NTP_TIMEOUT = 1000 * 10;
|
|
20
20
|
|
|
21
|
+
// The on-disk LMDB database can become corrupt (ex, a process killed mid-write). After this many
|
|
22
|
+
// consecutive failed operations we stop just reopening the handle and delete the files to start
|
|
23
|
+
// fresh - the data is only a cached time offset, so wiping it merely forces a re-measurement.
|
|
24
|
+
const LMDB_MAX_CORRUPTION_FAILURES = 3;
|
|
25
|
+
|
|
21
26
|
// Time can never go backwards, but we can run at a slower rate until the output time allows
|
|
22
27
|
// the real time to catch up with it.
|
|
23
28
|
const MINIMUM_TIME_RATE = 0.5;
|
|
24
29
|
|
|
30
|
+
// The offset tweens toward its target at this fraction of elapsed real time, then plateaus once it gets there. Must stay below 1 so output time keeps moving forward even while the offset is shrinking. Tweening across the whole transition window instead would mean a badly-off clock (many seconds) takes the entire window to converge, which breaks transactional consistency with other machines.
|
|
31
|
+
const OFFSET_TWEEN_RATE = 0.5;
|
|
32
|
+
|
|
25
33
|
const THROW_ON_ERROR = false;
|
|
26
34
|
|
|
27
35
|
// Hugely important as if we don't synchronize between processes, it means our logs are going to be confusing and out of order.
|
|
@@ -138,13 +146,24 @@ export function getTimeComponentsDetailed(): {
|
|
|
138
146
|
}
|
|
139
147
|
}
|
|
140
148
|
|
|
149
|
+
export function computeTweenedOffset(components: {
|
|
150
|
+
systemTime: number;
|
|
151
|
+
fromOffset: number;
|
|
152
|
+
toOffset: number;
|
|
153
|
+
fromTime: number;
|
|
154
|
+
}): number {
|
|
155
|
+
const elapsed = Math.max(0, components.systemTime - components.fromTime);
|
|
156
|
+
const delta = components.toOffset - components.fromOffset;
|
|
157
|
+
const maxChange = elapsed * OFFSET_TWEEN_RATE;
|
|
158
|
+
if (Math.abs(delta) <= maxChange) {
|
|
159
|
+
return components.toOffset;
|
|
160
|
+
}
|
|
161
|
+
return components.fromOffset + Math.sign(delta) * maxChange;
|
|
162
|
+
}
|
|
163
|
+
|
|
141
164
|
export function getTimeComponents(): { systemTime: number; offset: number } {
|
|
142
165
|
const detailed = getTimeComponentsDetailed();
|
|
143
|
-
|
|
144
|
-
const duration = detailed.toTime - detailed.fromTime;
|
|
145
|
-
const fraction = duration > 0 ? Math.min(1, elapsed / duration) : 0;
|
|
146
|
-
const offset = detailed.fromOffset + (detailed.toOffset - detailed.fromOffset) * fraction;
|
|
147
|
-
return { systemTime: detailed.systemTime, offset };
|
|
166
|
+
return { systemTime: detailed.systemTime, offset: computeTweenedOffset(detailed) };
|
|
148
167
|
}
|
|
149
168
|
|
|
150
169
|
export function getTrueTime() {
|
|
@@ -174,8 +193,30 @@ export function getTrueTimeOffset() {
|
|
|
174
193
|
const { offset } = getTimeComponents();
|
|
175
194
|
return offset;
|
|
176
195
|
}
|
|
177
|
-
export
|
|
178
|
-
|
|
196
|
+
export type TrueTimeProof = {
|
|
197
|
+
systemTime: number;
|
|
198
|
+
// The tween endpoints the current offset is moving between. When offset !== toOffset we are still converging.
|
|
199
|
+
fromOffset: number;
|
|
200
|
+
toOffset: number;
|
|
201
|
+
fromTime: number;
|
|
202
|
+
toTime: number;
|
|
203
|
+
offset: number;
|
|
204
|
+
// The raw measurement that produced the newest offset. Undefined if the offset came from a caller-provided base that only returns numbers.
|
|
205
|
+
measurement?: TimeOffsetProof;
|
|
206
|
+
};
|
|
207
|
+
export function getTrueTimeProof(): TrueTimeProof | undefined {
|
|
208
|
+
const data = cachedTimeOffsetData;
|
|
209
|
+
if (!data) return undefined;
|
|
210
|
+
const detailed = getTimeComponentsDetailed();
|
|
211
|
+
return {
|
|
212
|
+
systemTime: detailed.systemTime,
|
|
213
|
+
fromOffset: detailed.fromOffset,
|
|
214
|
+
toOffset: detailed.toOffset,
|
|
215
|
+
fromTime: detailed.fromTime,
|
|
216
|
+
toTime: detailed.toTime,
|
|
217
|
+
offset: computeTweenedOffset(detailed),
|
|
218
|
+
measurement: data.proof,
|
|
219
|
+
};
|
|
179
220
|
}
|
|
180
221
|
export function waitForFirstTimeSync(): Promise<void> | undefined {
|
|
181
222
|
if (didFirstTimeSync) return undefined;
|
|
@@ -283,67 +324,113 @@ type TimeOffsetStore = {
|
|
|
283
324
|
putInitial(data: TimeOffsetData): Promise<boolean>;
|
|
284
325
|
};
|
|
285
326
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
if (timeOffsetDb) return timeOffsetDb;
|
|
290
|
-
if (!isNode()) return undefined;
|
|
327
|
+
type TimeOffsetDb = import("lmdb").RootDatabase<TimeOffsetData, string>;
|
|
328
|
+
let timeOffsetDb: TimeOffsetDb | undefined = undefined;
|
|
329
|
+
let timeOffsetDbPath: string | undefined = undefined;
|
|
291
330
|
|
|
331
|
+
async function openTimeOffsetDb(): Promise<TimeOffsetDb | undefined> {
|
|
292
332
|
try {
|
|
293
333
|
const lmdb = await import("lmdb");
|
|
294
334
|
const path = await import("path");
|
|
295
335
|
const os = await import("os");
|
|
296
336
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
path:
|
|
337
|
+
timeOffsetDbPath = path.join(os.tmpdir(), "socket-function-time-offset-2");
|
|
338
|
+
return lmdb.open<TimeOffsetData, string>({
|
|
339
|
+
path: timeOffsetDbPath,
|
|
300
340
|
// Enable versioning for conditional writes
|
|
301
341
|
useVersions: true,
|
|
302
342
|
});
|
|
303
|
-
return timeOffsetDb;
|
|
304
343
|
} catch (e) {
|
|
305
|
-
console.error("Error opening LMDB database:", e);
|
|
344
|
+
console.error("Error opening LMDB database:", (e as Error).stack ?? e);
|
|
306
345
|
return undefined;
|
|
307
346
|
}
|
|
308
347
|
}
|
|
309
348
|
|
|
310
|
-
function
|
|
349
|
+
async function getTimeOffsetDb() {
|
|
350
|
+
if (!USE_LMDB_PROCESS_SYNC) return undefined;
|
|
351
|
+
if (!isNode()) return undefined;
|
|
352
|
+
if (timeOffsetDb) return timeOffsetDb;
|
|
353
|
+
timeOffsetDb = await openTimeOffsetDb();
|
|
354
|
+
return timeOffsetDb;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Closes the current handle (so the next op reopens a fresh one) and, when wipe is set, deletes the
|
|
358
|
+
// on-disk files so a corrupt database is replaced with an empty one. lmdb writes the main file at
|
|
359
|
+
// the path plus a sibling lock file, so we clear the path and its lock variants.
|
|
360
|
+
async function recreateTimeOffsetDb(config: { wipe: boolean }) {
|
|
361
|
+
let db = timeOffsetDb;
|
|
362
|
+
timeOffsetDb = undefined;
|
|
363
|
+
if (db) {
|
|
364
|
+
try {
|
|
365
|
+
await db.close();
|
|
366
|
+
} catch (e) {
|
|
367
|
+
console.error("Error closing LMDB database:", (e as Error).stack ?? e);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (config.wipe && timeOffsetDbPath) {
|
|
371
|
+
try {
|
|
372
|
+
const fs = await import("fs");
|
|
373
|
+
for (let suffix of ["", "-lock", ".lock"]) {
|
|
374
|
+
await fs.promises.rm(timeOffsetDbPath + suffix, { recursive: true, force: true });
|
|
375
|
+
}
|
|
376
|
+
console.log(yellow(`Wiped corrupt time-offset LMDB database at ${timeOffsetDbPath}`));
|
|
377
|
+
} catch (e) {
|
|
378
|
+
console.error("Error wiping corrupt LMDB database:", (e as Error).stack ?? e);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// A corrupt database throws on every read and on the read-back inside every write, and we can't
|
|
384
|
+
// repair it. So we run each op through here: on success we reset the failure count, and on error
|
|
385
|
+
// we reopen the handle (wiping the files once we've hit the threshold) and return the fallback so
|
|
386
|
+
// callers degrade to running unsynced instead of throwing. Ops are serialized by updatingOffset,
|
|
387
|
+
// so there is no concurrent access to worry about.
|
|
388
|
+
let lmdbCorruptionFailures = 0;
|
|
389
|
+
async function runLmdbOp<T>(name: string, op: (db: TimeOffsetDb) => Promise<T>, fallback: T): Promise<T> {
|
|
390
|
+
const db = await getTimeOffsetDb();
|
|
391
|
+
if (!db) return fallback;
|
|
392
|
+
try {
|
|
393
|
+
const result = await op(db);
|
|
394
|
+
lmdbCorruptionFailures = 0;
|
|
395
|
+
return result;
|
|
396
|
+
} catch (e) {
|
|
397
|
+
lmdbCorruptionFailures++;
|
|
398
|
+
console.error(`Error during LMDB ${name} (failure ${lmdbCorruptionFailures}/${LMDB_MAX_CORRUPTION_FAILURES}):`, (e as Error).stack ?? e);
|
|
399
|
+
let wipe = lmdbCorruptionFailures >= LMDB_MAX_CORRUPTION_FAILURES;
|
|
400
|
+
await recreateTimeOffsetDb({ wipe });
|
|
401
|
+
if (wipe) lmdbCorruptionFailures = 0;
|
|
402
|
+
return fallback;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function getLmdbStore(): TimeOffsetStore {
|
|
311
407
|
return {
|
|
312
408
|
async getEntry() {
|
|
313
|
-
|
|
409
|
+
return runLmdbOp("getEntry", async (db) => {
|
|
314
410
|
const entry = await db.getEntry("timeOffset"); // Gets {value, version} atomically
|
|
315
411
|
if (!entry) return undefined;
|
|
316
412
|
if (typeof entry.version !== "number" || !isValidTimeOffsetData(entry.value)) return undefined;
|
|
317
413
|
return { data: entry.value, version: entry.version };
|
|
318
|
-
}
|
|
319
|
-
console.error("Error reading from LMDB database:", e);
|
|
320
|
-
return undefined;
|
|
321
|
-
}
|
|
414
|
+
}, undefined);
|
|
322
415
|
},
|
|
323
416
|
async putIfVersion(data, expectedVersion) {
|
|
324
|
-
|
|
417
|
+
return runLmdbOp("putIfVersion", async (db) => {
|
|
325
418
|
// Use random version to minimize collision probability on retries
|
|
326
419
|
const newVersion = Math.random();
|
|
327
420
|
const success = await db.ifVersion("timeOffset", expectedVersion, () => {
|
|
328
421
|
return db.put("timeOffset", data, newVersion);
|
|
329
422
|
});
|
|
330
423
|
return success !== undefined;
|
|
331
|
-
}
|
|
332
|
-
console.error("Error writing to LMDB database:", e);
|
|
333
|
-
return false;
|
|
334
|
-
}
|
|
424
|
+
}, false);
|
|
335
425
|
},
|
|
336
426
|
async putInitial(data) {
|
|
337
|
-
|
|
427
|
+
return runLmdbOp("putInitial", async (db) => {
|
|
338
428
|
const newVersion = Math.random();
|
|
339
429
|
await db.put("timeOffset", data, newVersion);
|
|
340
430
|
// Read back to see what actually got written
|
|
341
431
|
const actualEntry = await db.getEntry("timeOffset");
|
|
342
432
|
return actualEntry?.version === newVersion;
|
|
343
|
-
}
|
|
344
|
-
console.error("Error writing to LMDB database:", e);
|
|
345
|
-
return false;
|
|
346
|
-
}
|
|
433
|
+
}, false);
|
|
347
434
|
},
|
|
348
435
|
};
|
|
349
436
|
}
|
|
@@ -407,7 +494,7 @@ async function getTimeOffsetStore(): Promise<TimeOffsetStore | undefined> {
|
|
|
407
494
|
if (isNode()) {
|
|
408
495
|
const db = await getTimeOffsetDb();
|
|
409
496
|
if (db) {
|
|
410
|
-
timeOffsetStore = getLmdbStore(
|
|
497
|
+
timeOffsetStore = getLmdbStore();
|
|
411
498
|
}
|
|
412
499
|
} else {
|
|
413
500
|
timeOffsetStore = getLocalStorageStore();
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict"; var console = (function shimConsole() { let baseConsole = globalThis.console; if (typeof window !== "undefined") return baseConsole; let name = __filename.replaceAll("\\", "/").split("/").pop(); let dirName = __dirname.replaceAll("\\", "/").split("/").pop(); let context = { __FILE__: __filename, __DIR__: __dirname, __NAME__: name, __DIRNAME__: dirName }; let newConsole = { ...baseConsole }; for (let shim of ["log", "info", "warn", "error"]) { newConsole[shim] = (...args) => { args.push(context); baseConsole[shim](...args); }; } newConsole.__context = context; return newConsole; })(); "use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
3
|
-
module.allowclient = true;
|
|
4
|
-
const misc_1 = require("./src/misc");
|
|
5
|
-
if (!(0, misc_1.isNode)()) {
|
|
6
|
-
process.env.CBOR_NATIVE_ACCELERATION_DISABLED = "true";
|
|
7
|
-
}
|
|
8
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2V0UHJvY2Vzc1ZhcmlhYmxlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIlNldFByb2Nlc3NWYXJpYWJsZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxNQUFNLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztBQUMxQixxQ0FBb0M7QUFFcEMsSUFBSSxDQUFDLElBQUEsYUFBTSxHQUFFLEVBQUUsQ0FBQztJQUNaLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUNBQWlDLEdBQUcsTUFBTSxDQUFDO0FBQzNELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJtb2R1bGUuYWxsb3djbGllbnQgPSB0cnVlO1xuaW1wb3J0IHsgaXNOb2RlIH0gZnJvbSBcIi4vc3JjL21pc2NcIjtcblxuaWYgKCFpc05vZGUoKSkge1xuICAgIHByb2Nlc3MuZW52LkNCT1JfTkFUSVZFX0FDQ0VMRVJBVElPTl9ESVNBQkxFRCA9IFwidHJ1ZVwiO1xufSJdfQ=//=
|
|
9
|
-
/* _JS_SOURCE_HASH = "249631df8c5cbb77a37aa988d0d9d058d467b254000e31ac2a58f9161b5a8626"; */
|