socket-function 1.2.30 → 1.2.32

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.
@@ -62,6 +62,10 @@ export type ClientHookContext = {
62
62
  };
63
63
  export interface SocketFunctionClientHook {
64
64
  (config: ClientHookContext): MaybePromise<void>;
65
+ /** Set on hooks which are called so frequently (or are so trivial) that the measurement overhead
66
+ * and profiling noise outweighs the value of measuring them.
67
+ */
68
+ noMeasure?: boolean;
65
69
  }
66
70
  export interface SocketRegisterType<ExposedType = any> {
67
71
  _classGuid: string;
@@ -92,6 +92,10 @@ export type ClientHookContext = {
92
92
  };
93
93
  export interface SocketFunctionClientHook {
94
94
  (config: ClientHookContext): MaybePromise<void>;
95
+ /** Set on hooks which are called so frequently (or are so trivial) that the measurement overhead
96
+ * and profiling noise outweighs the value of measuring them.
97
+ */
98
+ noMeasure?: boolean;
95
99
  }
96
100
 
97
101
  export interface SocketRegisterType<ExposedType = any> {
package/index.d.ts CHANGED
@@ -194,6 +194,10 @@ declare module "socket-function/SocketFunctionTypes" {
194
194
  };
195
195
  export interface SocketFunctionClientHook {
196
196
  (config: ClientHookContext): MaybePromise<void>;
197
+ /** Set on hooks which are called so frequently (or are so trivial) that the measurement overhead
198
+ * and profiling noise outweighs the value of measuring them.
199
+ */
200
+ noMeasure?: boolean;
197
201
  }
198
202
  export interface SocketRegisterType<ExposedType = any> {
199
203
  _classGuid: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "socket-function",
3
- "version": "1.2.30",
3
+ "version": "1.2.32",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {
@@ -887,15 +887,20 @@ const compressObjLZ4 = measureWrap(async function wireCallCompressLZ4(obj: unkno
887
887
  const MIN_INDIVIDUAL_SIZE = 10 * 1024 * 1024;
888
888
  const MAX_UNSPLIT_SIZE = 100 * 1024 * 1024;
889
889
 
890
+ // The output buffers are purely a chunked-for-compression view: in order, their
891
+ // concatenation is always exactly the concatenation of every original buffer. Small buffers
892
+ // are grouped (concatenated) so we don't compress tiny inputs individually, and large buffers
893
+ // are split so we don't hand LZ4 a single huge input. Crucially, the logical array structure
894
+ // is NOT tied to these chunk boundaries - a single original may be split across several output
895
+ // buffers, and several originals may share one. The original sizes recorded in the header are
896
+ // what decompress uses to carve the reassembled bytes back into the original array.
890
897
  let outputBuffers: Buffer[] = [];
891
- let outputDescriptors: number[][] = [];
892
898
  let currentGroup: Buffer[] = [];
893
899
  let currentGroupSize = 0;
894
900
 
895
901
  function flushCurrentGroup() {
896
902
  if (currentGroup.length > 0) {
897
903
  outputBuffers.push(Buffer.concat(currentGroup));
898
- outputDescriptors.push(currentGroup.map(b => b.length));
899
904
  currentGroup = [];
900
905
  currentGroupSize = 0;
901
906
  }
@@ -910,12 +915,10 @@ const compressObjLZ4 = measureWrap(async function wireCallCompressLZ4(obj: unkno
910
915
  while (offset < buf.length) {
911
916
  let chunkSize = Math.min(TARGET_SIZE, buf.length - offset);
912
917
  outputBuffers.push(buf.slice(offset, offset + chunkSize));
913
- outputDescriptors.push([chunkSize]);
914
918
  offset += chunkSize;
915
919
  }
916
920
  } else {
917
921
  outputBuffers.push(buf);
918
- outputDescriptors.push([buf.length]);
919
922
  }
920
923
  } else {
921
924
  currentGroup.push(buf);
@@ -929,10 +932,8 @@ const compressObjLZ4 = measureWrap(async function wireCallCompressLZ4(obj: unkno
929
932
 
930
933
  flushCurrentGroup();
931
934
 
932
- headerParts = [2, outputBuffers.length];
933
- for (let descriptor of outputDescriptors) {
934
- headerParts.push(descriptor.length, ...descriptor);
935
- }
935
+ let originalSizes = bufferArray.map(buf => buf.length);
936
+ headerParts = [2, originalSizes.length, ...originalSizes];
936
937
  dataBuffers = outputBuffers;
937
938
  } else {
938
939
  let buffers = await SocketFunction.WIRE_SERIALIZER.serialize(obj);
@@ -1022,24 +1023,32 @@ const decompressObjLZ4 = measureWrap(async function wireCallDecompressLZ4(obj: B
1022
1023
 
1023
1024
  if (type === 2) {
1024
1025
  let headerData = new Float64Array(headerBuffer.buffer, headerBuffer.byteOffset, headerBuffer.byteLength / 8);
1025
- let outputBufferCount = headerData[1];
1026
+ let originalCount = headerData[1];
1026
1027
 
1028
+ // The data buffers are a chunked view whose concatenation equals the concatenation of every
1029
+ // original buffer, so walk them and carve out each original by its recorded size, splicing
1030
+ // across data-buffer boundaries when an original was split into multiple chunks (and taking
1031
+ // several originals from one data buffer when they were grouped). This is what makes a single
1032
+ // large buffer that was split for compression come back as ONE entry, not N.
1027
1033
  let buffers: Buffer[] = [];
1028
- let headerIndex = 2;
1029
-
1030
- for (let i = 0; i < outputBufferCount; i++) {
1031
- let inputBufferCount = headerData[headerIndex++];
1032
- let sizes: number[] = [];
1033
- for (let j = 0; j < inputBufferCount; j++) {
1034
- sizes.push(headerData[headerIndex++]);
1035
- }
1036
-
1037
- let outputBuffer = dataBuffers[i];
1038
- let offset = 0;
1039
- for (let size of sizes) {
1040
- buffers.push(outputBuffer.slice(offset, offset + size));
1041
- offset += size;
1034
+ let dataIndex = 0;
1035
+ let dataOffset = 0;
1036
+ for (let i = 0; i < originalCount; i++) {
1037
+ let remaining = headerData[2 + i];
1038
+ let parts: Buffer[] = [];
1039
+ while (remaining > 0) {
1040
+ let current = dataBuffers[dataIndex];
1041
+ let available = current.length - dataOffset;
1042
+ let take = Math.min(available, remaining);
1043
+ parts.push(current.slice(dataOffset, dataOffset + take));
1044
+ dataOffset += take;
1045
+ remaining -= take;
1046
+ if (dataOffset >= current.length) {
1047
+ dataIndex++;
1048
+ dataOffset = 0;
1049
+ }
1042
1050
  }
1051
+ buffers.push(parts.length === 1 ? parts[0] : Buffer.concat(parts));
1043
1052
  }
1044
1053
 
1045
1054
  return buffers;
@@ -147,9 +147,13 @@ export const runClientHooks = measureWrap(async function runClientHooks(
147
147
  }
148
148
  for (let hook of clientHooks) {
149
149
  let time = Date.now();
150
- await measureBlock(async () => {
150
+ if (hook.noMeasure) {
151
151
  await hook(context);
152
- }, `clientHook|${hook.name || hook.toString().slice(0, 100)}`);
152
+ } else {
153
+ await measureBlock(async () => {
154
+ await hook(context);
155
+ }, `clientHook|${hook.name || hook.toString().slice(0, 100)}`);
156
+ }
153
157
  let now = Date.now();
154
158
  time = now - time;
155
159
  if (time > 500 && now - startupTime > 60_000) {