socket-function 1.2.14 → 1.2.15

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.
@@ -1,5 +1,6 @@
1
1
  /// <reference path="require/RequireController.d.ts" />
2
2
  /// <reference types="node" />
3
+ /// <reference types="node" />
3
4
  import { SocketExposedInterface, SocketFunctionHook, SocketFunctionClientHook, SocketExposedShape, SocketRegistered, CallerContext, FullCallType, SocketRegisterType } from "./SocketFunctionTypes";
4
5
  import { SocketServerConfig } from "./src/webSocketServer";
5
6
  import { Args, MaybePromise } from "./src/types";
@@ -36,6 +37,7 @@ export declare class SocketFunction {
36
37
  */
37
38
  static GET_ALTERNATE_NODE_IDS: (nodeId: string) => MaybePromise<string[] | undefined>;
38
39
  static WIRE_WARN_TIME: number;
40
+ static DISABLE_COMPRESSION: boolean;
39
41
  private static onMountCallbacks;
40
42
  private static exposedClassesSingleton;
41
43
  static get exposedClasses(): Set<string>;
package/SocketFunction.ts CHANGED
@@ -98,6 +98,9 @@ export class SocketFunction {
98
98
 
99
99
  public static WIRE_WARN_TIME = 100;
100
100
 
101
+ // Process-wide compression kill switch. When set before connections are established, LZ4 is left out of the protocol negotiation entirely (both for connections we initiate and ones we accept), so NEITHER side compresses — the wire format stays the plain backwards-compatible one. Overrides per-function `compress` flags.
102
+ public static DISABLE_COMPRESSION = false;
103
+
101
104
  // Shared across copies of this package, so onMount callbacks registered through one copy still
102
105
  // fire when another copy mounts. See createSingleton.
103
106
  private static onMountCallbacks = createSingleton("SocketFunction.onMountCallbacks", 1, () => new Map<string, (() => MaybePromise<void>)[]>()).get();
package/index.d.ts CHANGED
@@ -9,6 +9,7 @@ declare module "socket-function/SetProcessVariables" {
9
9
  declare module "socket-function/SocketFunction" {
10
10
  /// <reference path="require/RequireController.d.ts" />
11
11
  /// <reference types="node" />
12
+ /// <reference types="node" />
12
13
  import { SocketExposedInterface, SocketFunctionHook, SocketFunctionClientHook, SocketExposedShape, SocketRegistered, CallerContext, FullCallType, SocketRegisterType } from "socket-function/SocketFunctionTypes";
13
14
  import { SocketServerConfig } from "socket-function/src/webSocketServer";
14
15
  import { Args, MaybePromise } from "socket-function/src/types";
@@ -45,6 +46,7 @@ declare module "socket-function/SocketFunction" {
45
46
  */
46
47
  static GET_ALTERNATE_NODE_IDS: (nodeId: string) => MaybePromise<string[] | undefined>;
47
48
  static WIRE_WARN_TIME: number;
49
+ static DISABLE_COMPRESSION: boolean;
48
50
  private static onMountCallbacks;
49
51
  private static exposedClassesSingleton;
50
52
  static get exposedClasses(): Set<string>;
@@ -315,6 +317,7 @@ declare module "socket-function/require/CSSShim" {
315
317
  declare module "socket-function/require/RequireController" {
316
318
  /// <reference path="../../typenode/index.d.ts" />
317
319
  /// <reference types="node" />
320
+ /// <reference types="node" />
318
321
  declare global {
319
322
  namespace NodeJS {
320
323
  interface Module {
@@ -444,6 +447,7 @@ declare module "socket-function/require/compileFlags" {
444
447
  }
445
448
 
446
449
  declare module "socket-function/require/extMapper" {
450
+ /// <reference types="node" />
447
451
  /// <reference types="node" />
448
452
  export declare function getExtContentType(ext: string): string;
449
453
  export declare function getContentTypeFromBuffer(buffer: Buffer): string | undefined;
@@ -469,6 +473,7 @@ declare module "socket-function/require/require" {
469
473
  }
470
474
 
471
475
  declare module "socket-function/src/CallFactory" {
476
+ /// <reference types="node" />
472
477
  /// <reference types="node" />
473
478
  /// <reference types="node" />
474
479
  import { CallType } from "socket-function/SocketFunctionTypes";
@@ -527,6 +532,7 @@ declare module "socket-function/src/CallFactory" {
527
532
  }
528
533
 
529
534
  declare module "socket-function/src/JSONLACKS/JSONLACKS" {
535
+ /// <reference types="node" />
530
536
  /// <reference types="node" />
531
537
  export interface JSONLACKS_ParseConfig {
532
538
  extended?: boolean;
@@ -562,6 +568,7 @@ declare module "socket-function/src/JSONLACKS/JSONLACKS.generated.js" {
562
568
  }
563
569
 
564
570
  declare module "socket-function/src/Zip" {
571
+ /// <reference types="node" />
565
572
  /// <reference types="node" />
566
573
  import { MaybePromise } from "socket-function/src/types";
567
574
  export declare class Zip {
@@ -649,6 +656,7 @@ declare module "socket-function/src/batching" {
649
656
  }
650
657
 
651
658
  declare module "socket-function/src/bits" {
659
+ /// <reference types="node" />
652
660
  /// <reference types="node" />
653
661
  /** Subtracts the smallest possible value from a number (a double). This makes it possible to convert an exclusive range end
654
662
  * to an inclusive range end, which is sometimes required (as in, < x is the same as <= minusEpsilon(x)).
@@ -675,6 +683,7 @@ declare module "socket-function/src/bits" {
675
683
  }
676
684
 
677
685
  declare module "socket-function/src/buffers" {
686
+ /// <reference types="node" />
678
687
  /// <reference types="node" />
679
688
  export type ArrayBufferViewTypes = Uint8Array | Int8Array | Uint16Array | Int16Array | Uint32Array | Int32Array | BigUint64Array | BigInt64Array | Float64Array | Float32Array | Uint8ClampedArray;
680
689
  export type BufferType = ArrayBuffer | SharedArrayBuffer | ArrayBufferViewTypes;
@@ -752,6 +761,7 @@ declare module "socket-function/src/caching" {
752
761
  }
753
762
 
754
763
  declare module "socket-function/src/callHTTPHandler" {
764
+ /// <reference types="node" />
755
765
  /// <reference types="node" />
756
766
  /// <reference types="node" />
757
767
  import http from "http";
@@ -806,6 +816,7 @@ declare module "socket-function/src/callManager" {
806
816
  }
807
817
 
808
818
  declare module "socket-function/src/certStore" {
819
+ /// <reference types="node" />
809
820
  /// <reference types="node" />
810
821
  /** Must be populated before the server starts */
811
822
  export declare function trustCertificate(cert: string | Buffer): void;
@@ -971,6 +982,7 @@ declare module "socket-function/src/getUniqueTime" {
971
982
  }
972
983
 
973
984
  declare module "socket-function/src/https" {
985
+ /// <reference types="node" />
974
986
  /// <reference types="node" />
975
987
  export declare function httpsRequest(url: string, payload?: Buffer | Buffer[], method?: string, sendSessionCookies?: boolean, config?: {
976
988
  headers?: {
@@ -982,6 +994,7 @@ declare module "socket-function/src/https" {
982
994
  }
983
995
 
984
996
  declare module "socket-function/src/lz4/LZ4" {
997
+ /// <reference types="node" />
985
998
  /// <reference types="node" />
986
999
  export declare class LZ4 {
987
1000
  static compress(data: Buffer): Buffer;
@@ -1049,6 +1062,7 @@ declare module "socket-function/src/lz4/lz4_wasm_nodejs_bg.wasm" {
1049
1062
  }
1050
1063
 
1051
1064
  declare module "socket-function/src/misc" {
1065
+ /// <reference types="node" />
1052
1066
  /// <reference types="node" />
1053
1067
  import { MaybePromise } from "socket-function/src/types";
1054
1068
  export declare const timeInSecond = 1000;
@@ -1479,6 +1493,7 @@ declare module "socket-function/src/storagePath" {
1479
1493
  }
1480
1494
 
1481
1495
  declare module "socket-function/src/tlsParsing" {
1496
+ /// <reference types="node" />
1482
1497
  /// <reference types="node" />
1483
1498
  export declare function parseTLSHello(buffer: Buffer): {
1484
1499
  extensions: {
@@ -1508,6 +1523,7 @@ declare module "socket-function/src/upreal" {
1508
1523
  }
1509
1524
 
1510
1525
  declare module "socket-function/src/webSocketServer" {
1526
+ /// <reference types="node" />
1511
1527
  /// <reference types="node" />
1512
1528
  /// <reference types="node" />
1513
1529
  import https from "https";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "socket-function",
3
- "version": "1.2.14",
3
+ "version": "1.2.15",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {
@@ -1,5 +1,6 @@
1
1
  /// <reference path="../../typenode/index.d.ts" />
2
2
  /// <reference types="node" />
3
+ /// <reference types="node" />
3
4
  declare global {
4
5
  namespace NodeJS {
5
6
  interface Module {
@@ -1,3 +1,4 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  export declare function getExtContentType(ext: string): string;
3
4
  export declare function getContentTypeFromBuffer(buffer: Buffer): string | undefined;
@@ -1,5 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
+ /// <reference types="node" />
3
4
  import { CallType } from "../SocketFunctionTypes";
4
5
  import * as ws from "ws";
5
6
  import * as tls from "tls";
@@ -21,6 +21,13 @@ import { Zip } from "./Zip";
21
21
  import { decodeProtocol, proposeProtocols } from "./protocolNegotiation";
22
22
  setImmediate(() => import("./lz4/LZ4"));
23
23
 
24
+ // Cached in a plain variable because even though require/import caches modules, the lookup is still measurably slow on a hot path — and once cached the caller doesn't even need to await.
25
+ let lz4Cached: typeof import("./lz4/LZ4").LZ4 | undefined;
26
+ function getLZ4(): MaybePromise<typeof import("./lz4/LZ4").LZ4> {
27
+ if (lz4Cached) return lz4Cached;
28
+ return import("./lz4/LZ4").then(module => lz4Cached = module.LZ4);
29
+ }
30
+
24
31
  setFlag(require, "pako", "allowclient", true);
25
32
 
26
33
  // NOTE: If it is too low, and too many servers disconnect, we can easily spend 100% of our time
@@ -192,9 +199,10 @@ export async function createCallFactory(
192
199
  compressedSize: 0,
193
200
  };
194
201
  try {
195
- if (callFactory.receivedInitializeState?.supportsLZ4) {
202
+ if (SocketFunction.DISABLE_COMPRESSION) {
203
+ } else if (callFactory.receivedInitializeState?.supportsLZ4) {
196
204
  let compressMode = shouldCompressCall(fullCall);
197
- // If it's undefined, then we compress it. We basically always want to compress from now on, because LZ4 is so fast.
205
+ // If it's undefined, then we compress it. We basically always want to compress from now on, because LZ4 is so fast.
198
206
  if (compressMode !== false) {
199
207
  fullCall.args = await compressObjLZ4(fullCall.args, sendStats) as any;
200
208
  fullCall.isArgsCompressed = "LZ4";
@@ -488,7 +496,7 @@ export async function createCallFactory(
488
496
  let alternates = await SocketFunction.GET_ALTERNATE_NODE_IDS(nodeId);
489
497
  if (alternates) {
490
498
  for (let alternateNodeId of alternates) {
491
- let newWebSocket = createWebsocket(alternateNodeId, proposeProtocols(nodeId, { lz4: true }));
499
+ let newWebSocket = createWebsocket(alternateNodeId, proposeProtocols(nodeId, { lz4: !SocketFunction.DISABLE_COMPRESSION }));
492
500
  await initializeWebsocket(newWebSocket, true);
493
501
 
494
502
  if (callFactory.isConnected) {
@@ -500,7 +508,7 @@ export async function createCallFactory(
500
508
  console.error("Error getting alternate node IDs", e);
501
509
  }
502
510
 
503
- let newWebSocket = createWebsocket(nodeId, proposeProtocols(nodeId, { lz4: true }));
511
+ let newWebSocket = createWebsocket(nodeId, proposeProtocols(nodeId, { lz4: !SocketFunction.DISABLE_COMPRESSION }));
504
512
  await initializeWebsocket(newWebSocket);
505
513
 
506
514
  return newWebSocket;
@@ -635,7 +643,8 @@ export async function createCallFactory(
635
643
  let timeTaken = Date.now() - time;
636
644
  console.log(`DUR\t${(formatTime(timeTaken)).padEnd(6, " ")}\tFINISH\t${call.classGuid}.${call.functionName} at ${Date.now()}, (${nodeId} / ${localNodeId})`);
637
645
  }
638
- if (callFactory.receivedInitializeState?.supportsLZ4) {
646
+ if (SocketFunction.DISABLE_COMPRESSION) {
647
+ } else if (callFactory.receivedInitializeState?.supportsLZ4) {
639
648
  let compressMode = shouldCompressCall(call);
640
649
  if (compressMode !== false) {
641
650
  response.result = await compressObjLZ4(response.result, sendStats);
@@ -865,7 +874,7 @@ const decompressObj = measureWrap(async function wireCallDecompress(obj: Buffer,
865
874
  });
866
875
 
867
876
  const compressObjLZ4 = measureWrap(async function wireCallCompressLZ4(obj: unknown, stats: CompressionStats): Promise<Buffer[]> {
868
- const { LZ4 } = await import("./lz4/LZ4");
877
+ const LZ4 = await getLZ4();
869
878
  let headerParts: number[];
870
879
  let dataBuffers: Buffer[];
871
880
 
@@ -968,8 +977,10 @@ const compressObjLZ4 = measureWrap(async function wireCallCompressLZ4(obj: unkno
968
977
  });
969
978
 
970
979
  const decompressObjLZ4 = measureWrap(async function wireCallDecompressLZ4(obj: Buffer[], stats: CompressionStats): Promise<unknown> {
971
-
972
- const { LZ4 } = await import("./lz4/LZ4");
980
+ let LZ4 = getLZ4();
981
+ if (LZ4 instanceof Promise) {
982
+ LZ4 = await LZ4;
983
+ }
973
984
  stats.compressedSize += obj.reduce((sum, buf) => sum + buf.length, 0);
974
985
 
975
986
  let decompressed: Buffer[] = [];
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  export interface JSONLACKS_ParseConfig {
3
4
  extended?: boolean;
4
5
  discardMissingReferences?: boolean;
package/src/Zip.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { MaybePromise } from "./types";
3
4
  export declare class Zip {
4
5
  static gzip(buffer: Buffer, level?: number): Promise<Buffer>;
package/src/bits.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  /** Subtracts the smallest possible value from a number (a double). This makes it possible to convert an exclusive range end
3
4
  * to an inclusive range end, which is sometimes required (as in, < x is the same as <= minusEpsilon(x)).
4
5
  */
package/src/buffers.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  export type ArrayBufferViewTypes = Uint8Array | Int8Array | Uint16Array | Int16Array | Uint32Array | Int32Array | BigUint64Array | BigInt64Array | Float64Array | Float32Array | Uint8ClampedArray;
3
4
  export type BufferType = ArrayBuffer | SharedArrayBuffer | ArrayBufferViewTypes;
4
5
  export declare function cloneBuffer(data: Buffer): Buffer;
@@ -1,5 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
+ /// <reference types="node" />
3
4
  import http from "http";
4
5
  import { CallType } from "../SocketFunctionTypes";
5
6
  export declare function setDefaultHTTPCall(call: CallType): void;
@@ -128,6 +128,7 @@ export function unregisterGlobalClientHook(hook: SocketFunctionClientHook) {
128
128
  }
129
129
  }
130
130
 
131
+ let startupTime = Date.now();
131
132
  export const runClientHooks = measureWrap(async function runClientHooks(
132
133
  callType: FullCallType,
133
134
  hooks: Exclude<SocketExposedShape[""], undefined>,
@@ -149,8 +150,9 @@ export const runClientHooks = measureWrap(async function runClientHooks(
149
150
  await measureBlock(async () => {
150
151
  await hook(context);
151
152
  }, `clientHook|${hook.name || hook.toString().slice(0, 100)}`);
152
- time = Date.now() - time;
153
- if (time > 500) {
153
+ let now = Date.now();
154
+ time = now - time;
155
+ if (time > 500 && now - startupTime > 60_000) {
154
156
  console.warn(`Slow (${formatTime(time)}) client hook: ${JSON.stringify(hook.name || hook.toString().slice(0, 100))} for ${callType.classGuid}.${callType.functionName}(...)`);
155
157
  }
156
158
  // NOTE: See ClientHookContext.overrideResult for why we break here
@@ -171,8 +173,9 @@ export const runServerHooks = measureWrap(async function runServerHooks(
171
173
  for (let hook of globalHooks.concat(hooks.hooks || [])) {
172
174
  let time = Date.now();
173
175
  await _setSocketContext(caller, () => hook(hookContext));
174
- time = Date.now() - time;
175
- if (time > 500) {
176
+ let now = Date.now();
177
+ time = now - time;
178
+ if (time > 500 && now - startupTime > 60_000) {
176
179
  console.warn(`Slow (${formatTime(time)}) server hook: ${JSON.stringify(hook.name || hook.toString().slice(0, 100))} for ${callType.classGuid}.${callType.functionName}(...)`);
177
180
  }
178
181
  // NOTE: See HookContext.overrideResult for why we don't break here
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  /** Must be populated before the server starts */
3
4
  export declare function trustCertificate(cert: string | Buffer): void;
4
5
  export declare function getTrustedCertificates(): string[];
package/src/https.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  export declare function httpsRequest(url: string, payload?: Buffer | Buffer[], method?: string, sendSessionCookies?: boolean, config?: {
3
4
  headers?: {
4
5
  [key: string]: string | undefined;
package/src/lz4/LZ4.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  export declare class LZ4 {
3
4
  static compress(data: Buffer): Buffer;
4
5
  static compressUntracked(data: Buffer): Buffer;
package/src/misc.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { MaybePromise } from "./types";
3
4
  export declare const timeInSecond = 1000;
4
5
  export declare const timeInMinute: number;
@@ -78,7 +78,8 @@ export function proposeProtocols(target: string | undefined, clientCapabilities:
78
78
  }
79
79
  let out: string[] = [];
80
80
  let clientLZ4Options = clientCapabilities.lz4 ? [true, false] : [false];
81
- let serverLZ4Options = [true, false];
81
+ // When we don't want LZ4 we must not propose serverLZ4=1 at all — the server picks the first proposal it can serve, and the echoed serverLZ4 bit is what BOTH sides read as "this connection uses LZ4".
82
+ let serverLZ4Options = clientCapabilities.lz4 ? [true, false] : [false];
82
83
  let encodedTarget = target ?? WILDCARD_TARGET;
83
84
  for (let clientLZ4 of clientLZ4Options) {
84
85
  for (let serverLZ4 of serverLZ4Options) {
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  export declare function parseTLSHello(buffer: Buffer): {
3
4
  extensions: {
4
5
  type: number;
@@ -1,5 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
+ /// <reference types="node" />
3
4
  import https from "https";
4
5
  import { Watchable } from "./misc";
5
6
  export type SocketServerConfig = (https.ServerOptions & {
@@ -82,7 +82,7 @@ export async function startSocketServer(
82
82
  handleProtocols: (protocols, request) => {
83
83
  const ourNodeId = SocketFunction.mountedNodeId;
84
84
  const proposed = Array.from(protocols);
85
- const chosen = chooseProtocol(proposed, ourNodeId, { lz4: true });
85
+ const chosen = chooseProtocol(proposed, ourNodeId, { lz4: !SocketFunction.DISABLE_COMPRESSION });
86
86
  if (!chosen) {
87
87
  const proposedDecoded = proposed.map(p => decodeProtocol(p));
88
88
  let target = proposedDecoded[0]?.target;