querysub 0.356.0 → 0.358.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 (76) hide show
  1. package/.cursorrules +9 -0
  2. package/bin/movelogs.js +4 -0
  3. package/package.json +13 -6
  4. package/scripts/postinstall.js +23 -0
  5. package/src/-a-archives/archiveCache.ts +10 -12
  6. package/src/-a-archives/archives.ts +29 -0
  7. package/src/-a-archives/archivesBackBlaze.ts +60 -12
  8. package/src/-a-archives/archivesDisk.ts +39 -13
  9. package/src/-a-archives/archivesLimitedCache.ts +21 -0
  10. package/src/-a-archives/archivesMemoryCache.ts +374 -0
  11. package/src/-a-archives/archivesPrivateFileSystem.ts +22 -0
  12. package/src/-g-core-values/NodeCapabilities.ts +3 -0
  13. package/src/0-path-value-core/auditLogs.ts +5 -1
  14. package/src/0-path-value-core/pathValueCore.ts +7 -7
  15. package/src/4-dom/qreact.tsx +1 -0
  16. package/src/4-querysub/Querysub.ts +1 -5
  17. package/src/config.ts +5 -0
  18. package/src/deployManager/components/MachineDetailPage.tsx +43 -2
  19. package/src/deployManager/components/MachinesListPage.tsx +10 -2
  20. package/src/deployManager/machineApplyMainCode.ts +3 -3
  21. package/src/deployManager/machineSchema.ts +39 -0
  22. package/src/diagnostics/MachineThreadInfo.tsx +235 -0
  23. package/src/diagnostics/NodeViewer.tsx +5 -3
  24. package/src/diagnostics/logs/FastArchiveAppendable.ts +79 -42
  25. package/src/diagnostics/logs/FastArchiveController.ts +102 -63
  26. package/src/diagnostics/logs/FastArchiveViewer.tsx +36 -8
  27. package/src/diagnostics/logs/IndexedLogs/BufferIndex.ts +462 -0
  28. package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.cpp +327 -0
  29. package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.d.ts +18 -0
  30. package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.js +1 -0
  31. package/src/diagnostics/logs/IndexedLogs/BufferIndexHelpers.ts +222 -0
  32. package/src/diagnostics/logs/IndexedLogs/BufferIndexLogsOptimizationConstants.ts +22 -0
  33. package/src/diagnostics/logs/IndexedLogs/BufferIndexWAT.wat +1145 -0
  34. package/src/diagnostics/logs/IndexedLogs/BufferIndexWAT.wat.d.ts +178 -0
  35. package/src/diagnostics/logs/IndexedLogs/BufferListStreamer.ts +208 -0
  36. package/src/diagnostics/logs/IndexedLogs/BufferUnitIndex.ts +716 -0
  37. package/src/diagnostics/logs/IndexedLogs/BufferUnitSet.ts +146 -0
  38. package/src/diagnostics/logs/IndexedLogs/FilePathSelector.tsx +569 -0
  39. package/src/diagnostics/logs/IndexedLogs/FindProgressTracker.ts +45 -0
  40. package/src/diagnostics/logs/IndexedLogs/IndexedLogs.ts +685 -0
  41. package/src/diagnostics/logs/IndexedLogs/LogStreamer.ts +47 -0
  42. package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +901 -0
  43. package/src/diagnostics/logs/IndexedLogs/TimeFileTree.ts +236 -0
  44. package/src/diagnostics/logs/IndexedLogs/binding.gyp +23 -0
  45. package/src/diagnostics/logs/IndexedLogs/moveIndexLogsToPublic.ts +251 -0
  46. package/src/diagnostics/logs/IndexedLogs/moveLogsEntry.ts +10 -0
  47. package/src/diagnostics/logs/LogViewer2.tsx +120 -55
  48. package/src/diagnostics/logs/TimeRangeSelector.tsx +5 -2
  49. package/src/diagnostics/logs/diskLogger.ts +32 -48
  50. package/src/diagnostics/logs/errorNotifications/ErrorNotificationController.ts +3 -2
  51. package/src/diagnostics/logs/errorNotifications/errorDigests.tsx +1 -0
  52. package/src/diagnostics/logs/errorNotifications2/errorNotifications2.ts +0 -0
  53. package/src/diagnostics/logs/lifeCycleAnalysis/LifeCyclePages.tsx +150 -0
  54. package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycles.tsx +150 -15
  55. package/src/diagnostics/logs/lifeCycleAnalysis/test.ts +0 -0
  56. package/src/diagnostics/logs/lifeCycleAnalysis/test.wat +106 -0
  57. package/src/diagnostics/logs/lifeCycleAnalysis/test.wat.d.ts +2 -0
  58. package/src/diagnostics/logs/lifeCycleAnalysis/testHoist.ts +5 -0
  59. package/src/diagnostics/logs/logViewerExtractField.ts +2 -3
  60. package/src/diagnostics/managementPages.tsx +10 -0
  61. package/src/diagnostics/trackResources.ts +1 -1
  62. package/src/functional/limitProcessing.ts +39 -0
  63. package/src/misc/lz4_wasm_nodejs.d.ts +34 -0
  64. package/src/misc/lz4_wasm_nodejs.js +178 -0
  65. package/src/misc/lz4_wasm_nodejs_bg.js +94 -0
  66. package/src/misc/lz4_wasm_nodejs_bg.wasm +0 -0
  67. package/src/misc/lz4_wasm_nodejs_bg.wasm.d.ts +15 -0
  68. package/src/storage/CompressedStream.ts +13 -0
  69. package/src/storage/LZ4.ts +32 -0
  70. package/src/storage/ZSTD.ts +10 -0
  71. package/src/wat/watCompiler.ts +1716 -0
  72. package/src/wat/watGrammar.pegjs +93 -0
  73. package/src/wat/watHandler.ts +179 -0
  74. package/src/wat/watInstructions.txt +707 -0
  75. package/src/zip.ts +3 -89
  76. package/src/diagnostics/logs/lifeCycleAnalysis/spec.md +0 -125
@@ -1,16 +1,151 @@
1
- //todonext
2
- // Welp... no logs are showing up. That's a problem..
3
- // Ah, okay, we don't store logs locally. Because... we only log to backblaze? Alright, fair enough...
4
1
  /*
5
- 0) LIFECYCLES!
6
- - To debug auditting (to some degree)
7
- - To debug why servers are getting sent values from the wrong authority
8
- - This would be VERY interesting
9
- - Rewrite the spec for how to do this
10
- - One big thing is value association. As in, we want logs to be able to associate a session with a user. Even dynamically, so we might log somewhere saying this is the current user, and then we might log after that saying this is the session. And both of the logs might contain something saying this is the thread. And so we could say, okay, for the thread, the current user is this. And then when it says what the session is, we say, okay, well, the current user, which was defined earlier, has this session.
11
- - The biggest issue with this is caching, as now everything becomes one big bucket
12
- - We want to be able to cache the parsing of the logs with the different lifecycle specifications. That way, we can view even just specific life cycles, and it can be very fast to load it, even if we have billions of logs, which take hours to parse.
13
- - I think we do want the lifecycle parsing to be run in the background. We already have a lot of background scripts (although we haven't been running them for a long time).
14
- - Our log parsing is already pretty fast, which is good. So, then this will be even faster.
15
- - We will be need to be able to dynamically parse it though. And I guess we'll want to be able to parse it in the browser. And then that becomes a whole complicated thing to manage, but I think it's worth it.
16
- */
2
+ todonext
3
+
4
+ OKAY! CORE CONCEPTS
5
+ - Index needs to be fast searched, so it's uncompressed form has to be small
6
+ - Nesting compression is fine, as long as it's small enough that each search decompresses very little
7
+ - The enemy is storing every single position, we get around this by:
8
+ - In-exact matches, only storing block indexes.
9
+ - Requires full search to verify, but... in practice has low false hit rate
10
+ - Input key (unit) is only inexact matched.
11
+ - Input query almost always has more than 1 byte of uniqueness. This means if even part is only 50% accurate, we can still get very high hit rates (8 bytes means 255/256 hit rate!)
12
+
13
+
14
+ todonext
15
+
16
+
17
+
18
+ IMPORTANT! Now I am properly calling shutdown, so none of the streamed logs should ever break. The code should be waiting until everything's fully flushed before it allows the shutdown handler to finish running. If we see any more errors, we need to investigate them.
19
+
20
+
21
+
22
+ 4) Make it easy to enable or disable an entire server, regardless of what services are on it.
23
+ - This is annoying, but it would be very useful. I think the apply loop can probably figure it out. We should probably ask the AI to do it. I'm sure it'll fuck it up, but it'll give us a start at least. And we can also just tell it, okay, find the actual code that we're going to need to change, but not change it, and just keep and maybe even have it put a comment there. And then we just keep doing that until we're absolutely certain that we found every place that we need to change to make this work. And then the AI might be able to help with the refactor.
24
+ 3) Start the servers again, and deploy all of our code
25
+
26
+ 2) Create lot of remote server logs
27
+ - Via our refresh loop
28
+
29
+ 2.0) SUPPORT reading pending from multiple servers
30
+ - The main controller has to find a node on each other machine, and call it. Only one node per machine though, so it shouldn't be too difficult.
31
+ - We'll cache the last node per machine that we picked.
32
+ - If the cache value doesn't exist, or if it doesn't work, if it throws an error when we try to verify it works, then we'll call a function to get the entry point on all of the nodes for that machine
33
+ - After we receive the first result, we'll wait at least a second so we get some more results, and then we'll prioritize the one that's the function endpoint, which will end in function.js.
34
+
35
+ 2) Add a UI toggle to read public logs (only shows up on a non-public server though, as otherwise it wouldn't make sense)
36
+ - Basically, just changes the code we're reading from multiple servers to select public servers instead, and then, of course, skip ourselves.
37
+
38
+ 3) Verify true remote reads are reasonable fast
39
+
40
+ 3) Deploy service for movelogs
41
+ 0) Run move logs in function runner, in development, just so we don't get too far behind
42
+
43
+
44
+
45
+
46
+
47
+ 1) Fix missing __NAME__
48
+ "Received PathValue for path" misses name?
49
+ - Maybe the missing name only happens when we rate limit?
50
+
51
+
52
+
53
+
54
+ Rewrite error notification code
55
+ THINK about how to do a somewhat generic logs => derived thing, as... we will need the exact same thing for life cycles!
56
+ - Maybe make it generic immediately? Having it abstracted it kind of nice for development anyways...
57
+ - New service that manages it, instead of doing it on demand
58
+ - It asks everyone to send it error logs
59
+ - Stores cached error logs => { unsuppressed logs, suppressionSummary }
60
+ - Unsuppressed logs only for suppression which is old enough.
61
+ - Only when logs are old enough.
62
+ - Stores in memory with all suppressionSummaries
63
+ AND, the only watcher will be the watcher service. You can't get recent errors, or any errors, without going through one of those
64
+ NO dev errors. They are usually red-herrings anyways... and we should just be using public servers for regular usage
65
+ - And we still have dev logs we can check if to see if an error happened locally
66
+
67
+
68
+
69
+ Remove all old LogViewer/FastArchiveAppendable code
70
+
71
+
72
+ 0) Add LZ4 compression to socket-function by default
73
+ - Allow setting "compress" to "none" or "lz4" or "zip" or "zip0" or "zip3", etc, for levels.
74
+ - default is "lz4"
75
+ - REQUIRES feature checking the remote, to make sure it is new enough to accept this.
76
+ - A generic thing which gets the version is probably fine.
77
+ - LZ4 compression is fast enough that this should cause basically no overhead, and in many cases greatly reduce the bandwidth (which will increase the speed).
78
+ - We're gonna have to investigate how we're sending buffers anyway. I think this should be easy, but we
79
+ 0.1) Verify the size distance with some local testing
80
+ - ALSO, verify the processing overhead is acceptable.
81
+ 1) Deploy, which SHOULD be backwards compatible with everything?
82
+
83
+ */
84
+
85
+
86
+
87
+
88
+
89
+ // todonext;
90
+ // Hmm... so... should we index it, so we can search it? HMM... I think we might want to?
91
+ // - Although the searches might get a bit complicated...
92
+ // - I think we need to limit lifecycle lengths? Hmm... as otherwise we need a lot in memory at once?
93
+ // - We could always do it based on size, so if we have too many logs the max time length is less
94
+ // 7) Decide how we're going to store it, and setup the controller
95
+ // 8) Get the AI to set up some basic UI to manage it.
96
+ // - For now, we'll run the phases one after the other. Controlled by the caller. Caching is going to come much later.
97
+ // - The first phase I think we can run when we receive the logs directly. This will make progress nice. And then the second phase will run automatically in the finish function. We'll have to add additional progress for that, which shouldn't be too difficult.
98
+ // - Having the finish function fork off into an async is probably fine, although we will have to expose the cancellation promise to the finish function?
99
+ // - Or do we even need cancellation? Are we ever going to even keep this code? So if we have a server precaching the values, we still need the pending values to be parsed somewhere. Hmm... That's annoying. Are we just not going to use fast archives for this?
100
+ // - MAYBE We can have the Fast Archives support external caching, so it'll give us the name of the file, and we'll tell it if it's cached or not. Actually, it can give us the name of all the files, and we'll tell it if we have a cached result for it. And if we do, we'll load the cache result, and it won't do any of the parsing of that file.
101
+ // 9) Stress test it, by automating something to load a page repeatedly (which should cause a lot of path logs). We should try at least 10K page refreshes, and nothing should break...
102
+ // - If my estimates are correct, and a page load of a large book results in ~5K logs, that will use ~2.5MB of uncompressed space, (~100KB compressed). Which... is acceptable. 10K page loads is 1GB, so a million would cost 1 USD/month to store. AND that's if we keep storing all audits in the logs, which we don't really have to do...
103
+ // - Processing it, on the other hand, will be kind of slow. Looks like we decompress about ten MB a second. But... there's not much we can do about that... unless... we searched on the compressed data directly? Hmm... or at least optimized based on it.
104
+ // 10) Add log file overview page, so we can keep an eye on the size of logs
105
+ // 10.1) Start storing the log count in the log file names
106
+ // - WHICH, requires breaking all of our old logs, but... that's not too big of deal
107
+ // - ONLY for the non-pending logs
108
+ // 11) Pull requests our lz4-wasm code. It's purely AI generated, but it might be of some interest.
109
+ // - As in, supporting streaming and decoding from a stream
110
+ // - REMEMBER to delete all of our test files and test code, and also really clean up the pull request before we make it.
111
+ /*
112
+ Two phases, and second phase has limitted, as some of our life cycles might explode quadratically.
113
+ */
114
+
115
+
116
+ // logs => life cycle related => life cycle group by key => life cycle list, with each one being expandable
117
+
118
+ // Searching in previous state
119
+ // Using variables from logs?
120
+ // Using variables from lifecycle?
121
+ // The FORM we match will be pretty much always the same (not depending on variables). If we absolutely need to we can do some late filtering in the second phase, but I don't think we'll need to. However the life cycle it becomes a part of, that will depend on the state.
122
+ // OH! The start lifecycle entry will create a lifecycle, THEN we match. The later matches might not be as restrictive as the start life cycle. SOO...
123
+ // start = [path, clientId]
124
+ // watch = [path]
125
+ // AND SO, This is what we can do to kind of expand our paths. So really, it's more of a debug thing, where the start is something that provides a key for what we're debugging. And then after it, we'll have different lines which can match whichever data we want.
126
+ // - The only restriction is the other lines have to happen after the start and before the end.
127
+ // - The end will be the first end matched as well
128
+ // - AND Optionally, you can make it so that the start ends the previous one
129
+ // - And you can also just not provide an end. There's no reason the life cycle needs to end.
130
+ // - I think technically if you add a start and it keeps triggering and you don't tell it that it should end the previous one, then there'll be a lot of overlapping and some of the life cycles will get quite large. But we can handle that by throttling and lazy evaluation, so it shouldn't actually be an issue.
131
+ // todonext;
132
+ // // Okay, so it's looking like the first thing we're going to do is match the start, and then once we find the start, if we want to expand that life cycle, then we do a second phase search.
133
+ // todonext;
134
+ // // HMM... So actually what kind of variables do we need? I guess if we want to map between IDs. But then can't we just Match some line That gives us the mapping. And then, presumably, that'll be early on in the life cycle....
135
+ // todonext;
136
+ // // OH! Okay, so we want to allow some logs in the life cycle to match before the start? But that's all. They just match before the start. And I think we have to define how long they can match before the start. Obviously, we can't search forever. And then they're just normal lines after that. They can set life cycle variables, and we can access life cycle variables.
137
+ // todonext;
138
+ // // Yes, so... The variables are going to be a lot simple. It's just the lifecycle will have variables associated with it, which lines in the life cycle can set.
139
+ // todonext;
140
+ // // Let's not have any regex parsing either. Lifecycles entries can just say, I care about these variables and we expect them to be a part of the log object, and then we add them to the lifecycle.
141
+ // // - Which is really more for UI organization, as we can say these are important. And prevents the bug of some random log having to have happen to having a thread ID, but we have a thread ID and we mean the client thread ID, etc., etc. We just make it explicit per line, and then we don't run into that bug ever.
142
+
143
+ // TODO: Eventually, if we need it, we can have entries find other life cycles, either matching many, the latest, etc, and take variables from them PURELY FOR DISPLAY PURPOSES. But right at this moment, that's not needed.
144
+
145
+ type LifeCycle = {
146
+
147
+ };
148
+
149
+ type LifeCycleEntry = {
150
+
151
+ };
File without changes
@@ -0,0 +1,106 @@
1
+ (module
2
+ ;; Import memory from JavaScript (with memory64 support for >4GB).
3
+ ;; Callers use allocateBuffer(exports, size) from supportWat.ts to
4
+ ;; request scratch regions; memory will be grown automatically as needed.
5
+ (import "env" "memory" (memory i64 1))
6
+
7
+ ;; Export the heap base so the allocator knows where static data ends.
8
+ ;; With no static data section here, the heap starts at byte 0.
9
+ (global (export "__heap_base") i32 (i32.const 0))
10
+
11
+ ;; Add function: adds two i32 integers
12
+ (func $add (param $a i32) (param $b i32) (result i32)
13
+ local.get $a
14
+ local.get $b
15
+ i32.add
16
+ )
17
+ (export "add" (func $add))
18
+
19
+ ;; Multiply function: multiplies two i32 integers
20
+ (func $multiply (param $a i32) (param $b i32) (result i32)
21
+ local.get $a
22
+ local.get $b
23
+ i32.mul
24
+ )
25
+ (export "multiply" (func $multiply))
26
+
27
+ ;; stddev(offset: i32, count: i32) -> f64
28
+ ;;
29
+ ;; Computes the population standard deviation of `count` f64 values
30
+ ;; stored contiguously in memory starting at byte `offset`.
31
+ ;; Each value occupies 8 bytes (little-endian IEEE 754 double).
32
+ ;; Returns 0.0 when count == 0.
33
+ (func $stddev (param $offset i32) (param $count i32) (result f64)
34
+ (local $i i32)
35
+ (local $sum f64)
36
+ (local $mean f64)
37
+ (local $diff f64)
38
+ (local $variance_sum f64)
39
+
40
+ ;; Guard: return 0 if count == 0
41
+ (if (i32.eqz (local.get $count))
42
+ (then (return (f64.const 0)))
43
+ )
44
+
45
+ ;; Pass 1: compute sum
46
+ (local.set $i (i32.const 0))
47
+ (local.set $sum (f64.const 0))
48
+ (block $break1
49
+ (loop $loop1
50
+ (br_if $break1 (i32.ge_u (local.get $i) (local.get $count)))
51
+ (local.set $sum
52
+ (f64.add
53
+ (local.get $sum)
54
+ (f64.load
55
+ (i32.add
56
+ (local.get $offset)
57
+ (i32.mul (local.get $i) (i32.const 8))
58
+ )
59
+ )
60
+ )
61
+ )
62
+ (local.set $i (i32.add (local.get $i) (i32.const 1)))
63
+ (br $loop1)
64
+ )
65
+ )
66
+
67
+ ;; mean = sum / count
68
+ (local.set $mean
69
+ (f64.div (local.get $sum) (f64.convert_i32_u (local.get $count)))
70
+ )
71
+
72
+ ;; Pass 2: compute sum of squared deviations
73
+ (local.set $i (i32.const 0))
74
+ (local.set $variance_sum (f64.const 0))
75
+ (block $break2
76
+ (loop $loop2
77
+ (br_if $break2 (i32.ge_u (local.get $i) (local.get $count)))
78
+ (local.set $diff
79
+ (f64.sub
80
+ (f64.load
81
+ (i32.add
82
+ (local.get $offset)
83
+ (i32.mul (local.get $i) (i32.const 8))
84
+ )
85
+ )
86
+ (local.get $mean)
87
+ )
88
+ )
89
+ (local.set $variance_sum
90
+ (f64.add
91
+ (local.get $variance_sum)
92
+ (f64.mul (local.get $diff) (local.get $diff))
93
+ )
94
+ )
95
+ (local.set $i (i32.add (local.get $i) (i32.const 1)))
96
+ (br $loop2)
97
+ )
98
+ )
99
+
100
+ ;; return sqrt(variance_sum / count)
101
+ (f64.sqrt
102
+ (f64.div (local.get $variance_sum) (f64.convert_i32_u (local.get $count)))
103
+ )
104
+ )
105
+ (export "stddev" (func $stddev))
106
+ )
@@ -0,0 +1,2 @@
1
+ export const add: (a: number, b: number) => number;
2
+ export const multiply: (a: number, b: number) => number;
@@ -0,0 +1,5 @@
1
+ import "../../../forceProduction";
2
+ import "../../../inject";
3
+ import { chdir } from "process";
4
+ chdir("D:/repos/qs-cyoa/");
5
+ import "./test";
@@ -2,7 +2,7 @@ import { ScanFnc } from "./FastArchiveViewer";
2
2
 
3
3
  export function createLogViewerExtractField(
4
4
  fieldName: string,
5
- onFieldValue: (value: string) => void,
5
+ onFieldValue: (value: string, unpackedSize: number) => void,
6
6
  ): ScanFnc {
7
7
  let fieldNameBuffer = Buffer.from(`${JSON.stringify(fieldName)}:"`);
8
8
  let quoteChar = Buffer.from(`"`)[0];
@@ -19,7 +19,7 @@ export function createLogViewerExtractField(
19
19
  let start = i + j + 1;
20
20
  for (let k = start; k < posEnd; k++) {
21
21
  if (data[k] === quoteChar) {
22
- onFieldValue(data.slice(start, k).toString());
22
+ onFieldValue(data.slice(start, k).toString(), posEnd - start);
23
23
  break;
24
24
  }
25
25
  if (data[k] === escapeChar) {
@@ -31,7 +31,6 @@ export function createLogViewerExtractField(
31
31
  }
32
32
  }
33
33
  }
34
- onFieldValue("");
35
34
  return false;
36
35
  };
37
36
  }
@@ -91,6 +91,16 @@ export async function registerManagementPages2(config: {
91
91
  componentName: "LogViewer2",
92
92
  getModule: () => import("./logs/LogViewer2"),
93
93
  });
94
+ inputPages.push({
95
+ title: "Logs3",
96
+ componentName: "LogViewer3",
97
+ getModule: () => import("./logs/IndexedLogs/LogViewer3"),
98
+ });
99
+ inputPages.push({
100
+ title: "Life Cycles",
101
+ componentName: "LifeCyclePages",
102
+ getModule: () => import("./logs/lifeCycleAnalysis/LifeCyclePages"),
103
+ });
94
104
  inputPages.push({
95
105
  title: "Error Digests",
96
106
  componentName: "ErrorDigestPage",
@@ -86,7 +86,7 @@ function logResourcesNow() {
86
86
  }
87
87
 
88
88
  registerMeasureInfo(() => {
89
- return `${formatNumber(getUsedHeapSize())}B+${formatNumber(getBufferUsage())}B/${formatNumber(getHeapSize())}B`;
89
+ return `MEM ${formatNumber(getUsedHeapSize())}B+${formatNumber(getBufferUsage())}B/${formatNumber(getHeapSize())}B `;
90
90
  });
91
91
 
92
92
  registerPeriodic(logResourcesNow);
@@ -0,0 +1,39 @@
1
+ import { measureFnc } from "socket-function/src/profiling/measure";
2
+ import { MaybePromise } from "socket-function/src/types";
3
+
4
+ export class LimitGroup {
5
+ /** We have processing sections. In each section, if we exceed the current maximum wait, then any new processing will be told that it needs to wait. And then at the end of the section we wait wait time. This can be zero, which is fine, and we'll should wait enough time for networking, etc to run. */
6
+ constructor(public config: {
7
+ maxTimePerBeforeWait: number;
8
+ waitTime: number;
9
+ }) { }
10
+
11
+ private sectionStartTime: number | undefined = undefined;
12
+ private afterSectionResolvers: (() => void)[] = [];
13
+
14
+ @measureFnc
15
+ public wait(): MaybePromise<void> {
16
+ if (this.sectionStartTime === undefined) {
17
+ this.sectionStartTime = Date.now();
18
+ setTimeout(async () => {
19
+ await new Promise(resolve => setTimeout(resolve, this.config.waitTime));
20
+
21
+ this.sectionStartTime = undefined;
22
+ const resolvers = this.afterSectionResolvers;
23
+ this.afterSectionResolvers = [];
24
+ for (const resolve of resolvers) {
25
+ resolve();
26
+ }
27
+ }, 0);
28
+ }
29
+
30
+ const elapsed = Date.now() - this.sectionStartTime;
31
+ if (elapsed >= this.config.maxTimePerBeforeWait) {
32
+ return new Promise<void>((resolve) => {
33
+ this.afterSectionResolvers.push(resolve);
34
+ });
35
+ }
36
+
37
+ return undefined;
38
+ }
39
+ }
@@ -0,0 +1,34 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * Streaming LZ4 compressor (frame format with linked blocks).
6
+ * Concatenate all output chunks to form a complete LZ4 frame.
7
+ */
8
+ export class Lz4StreamCompressor {
9
+ free(): void;
10
+ [Symbol.dispose](): void;
11
+ compress(input: Uint8Array): Uint8Array;
12
+ constructor();
13
+ }
14
+
15
+ /**
16
+ * One-shot block compression with size prepended.
17
+ */
18
+ export function compress(input: Uint8Array): Uint8Array;
19
+
20
+ /**
21
+ * One-shot block decompression with size prepended.
22
+ */
23
+ export function decompress(input: Uint8Array): Uint8Array;
24
+
25
+ /**
26
+ * Decompress an LZ4 stream (frame format).
27
+ * Auto-injects end marker if missing. On error, returns partial data and sets a warning.
28
+ */
29
+ export function decompress_stream(input: Uint8Array): Uint8Array;
30
+
31
+ /**
32
+ * Get and clear the last warning from decompression.
33
+ */
34
+ export function get_last_warning(): string | undefined;