ugly-app 0.1.331 → 0.1.332
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/coverage/{server/RateLimit.ts.html → NatsProxyClient.ts.html} +406 -445
- package/coverage/clover.xml +140 -3813
- package/coverage/coverage-final.json +1 -68
- package/coverage/index.html +14 -224
- package/dist/cli/version.d.ts +1 -1
- package/dist/cli/version.js +1 -1
- package/dist/markdown/shared/Comments.d.ts +16 -0
- package/dist/markdown/shared/Comments.d.ts.map +1 -0
- package/dist/markdown/shared/Comments.js +122 -0
- package/dist/markdown/shared/Comments.js.map +1 -0
- package/dist/markdown/shared/KatexLazy.d.ts +41 -0
- package/dist/markdown/shared/KatexLazy.d.ts.map +1 -0
- package/dist/markdown/shared/KatexLazy.js +104 -0
- package/dist/markdown/shared/KatexLazy.js.map +1 -0
- package/dist/markdown/shared/MdastParser.d.ts +59 -0
- package/dist/markdown/shared/MdastParser.d.ts.map +1 -0
- package/dist/markdown/shared/MdastParser.js +695 -0
- package/dist/markdown/shared/MdastParser.js.map +1 -0
- package/dist/markdown/shared/MdastTypes.d.ts +202 -0
- package/dist/markdown/shared/MdastTypes.d.ts.map +1 -0
- package/dist/markdown/shared/MdastTypes.js +9 -0
- package/dist/markdown/shared/MdastTypes.js.map +1 -0
- package/dist/markdown/shared/index.d.ts +6 -0
- package/dist/markdown/shared/index.d.ts.map +1 -0
- package/dist/markdown/shared/index.js +4 -0
- package/dist/markdown/shared/index.js.map +1 -0
- package/dist/server/DataProxyClient.d.ts.map +1 -1
- package/dist/server/DataProxyClient.js +12 -6
- package/dist/server/DataProxyClient.js.map +1 -1
- package/dist/server/Strings.js.map +1 -1
- package/dist/shared/Strings.d.ts +1 -1
- package/dist/shared/Strings.d.ts.map +1 -1
- package/package.json +13 -1
- package/src/cli/version.ts +1 -1
- package/src/markdown/shared/Comments.ts +156 -0
- package/src/markdown/shared/KatexLazy.ts +133 -0
- package/src/markdown/shared/MdastParser.ts +838 -0
- package/src/markdown/shared/MdastTypes.ts +288 -0
- package/src/markdown/shared/index.ts +76 -0
- package/src/server/DataProxyClient.ts +12 -6
- package/src/server/Strings.ts +1 -1
- package/src/shared/Strings.ts +1 -1
- package/templates/client/allPages.ts +1 -0
- package/templates/client/main.tsx +11 -0
- package/templates/client/pages/StringsTestPage.tsx +74 -0
- package/templates/client/pages/TestIndexPage.tsx +1 -0
- package/templates/server/index.ts +13 -0
- package/templates/shared/lang/en.ts +13 -0
- package/templates/shared/lang/es.ts +13 -0
- package/templates/shared/pages.ts +1 -0
- package/templates/shared/strings.ts +26 -0
- package/coverage/client/AppProvider.tsx.html +0 -820
- package/coverage/client/FeedbackContext.ts.html +0 -133
- package/coverage/client/LoginPopup.tsx.html +0 -337
- package/coverage/client/Router.tsx.html +0 -2230
- package/coverage/client/Screenshot.ts.html +0 -790
- package/coverage/client/ViewFlipper.tsx.html +0 -778
- package/coverage/client/animation/Animated.tsx.html +0 -544
- package/coverage/client/animation/animatedValue.ts.html +0 -721
- package/coverage/client/animation/index.html +0 -131
- package/coverage/client/components/Button.tsx.html +0 -379
- package/coverage/client/components/FeedbackButton.tsx.html +0 -631
- package/coverage/client/components/Input.tsx.html +0 -286
- package/coverage/client/components/Modal.tsx.html +0 -277
- package/coverage/client/components/Text.tsx.html +0 -349
- package/coverage/client/components/Toast.tsx.html +0 -235
- package/coverage/client/components/index.html +0 -206
- package/coverage/client/components/zIndex.ts.html +0 -118
- package/coverage/client/createSocket.ts.html +0 -2248
- package/coverage/client/index.html +0 -206
- package/coverage/collab/server/CollabServer.ts.html +0 -1681
- package/coverage/collab/server/index.html +0 -116
- package/coverage/server/Cache.ts.html +0 -568
- package/coverage/server/DB.ts.html +0 -1546
- package/coverage/server/DataProxyClient.ts.html +0 -1585
- package/coverage/server/Email.ts.html +0 -355
- package/coverage/server/EmailTemplate.ts.html +0 -223
- package/coverage/server/EventLogAdmin.ts.html +0 -1486
- package/coverage/server/PushNotification.ts.html +0 -400
- package/coverage/server/Router.ts.html +0 -520
- package/coverage/server/SchemaCheck.ts.html +0 -484
- package/coverage/server/Socket.ts.html +0 -1534
- package/coverage/server/ai/ImageGenClient.ts.html +0 -142
- package/coverage/server/ai/ProviderBalance.ts.html +0 -184
- package/coverage/server/ai/TextGenClient.ts.html +0 -244
- package/coverage/server/ai/WebSearchClient.ts.html +0 -190
- package/coverage/server/ai/index.html +0 -191
- package/coverage/server/ai/index.ts.html +0 -187
- package/coverage/server/ai/providers/UglyBotImageGenProvider.ts.html +0 -157
- package/coverage/server/ai/providers/UglyBotTextGenProvider.ts.html +0 -343
- package/coverage/server/ai/providers/UglyBotWebSearchProvider.ts.html +0 -271
- package/coverage/server/ai/providers/index.html +0 -146
- package/coverage/server/ai/types.ts.html +0 -520
- package/coverage/server/billing/BillingGateway.ts.html +0 -868
- package/coverage/server/billing/BillingLedger.ts.html +0 -910
- package/coverage/server/billing/CreditStore.ts.html +0 -577
- package/coverage/server/billing/LimitEnforcer.ts.html +0 -1237
- package/coverage/server/billing/UserLimitCache.ts.html +0 -388
- package/coverage/server/billing/index.html +0 -191
- package/coverage/server/billing/types.ts.html +0 -889
- package/coverage/server/embeddings/EmbeddingClient.ts.html +0 -217
- package/coverage/server/embeddings/index.html +0 -131
- package/coverage/server/embeddings/providers/OpenAI.ts.html +0 -136
- package/coverage/server/embeddings/providers/index.html +0 -116
- package/coverage/server/embeddings/registry.ts.html +0 -151
- package/coverage/server/index.html +0 -281
- package/coverage/server/uglyBotProxy.ts.html +0 -220
- package/coverage/shared/Api.ts.html +0 -640
- package/coverage/shared/Audio.ts.html +0 -1318
- package/coverage/shared/DB.ts.html +0 -1948
- package/coverage/shared/Errors.ts.html +0 -145
- package/coverage/shared/Experiment.ts.html +0 -298
- package/coverage/shared/FrameworkMessages.ts.html +0 -136
- package/coverage/shared/FrameworkRequests.ts.html +0 -538
- package/coverage/shared/ImageGen.ts.html +0 -1861
- package/coverage/shared/Router.ts.html +0 -538
- package/coverage/shared/SchemaDiff.ts.html +0 -634
- package/coverage/shared/SchemaSerializer.ts.html +0 -517
- package/coverage/shared/TextGen.ts.html +0 -3076
- package/coverage/shared/UglyBotMessages.ts.html +0 -211
- package/coverage/shared/Voice.ts.html +0 -331
- package/coverage/shared/index.html +0 -341
- package/coverage/shared/index.ts.html +0 -541
- package/coverage/shared/uglyBotUrl.ts.html +0 -151
- package/coverage/three/server/VideoEncoder.ts.html +0 -2248
- package/coverage/three/server/index.html +0 -116
- package/coverage/three/shared/CameraController.ts.html +0 -1519
- package/coverage/three/shared/PostProcessing.ts.html +0 -1771
- package/coverage/three/shared/index.html +0 -131
- package/coverage/webrtc/server/VideoRoomServer.ts.html +0 -1726
- package/coverage/webrtc/server/index.html +0 -116
- package/coverage/worker/TaskHost.ts.html +0 -865
- package/coverage/worker/index.html +0 -116
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
<html lang="en">
|
|
4
4
|
|
|
5
5
|
<head>
|
|
6
|
-
<title>Code coverage report for
|
|
6
|
+
<title>Code coverage report for NatsProxyClient.ts</title>
|
|
7
7
|
<meta charset="utf-8" />
|
|
8
|
-
<link rel="stylesheet" href="
|
|
9
|
-
<link rel="stylesheet" href="
|
|
10
|
-
<link rel="shortcut icon" type="image/x-icon" href="
|
|
8
|
+
<link rel="stylesheet" href="prettify.css" />
|
|
9
|
+
<link rel="stylesheet" href="base.css" />
|
|
10
|
+
<link rel="shortcut icon" type="image/x-icon" href="favicon.png" />
|
|
11
11
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
12
12
|
<style type='text/css'>
|
|
13
13
|
.coverage-summary .sorter {
|
|
14
|
-
background-image: url(
|
|
14
|
+
background-image: url(sort-arrow-sprite.png);
|
|
15
15
|
}
|
|
16
16
|
</style>
|
|
17
17
|
</head>
|
|
@@ -19,34 +19,34 @@
|
|
|
19
19
|
<body>
|
|
20
20
|
<div class='wrapper'>
|
|
21
21
|
<div class='pad1'>
|
|
22
|
-
<h1><a href="
|
|
22
|
+
<h1><a href="index.html">All files</a> NatsProxyClient.ts</h1>
|
|
23
23
|
<div class='clearfix'>
|
|
24
24
|
|
|
25
25
|
<div class='fl pad1y space-right2'>
|
|
26
|
-
<span class="strong">
|
|
26
|
+
<span class="strong">100% </span>
|
|
27
27
|
<span class="quiet">Statements</span>
|
|
28
|
-
<span class='fraction'>
|
|
28
|
+
<span class='fraction'>140/140</span>
|
|
29
29
|
</div>
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
<div class='fl pad1y space-right2'>
|
|
33
|
-
<span class="strong">
|
|
33
|
+
<span class="strong">100% </span>
|
|
34
34
|
<span class="quiet">Branches</span>
|
|
35
|
-
<span class='fraction'>
|
|
35
|
+
<span class='fraction'>32/32</span>
|
|
36
36
|
</div>
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
<div class='fl pad1y space-right2'>
|
|
40
40
|
<span class="strong">100% </span>
|
|
41
41
|
<span class="quiet">Functions</span>
|
|
42
|
-
<span class='fraction'>
|
|
42
|
+
<span class='fraction'>35/35</span>
|
|
43
43
|
</div>
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
<div class='fl pad1y space-right2'>
|
|
47
47
|
<span class="strong">100% </span>
|
|
48
48
|
<span class="quiet">Lines</span>
|
|
49
|
-
<span class='fraction'>
|
|
49
|
+
<span class='fraction'>134/134</span>
|
|
50
50
|
</div>
|
|
51
51
|
|
|
52
52
|
|
|
@@ -384,27 +384,7 @@
|
|
|
384
384
|
<a name='L319'></a><a href='#L319'>319</a>
|
|
385
385
|
<a name='L320'></a><a href='#L320'>320</a>
|
|
386
386
|
<a name='L321'></a><a href='#L321'>321</a>
|
|
387
|
-
<a name='L322'></a><a href='#L322'>322</a>
|
|
388
|
-
<a name='L323'></a><a href='#L323'>323</a>
|
|
389
|
-
<a name='L324'></a><a href='#L324'>324</a>
|
|
390
|
-
<a name='L325'></a><a href='#L325'>325</a>
|
|
391
|
-
<a name='L326'></a><a href='#L326'>326</a>
|
|
392
|
-
<a name='L327'></a><a href='#L327'>327</a>
|
|
393
|
-
<a name='L328'></a><a href='#L328'>328</a>
|
|
394
|
-
<a name='L329'></a><a href='#L329'>329</a>
|
|
395
|
-
<a name='L330'></a><a href='#L330'>330</a>
|
|
396
|
-
<a name='L331'></a><a href='#L331'>331</a>
|
|
397
|
-
<a name='L332'></a><a href='#L332'>332</a>
|
|
398
|
-
<a name='L333'></a><a href='#L333'>333</a>
|
|
399
|
-
<a name='L334'></a><a href='#L334'>334</a>
|
|
400
|
-
<a name='L335'></a><a href='#L335'>335</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
|
|
401
|
-
<span class="cline-any cline-neutral"> </span>
|
|
402
|
-
<span class="cline-any cline-neutral"> </span>
|
|
403
|
-
<span class="cline-any cline-neutral"> </span>
|
|
404
|
-
<span class="cline-any cline-neutral"> </span>
|
|
405
|
-
<span class="cline-any cline-neutral"> </span>
|
|
406
|
-
<span class="cline-any cline-neutral"> </span>
|
|
407
|
-
<span class="cline-any cline-neutral"> </span>
|
|
387
|
+
<a name='L322'></a><a href='#L322'>322</a></td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
|
|
408
388
|
<span class="cline-any cline-neutral"> </span>
|
|
409
389
|
<span class="cline-any cline-neutral"> </span>
|
|
410
390
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -415,23 +395,50 @@
|
|
|
415
395
|
<span class="cline-any cline-neutral"> </span>
|
|
416
396
|
<span class="cline-any cline-neutral"> </span>
|
|
417
397
|
<span class="cline-any cline-neutral"> </span>
|
|
398
|
+
<span class="cline-any cline-yes">37x</span>
|
|
399
|
+
<span class="cline-any cline-yes">37x</span>
|
|
400
|
+
<span class="cline-any cline-yes">37x</span>
|
|
418
401
|
<span class="cline-any cline-neutral"> </span>
|
|
402
|
+
<span class="cline-any cline-yes">37x</span>
|
|
403
|
+
<span class="cline-any cline-yes">37x</span>
|
|
404
|
+
<span class="cline-any cline-yes">37x</span>
|
|
405
|
+
<span class="cline-any cline-yes">37x</span>
|
|
406
|
+
<span class="cline-any cline-yes">37x</span>
|
|
419
407
|
<span class="cline-any cline-neutral"> </span>
|
|
408
|
+
<span class="cline-any cline-yes">37x</span>
|
|
409
|
+
<span class="cline-any cline-yes">37x</span>
|
|
410
|
+
<span class="cline-any cline-yes">37x</span>
|
|
411
|
+
<span class="cline-any cline-yes">37x</span>
|
|
412
|
+
<span class="cline-any cline-yes">37x</span>
|
|
413
|
+
<span class="cline-any cline-yes">37x</span>
|
|
414
|
+
<span class="cline-any cline-yes">37x</span>
|
|
420
415
|
<span class="cline-any cline-neutral"> </span>
|
|
416
|
+
<span class="cline-any cline-yes">37x</span>
|
|
421
417
|
<span class="cline-any cline-neutral"> </span>
|
|
418
|
+
<span class="cline-any cline-yes">37x</span>
|
|
419
|
+
<span class="cline-any cline-yes">37x</span>
|
|
422
420
|
<span class="cline-any cline-neutral"> </span>
|
|
421
|
+
<span class="cline-any cline-yes">37x</span>
|
|
423
422
|
<span class="cline-any cline-neutral"> </span>
|
|
424
423
|
<span class="cline-any cline-neutral"> </span>
|
|
425
424
|
<span class="cline-any cline-neutral"> </span>
|
|
425
|
+
<span class="cline-any cline-yes">37x</span>
|
|
426
|
+
<span class="cline-any cline-yes">37x</span>
|
|
426
427
|
<span class="cline-any cline-neutral"> </span>
|
|
427
428
|
<span class="cline-any cline-neutral"> </span>
|
|
428
429
|
<span class="cline-any cline-neutral"> </span>
|
|
429
430
|
<span class="cline-any cline-neutral"> </span>
|
|
430
431
|
<span class="cline-any cline-neutral"> </span>
|
|
431
432
|
<span class="cline-any cline-neutral"> </span>
|
|
433
|
+
<span class="cline-any cline-yes">37x</span>
|
|
434
|
+
<span class="cline-any cline-yes">37x</span>
|
|
435
|
+
<span class="cline-any cline-yes">37x</span>
|
|
432
436
|
<span class="cline-any cline-neutral"> </span>
|
|
433
437
|
<span class="cline-any cline-neutral"> </span>
|
|
438
|
+
<span class="cline-any cline-yes">37x</span>
|
|
434
439
|
<span class="cline-any cline-neutral"> </span>
|
|
440
|
+
<span class="cline-any cline-yes">37x</span>
|
|
441
|
+
<span class="cline-any cline-yes">37x</span>
|
|
435
442
|
<span class="cline-any cline-neutral"> </span>
|
|
436
443
|
<span class="cline-any cline-neutral"> </span>
|
|
437
444
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -441,15 +448,23 @@
|
|
|
441
448
|
<span class="cline-any cline-neutral"> </span>
|
|
442
449
|
<span class="cline-any cline-neutral"> </span>
|
|
443
450
|
<span class="cline-any cline-neutral"> </span>
|
|
444
|
-
<span class="cline-any cline-yes">
|
|
445
|
-
<span class="cline-any cline-yes">
|
|
446
|
-
<span class="cline-any cline-yes">
|
|
447
|
-
<span class="cline-any cline-yes">
|
|
451
|
+
<span class="cline-any cline-yes">39x</span>
|
|
452
|
+
<span class="cline-any cline-yes">39x</span>
|
|
453
|
+
<span class="cline-any cline-yes">39x</span>
|
|
454
|
+
<span class="cline-any cline-yes">39x</span>
|
|
455
|
+
<span class="cline-any cline-yes">39x</span>
|
|
456
|
+
<span class="cline-any cline-yes">39x</span>
|
|
457
|
+
<span class="cline-any cline-yes">39x</span>
|
|
458
|
+
<span class="cline-any cline-yes">39x</span>
|
|
448
459
|
<span class="cline-any cline-neutral"> </span>
|
|
449
|
-
<span class="cline-any cline-yes">17x</span>
|
|
450
|
-
<span class="cline-any cline-yes">17x</span>
|
|
451
460
|
<span class="cline-any cline-neutral"> </span>
|
|
452
461
|
<span class="cline-any cline-neutral"> </span>
|
|
462
|
+
<span class="cline-any cline-yes">4x</span>
|
|
463
|
+
<span class="cline-any cline-yes">4x</span>
|
|
464
|
+
<span class="cline-any cline-yes">4x</span>
|
|
465
|
+
<span class="cline-any cline-yes">4x</span>
|
|
466
|
+
<span class="cline-any cline-yes">4x</span>
|
|
467
|
+
<span class="cline-any cline-yes">4x</span>
|
|
453
468
|
<span class="cline-any cline-neutral"> </span>
|
|
454
469
|
<span class="cline-any cline-neutral"> </span>
|
|
455
470
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -457,204 +472,176 @@
|
|
|
457
472
|
<span class="cline-any cline-neutral"> </span>
|
|
458
473
|
<span class="cline-any cline-neutral"> </span>
|
|
459
474
|
<span class="cline-any cline-neutral"> </span>
|
|
460
|
-
<span class="cline-any cline-yes">6x</span>
|
|
461
|
-
<span class="cline-any cline-yes">6x</span>
|
|
462
475
|
<span class="cline-any cline-neutral"> </span>
|
|
463
476
|
<span class="cline-any cline-neutral"> </span>
|
|
464
|
-
<span class="cline-any cline-yes">
|
|
477
|
+
<span class="cline-any cline-yes">31x</span>
|
|
465
478
|
<span class="cline-any cline-neutral"> </span>
|
|
466
479
|
<span class="cline-any cline-neutral"> </span>
|
|
467
480
|
<span class="cline-any cline-neutral"> </span>
|
|
468
|
-
<span class="cline-any cline-yes">23x</span>
|
|
469
481
|
<span class="cline-any cline-neutral"> </span>
|
|
470
482
|
<span class="cline-any cline-neutral"> </span>
|
|
471
483
|
<span class="cline-any cline-neutral"> </span>
|
|
472
484
|
<span class="cline-any cline-neutral"> </span>
|
|
485
|
+
<span class="cline-any cline-yes">53x</span>
|
|
473
486
|
<span class="cline-any cline-neutral"> </span>
|
|
487
|
+
<span class="cline-any cline-yes">52x</span>
|
|
474
488
|
<span class="cline-any cline-neutral"> </span>
|
|
475
489
|
<span class="cline-any cline-neutral"> </span>
|
|
490
|
+
<span class="cline-any cline-yes">52x</span>
|
|
491
|
+
<span class="cline-any cline-yes">16x</span>
|
|
476
492
|
<span class="cline-any cline-neutral"> </span>
|
|
493
|
+
<span class="cline-any cline-yes">16x</span>
|
|
494
|
+
<span class="cline-any cline-yes">4x</span>
|
|
495
|
+
<span class="cline-any cline-yes">4x</span>
|
|
496
|
+
<span class="cline-any cline-yes">4x</span>
|
|
497
|
+
<span class="cline-any cline-yes">4x</span>
|
|
498
|
+
<span class="cline-any cline-yes">4x</span>
|
|
499
|
+
<span class="cline-any cline-yes">4x</span>
|
|
500
|
+
<span class="cline-any cline-yes">4x</span>
|
|
477
501
|
<span class="cline-any cline-neutral"> </span>
|
|
478
|
-
<span class="cline-any cline-yes">54x</span>
|
|
479
502
|
<span class="cline-any cline-neutral"> </span>
|
|
503
|
+
<span class="cline-any cline-yes">12x</span>
|
|
504
|
+
<span class="cline-any cline-yes">11x</span>
|
|
505
|
+
<span class="cline-any cline-yes">11x</span>
|
|
506
|
+
<span class="cline-any cline-yes">11x</span>
|
|
507
|
+
<span class="cline-any cline-yes">11x</span>
|
|
508
|
+
<span class="cline-any cline-yes">11x</span>
|
|
509
|
+
<span class="cline-any cline-yes">11x</span>
|
|
510
|
+
<span class="cline-any cline-yes">11x</span>
|
|
480
511
|
<span class="cline-any cline-neutral"> </span>
|
|
481
512
|
<span class="cline-any cline-neutral"> </span>
|
|
513
|
+
<span class="cline-any cline-yes">1x</span>
|
|
482
514
|
<span class="cline-any cline-neutral"> </span>
|
|
483
515
|
<span class="cline-any cline-neutral"> </span>
|
|
484
516
|
<span class="cline-any cline-neutral"> </span>
|
|
517
|
+
<span class="cline-any cline-yes">36x</span>
|
|
518
|
+
<span class="cline-any cline-yes">36x</span>
|
|
519
|
+
<span class="cline-any cline-yes">36x</span>
|
|
520
|
+
<span class="cline-any cline-yes">36x</span>
|
|
521
|
+
<span class="cline-any cline-yes">35x</span>
|
|
522
|
+
<span class="cline-any cline-yes">35x</span>
|
|
523
|
+
<span class="cline-any cline-yes">29x</span>
|
|
485
524
|
<span class="cline-any cline-neutral"> </span>
|
|
486
|
-
<span class="cline-any cline-yes">
|
|
525
|
+
<span class="cline-any cline-yes">6x</span>
|
|
487
526
|
<span class="cline-any cline-neutral"> </span>
|
|
527
|
+
<span class="cline-any cline-yes">35x</span>
|
|
488
528
|
<span class="cline-any cline-neutral"> </span>
|
|
489
|
-
<span class="cline-any cline-yes">47x</span>
|
|
490
|
-
<span class="cline-any cline-yes">47x</span>
|
|
491
|
-
<span class="cline-any cline-yes">34x</span>
|
|
492
|
-
<span class="cline-any cline-yes">34x</span>
|
|
493
529
|
<span class="cline-any cline-neutral"> </span>
|
|
494
|
-
<span class="cline-any cline-yes">
|
|
530
|
+
<span class="cline-any cline-yes">1x</span>
|
|
495
531
|
<span class="cline-any cline-neutral"> </span>
|
|
496
532
|
<span class="cline-any cline-neutral"> </span>
|
|
497
533
|
<span class="cline-any cline-neutral"> </span>
|
|
534
|
+
<span class="cline-any cline-yes">39x</span>
|
|
535
|
+
<span class="cline-any cline-yes">38x</span>
|
|
498
536
|
<span class="cline-any cline-neutral"> </span>
|
|
499
537
|
<span class="cline-any cline-neutral"> </span>
|
|
500
538
|
<span class="cline-any cline-neutral"> </span>
|
|
501
539
|
<span class="cline-any cline-neutral"> </span>
|
|
540
|
+
<span class="cline-any cline-yes">26x</span>
|
|
541
|
+
<span class="cline-any cline-yes">26x</span>
|
|
502
542
|
<span class="cline-any cline-neutral"> </span>
|
|
543
|
+
<span class="cline-any cline-yes">26x</span>
|
|
544
|
+
<span class="cline-any cline-yes">26x</span>
|
|
545
|
+
<span class="cline-any cline-yes">26x</span>
|
|
503
546
|
<span class="cline-any cline-neutral"> </span>
|
|
504
547
|
<span class="cline-any cline-neutral"> </span>
|
|
505
|
-
<span class="cline-any cline-yes">54x</span>
|
|
506
548
|
<span class="cline-any cline-neutral"> </span>
|
|
507
549
|
<span class="cline-any cline-neutral"> </span>
|
|
508
|
-
<span class="cline-any cline-yes">42x</span>
|
|
509
550
|
<span class="cline-any cline-neutral"> </span>
|
|
510
551
|
<span class="cline-any cline-neutral"> </span>
|
|
511
552
|
<span class="cline-any cline-neutral"> </span>
|
|
512
|
-
<span class="cline-any cline-yes">42x</span>
|
|
513
|
-
<span class="cline-any cline-yes">42x</span>
|
|
514
|
-
<span class="cline-any cline-yes">22x</span>
|
|
515
|
-
<span class="cline-any cline-yes">22x</span>
|
|
516
553
|
<span class="cline-any cline-neutral"> </span>
|
|
517
554
|
<span class="cline-any cline-neutral"> </span>
|
|
518
|
-
<span class="cline-any cline-yes">
|
|
519
|
-
<span class="cline-any cline-yes">42x</span>
|
|
555
|
+
<span class="cline-any cline-yes">6x</span>
|
|
520
556
|
<span class="cline-any cline-yes">4x</span>
|
|
521
557
|
<span class="cline-any cline-yes">4x</span>
|
|
522
558
|
<span class="cline-any cline-neutral"> </span>
|
|
523
|
-
<span class="cline-any cline-yes">42x</span>
|
|
524
|
-
<span class="cline-any cline-neutral"> </span>
|
|
525
|
-
<span class="cline-any cline-neutral"> </span>
|
|
526
|
-
<span class="cline-any cline-neutral"> </span>
|
|
527
|
-
<span class="cline-any cline-yes">17x</span>
|
|
528
|
-
<span class="cline-any cline-yes">5x</span>
|
|
529
|
-
<span class="cline-any cline-yes">5x</span>
|
|
530
|
-
<span class="cline-any cline-yes">4x</span>
|
|
531
559
|
<span class="cline-any cline-yes">4x</span>
|
|
532
560
|
<span class="cline-any cline-neutral"> </span>
|
|
533
|
-
<span class="cline-any cline-yes">1x</span>
|
|
534
|
-
<span class="cline-any cline-neutral"> </span>
|
|
535
561
|
<span class="cline-any cline-neutral"> </span>
|
|
536
562
|
<span class="cline-any cline-neutral"> </span>
|
|
537
563
|
<span class="cline-any cline-neutral"> </span>
|
|
538
564
|
<span class="cline-any cline-neutral"> </span>
|
|
539
565
|
<span class="cline-any cline-neutral"> </span>
|
|
540
566
|
<span class="cline-any cline-neutral"> </span>
|
|
541
|
-
<span class="cline-any cline-yes">32x</span>
|
|
542
567
|
<span class="cline-any cline-neutral"> </span>
|
|
543
568
|
<span class="cline-any cline-neutral"> </span>
|
|
544
569
|
<span class="cline-any cline-neutral"> </span>
|
|
545
570
|
<span class="cline-any cline-neutral"> </span>
|
|
546
571
|
<span class="cline-any cline-neutral"> </span>
|
|
547
|
-
<span class="cline-any cline-yes">
|
|
548
|
-
<span class="cline-any cline-yes">
|
|
549
|
-
<span class="cline-any cline-yes">
|
|
550
|
-
<span class="cline-any cline-
|
|
551
|
-
<span class="cline-any cline-yes">23x</span>
|
|
572
|
+
<span class="cline-any cline-yes">3x</span>
|
|
573
|
+
<span class="cline-any cline-yes">3x</span>
|
|
574
|
+
<span class="cline-any cline-yes">3x</span>
|
|
575
|
+
<span class="cline-any cline-yes">3x</span>
|
|
552
576
|
<span class="cline-any cline-neutral"> </span>
|
|
553
|
-
<span class="cline-any cline-yes">
|
|
577
|
+
<span class="cline-any cline-yes">3x</span>
|
|
578
|
+
<span class="cline-any cline-yes">2x</span>
|
|
579
|
+
<span class="cline-any cline-yes">2x</span>
|
|
580
|
+
<span class="cline-any cline-yes">2x</span>
|
|
581
|
+
<span class="cline-any cline-yes">2x</span>
|
|
582
|
+
<span class="cline-any cline-yes">2x</span>
|
|
583
|
+
<span class="cline-any cline-yes">2x</span>
|
|
554
584
|
<span class="cline-any cline-yes">2x</span>
|
|
555
|
-
<span class="cline-any cline-neutral"> </span>
|
|
556
|
-
<span class="cline-any cline-yes">21x</span>
|
|
557
|
-
<span class="cline-any cline-neutral"> </span>
|
|
558
|
-
<span class="cline-any cline-neutral"> </span>
|
|
559
585
|
<span class="cline-any cline-neutral"> </span>
|
|
560
586
|
<span class="cline-any cline-neutral"> </span>
|
|
561
587
|
<span class="cline-any cline-neutral"> </span>
|
|
562
588
|
<span class="cline-any cline-neutral"> </span>
|
|
563
589
|
<span class="cline-any cline-neutral"> </span>
|
|
564
|
-
<span class="cline-any cline-yes">16x</span>
|
|
565
|
-
<span class="cline-any cline-yes">16x</span>
|
|
566
|
-
<span class="cline-any cline-yes">9x</span>
|
|
567
590
|
<span class="cline-any cline-neutral"> </span>
|
|
568
|
-
<span class="cline-any cline-yes">7x</span>
|
|
569
591
|
<span class="cline-any cline-neutral"> </span>
|
|
570
592
|
<span class="cline-any cline-neutral"> </span>
|
|
571
593
|
<span class="cline-any cline-neutral"> </span>
|
|
594
|
+
<span class="cline-any cline-yes">5x</span>
|
|
572
595
|
<span class="cline-any cline-neutral"> </span>
|
|
573
596
|
<span class="cline-any cline-neutral"> </span>
|
|
574
597
|
<span class="cline-any cline-neutral"> </span>
|
|
575
598
|
<span class="cline-any cline-neutral"> </span>
|
|
576
599
|
<span class="cline-any cline-neutral"> </span>
|
|
577
600
|
<span class="cline-any cline-neutral"> </span>
|
|
578
|
-
<span class="cline-any cline-yes">12x</span>
|
|
579
|
-
<span class="cline-any cline-yes">12x</span>
|
|
580
|
-
<span class="cline-any cline-yes">2x</span>
|
|
581
601
|
<span class="cline-any cline-yes">2x</span>
|
|
582
602
|
<span class="cline-any cline-yes">2x</span>
|
|
583
|
-
<span class="cline-any cline-yes">1x</span>
|
|
584
|
-
<span class="cline-any cline-yes">1x</span>
|
|
585
|
-
<span class="cline-any cline-neutral"> </span>
|
|
586
|
-
<span class="cline-any cline-yes">1x</span>
|
|
587
603
|
<span class="cline-any cline-neutral"> </span>
|
|
588
604
|
<span class="cline-any cline-neutral"> </span>
|
|
589
605
|
<span class="cline-any cline-neutral"> </span>
|
|
590
606
|
<span class="cline-any cline-neutral"> </span>
|
|
591
607
|
<span class="cline-any cline-neutral"> </span>
|
|
592
608
|
<span class="cline-any cline-neutral"> </span>
|
|
593
|
-
<span class="cline-any cline-yes">54x</span>
|
|
594
|
-
<span class="cline-any cline-neutral"> </span>
|
|
595
|
-
<span class="cline-any cline-yes">16x</span>
|
|
596
609
|
<span class="cline-any cline-neutral"> </span>
|
|
597
|
-
<span class="cline-any cline-yes">
|
|
598
|
-
<span class="cline-any cline-yes">15x</span>
|
|
610
|
+
<span class="cline-any cline-yes">1x</span>
|
|
599
611
|
<span class="cline-any cline-neutral"> </span>
|
|
600
|
-
<span class="cline-any cline-yes">15x</span>
|
|
601
|
-
<span class="cline-any cline-yes">4x</span>
|
|
602
612
|
<span class="cline-any cline-neutral"> </span>
|
|
603
613
|
<span class="cline-any cline-neutral"> </span>
|
|
604
614
|
<span class="cline-any cline-neutral"> </span>
|
|
605
|
-
<span class="cline-any cline-yes">11x</span>
|
|
606
|
-
<span class="cline-any cline-yes">2x</span>
|
|
607
615
|
<span class="cline-any cline-neutral"> </span>
|
|
608
616
|
<span class="cline-any cline-neutral"> </span>
|
|
617
|
+
<span class="cline-any cline-yes">1x</span>
|
|
609
618
|
<span class="cline-any cline-neutral"> </span>
|
|
610
|
-
<span class="cline-any cline-yes">9x</span>
|
|
611
|
-
<span class="cline-any cline-yes">9x</span>
|
|
612
|
-
<span class="cline-any cline-yes">3x</span>
|
|
613
619
|
<span class="cline-any cline-neutral"> </span>
|
|
614
620
|
<span class="cline-any cline-neutral"> </span>
|
|
615
|
-
<span class="cline-any cline-yes">
|
|
616
|
-
<span class="cline-any cline-yes">
|
|
617
|
-
<span class="cline-any cline-yes">3x</span>
|
|
618
|
-
<span class="cline-any cline-yes">3x</span>
|
|
619
|
-
<span class="cline-any cline-yes">3x</span>
|
|
620
|
-
<span class="cline-any cline-neutral"> </span>
|
|
621
|
-
<span class="cline-any cline-neutral"> </span>
|
|
622
|
-
<span class="cline-any cline-yes">6x</span>
|
|
623
|
-
<span class="cline-any cline-yes">1x</span>
|
|
621
|
+
<span class="cline-any cline-yes">2x</span>
|
|
622
|
+
<span class="cline-any cline-yes">2x</span>
|
|
624
623
|
<span class="cline-any cline-yes">1x</span>
|
|
625
624
|
<span class="cline-any cline-neutral"> </span>
|
|
626
625
|
<span class="cline-any cline-neutral"> </span>
|
|
627
|
-
<span class="cline-any cline-yes">6x</span>
|
|
628
626
|
<span class="cline-any cline-neutral"> </span>
|
|
629
627
|
<span class="cline-any cline-neutral"> </span>
|
|
630
628
|
<span class="cline-any cline-neutral"> </span>
|
|
629
|
+
<span class="cline-any cline-yes">1x</span>
|
|
631
630
|
<span class="cline-any cline-neutral"> </span>
|
|
632
|
-
<span class="cline-any cline-yes">13x</span>
|
|
633
|
-
<span class="cline-any cline-yes">13x</span>
|
|
634
631
|
<span class="cline-any cline-neutral"> </span>
|
|
635
|
-
<span class="cline-any cline-yes">13x</span>
|
|
636
|
-
<span class="cline-any cline-yes">16x</span>
|
|
637
|
-
<span class="cline-any cline-yes">16x</span>
|
|
638
632
|
<span class="cline-any cline-neutral"> </span>
|
|
633
|
+
<span class="cline-any cline-yes">2x</span>
|
|
639
634
|
<span class="cline-any cline-neutral"> </span>
|
|
640
635
|
<span class="cline-any cline-neutral"> </span>
|
|
641
|
-
<span class="cline-any cline-yes">16x</span>
|
|
642
|
-
<span class="cline-any cline-yes">16x</span>
|
|
643
636
|
<span class="cline-any cline-neutral"> </span>
|
|
644
|
-
<span class="cline-any cline-yes">12x</span>
|
|
645
|
-
<span class="cline-any cline-yes">12x</span>
|
|
646
637
|
<span class="cline-any cline-neutral"> </span>
|
|
647
638
|
<span class="cline-any cline-neutral"> </span>
|
|
648
|
-
<span class="cline-any cline-yes">4x</span>
|
|
649
639
|
<span class="cline-any cline-neutral"> </span>
|
|
640
|
+
<span class="cline-any cline-yes">1x</span>
|
|
650
641
|
<span class="cline-any cline-neutral"> </span>
|
|
651
642
|
<span class="cline-any cline-neutral"> </span>
|
|
652
643
|
<span class="cline-any cline-neutral"> </span>
|
|
653
644
|
<span class="cline-any cline-neutral"> </span>
|
|
654
|
-
<span class="cline-any cline-yes">4x</span>
|
|
655
|
-
<span class="cline-any cline-yes">4x</span>
|
|
656
|
-
<span class="cline-any cline-yes">4x</span>
|
|
657
|
-
<span class="cline-any cline-yes">4x</span>
|
|
658
645
|
<span class="cline-any cline-neutral"> </span>
|
|
659
646
|
<span class="cline-any cline-neutral"> </span>
|
|
660
647
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -666,30 +653,38 @@
|
|
|
666
653
|
<span class="cline-any cline-neutral"> </span>
|
|
667
654
|
<span class="cline-any cline-neutral"> </span>
|
|
668
655
|
<span class="cline-any cline-neutral"> </span>
|
|
656
|
+
<span class="cline-any cline-yes">7x</span>
|
|
669
657
|
<span class="cline-any cline-neutral"> </span>
|
|
670
|
-
<span class="cline-any cline-yes">38x</span>
|
|
671
658
|
<span class="cline-any cline-neutral"> </span>
|
|
672
|
-
<span class="cline-any cline-yes">22x</span>
|
|
673
|
-
<span class="cline-any cline-yes">22x</span>
|
|
674
659
|
<span class="cline-any cline-neutral"> </span>
|
|
675
|
-
<span class="cline-any cline-yes">22x</span>
|
|
676
660
|
<span class="cline-any cline-neutral"> </span>
|
|
677
661
|
<span class="cline-any cline-yes">7x</span>
|
|
678
662
|
<span class="cline-any cline-neutral"> </span>
|
|
663
|
+
<span class="cline-any cline-yes">7x</span>
|
|
664
|
+
<span class="cline-any cline-yes">9x</span>
|
|
679
665
|
<span class="cline-any cline-neutral"> </span>
|
|
680
666
|
<span class="cline-any cline-neutral"> </span>
|
|
681
667
|
<span class="cline-any cline-neutral"> </span>
|
|
682
|
-
<span class="cline-any cline-yes">
|
|
683
|
-
<span class="cline-any cline-yes">
|
|
684
|
-
<span class="cline-any cline-
|
|
668
|
+
<span class="cline-any cline-yes">2x</span>
|
|
669
|
+
<span class="cline-any cline-yes">2x</span>
|
|
670
|
+
<span class="cline-any cline-yes">2x</span>
|
|
671
|
+
<span class="cline-any cline-yes">2x</span>
|
|
672
|
+
<span class="cline-any cline-yes">2x</span>
|
|
673
|
+
<span class="cline-any cline-yes">2x</span>
|
|
685
674
|
<span class="cline-any cline-neutral"> </span>
|
|
686
675
|
<span class="cline-any cline-neutral"> </span>
|
|
687
|
-
<span class="cline-any cline-yes">
|
|
676
|
+
<span class="cline-any cline-yes">3x</span>
|
|
677
|
+
<span class="cline-any cline-yes">3x</span>
|
|
678
|
+
<span class="cline-any cline-yes">3x</span>
|
|
679
|
+
<span class="cline-any cline-yes">3x</span>
|
|
680
|
+
<span class="cline-any cline-yes">3x</span>
|
|
681
|
+
<span class="cline-any cline-yes">3x</span>
|
|
688
682
|
<span class="cline-any cline-yes">3x</span>
|
|
689
683
|
<span class="cline-any cline-neutral"> </span>
|
|
690
684
|
<span class="cline-any cline-neutral"> </span>
|
|
691
|
-
<span class="cline-any cline-yes">
|
|
692
|
-
<span class="cline-any cline-yes">
|
|
685
|
+
<span class="cline-any cline-yes">2x</span>
|
|
686
|
+
<span class="cline-any cline-yes">2x</span>
|
|
687
|
+
<span class="cline-any cline-yes">2x</span>
|
|
693
688
|
<span class="cline-any cline-yes">2x</span>
|
|
694
689
|
<span class="cline-any cline-yes">2x</span>
|
|
695
690
|
<span class="cline-any cline-yes">2x</span>
|
|
@@ -697,32 +692,9 @@
|
|
|
697
692
|
<span class="cline-any cline-neutral"> </span>
|
|
698
693
|
<span class="cline-any cline-neutral"> </span>
|
|
699
694
|
<span class="cline-any cline-neutral"> </span>
|
|
700
|
-
<span class="cline-any cline-yes">
|
|
701
|
-
<span class="cline-any cline-neutral"> </span>
|
|
702
|
-
<span class="cline-any cline-neutral"> </span>
|
|
703
|
-
<span class="cline-any cline-yes">4x</span>
|
|
704
|
-
<span class="cline-any cline-yes">4x</span>
|
|
705
|
-
<span class="cline-any cline-neutral"> </span>
|
|
706
|
-
<span class="cline-any cline-neutral"> </span>
|
|
707
|
-
<span class="cline-any cline-neutral"> </span>
|
|
708
|
-
<span class="cline-any cline-neutral"> </span>
|
|
709
|
-
<span class="cline-any cline-neutral"> </span>
|
|
710
|
-
<span class="cline-any cline-neutral"> </span>
|
|
711
|
-
<span class="cline-any cline-neutral"> </span>
|
|
712
|
-
<span class="cline-any cline-neutral"> </span>
|
|
713
|
-
<span class="cline-any cline-yes">17x</span>
|
|
714
|
-
<span class="cline-any cline-yes">17x</span>
|
|
715
|
-
<span class="cline-any cline-yes">17x</span>
|
|
716
|
-
<span class="cline-any cline-yes">17x</span>
|
|
717
|
-
<span class="cline-any cline-neutral"> </span>
|
|
718
|
-
<span class="cline-any cline-neutral"> </span>
|
|
719
|
-
<span class="cline-any cline-neutral"> </span>
|
|
720
|
-
<span class="cline-any cline-neutral"> </span>
|
|
721
|
-
<span class="cline-any cline-yes">3x</span>
|
|
722
|
-
<span class="cline-any cline-yes">3x</span>
|
|
723
|
-
<span class="cline-any cline-yes">3x</span>
|
|
724
|
-
<span class="cline-any cline-neutral"> </span>
|
|
695
|
+
<span class="cline-any cline-yes">7x</span>
|
|
725
696
|
<span class="cline-any cline-neutral"> </span>
|
|
697
|
+
<span class="cline-any cline-yes">1x</span>
|
|
726
698
|
<span class="cline-any cline-neutral"> </span>
|
|
727
699
|
<span class="cline-any cline-neutral"> </span>
|
|
728
700
|
<span class="cline-any cline-neutral"> </span>
|
|
@@ -730,341 +702,330 @@
|
|
|
730
702
|
<span class="cline-any cline-neutral"> </span>
|
|
731
703
|
<span class="cline-any cline-neutral"> </span>
|
|
732
704
|
<span class="cline-any cline-neutral"> </span>
|
|
705
|
+
<span class="cline-any cline-yes">1x</span>
|
|
706
|
+
<span class="cline-any cline-yes">1x</span>
|
|
733
707
|
<span class="cline-any cline-neutral"> </span>
|
|
734
|
-
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js"
|
|
708
|
+
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">/**
|
|
709
|
+
* NatsProxyClient — Binary WebSocket client for NATS operations via data-proxy.
|
|
710
|
+
*
|
|
711
|
+
* Speaks the binary frame protocol defined in data-proxy/protocol.ts.
|
|
712
|
+
* Shares the WebSocket connection with DataProxyClient (JSON-RPC).
|
|
713
|
+
*/
|
|
735
714
|
|
|
736
|
-
|
|
737
|
-
// Window size in seconds (default: 3600 = 1 hour)
|
|
738
|
-
windowSeconds?: number;
|
|
739
|
-
// Max units in the window (default: 1.0)
|
|
740
|
-
maxPerWindow?: number;
|
|
741
|
-
// Max concurrent requests waiting in queue (default: 100)
|
|
742
|
-
maxQueueDepth?: number;
|
|
743
|
-
// How long to wait in queue before giving up, ms (default: 300000 = 5 min)
|
|
744
|
-
maxWaitMs?: number;
|
|
745
|
-
// Optional NATS KV bucket for cross-server rate limiting
|
|
746
|
-
bucket?: KV;
|
|
747
|
-
}
|
|
715
|
+
import WebSocket from 'ws';
|
|
748
716
|
|
|
749
|
-
|
|
750
|
-
userId: string;
|
|
751
|
-
operation: string;
|
|
752
|
-
used: number; // units charged so far in current window
|
|
753
|
-
limit: number; // max units per window
|
|
754
|
-
windowStart: Date; // when the current window started
|
|
755
|
-
queued: number; // currently waiting in queue
|
|
756
|
-
}
|
|
717
|
+
// ── Protocol constants (mirrored from data-proxy/protocol.ts) ─────────────
|
|
757
718
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
// If over limit: queues the request and waits until budget is available.
|
|
762
|
-
// Throws RateLimitError if queue is full or wait timeout exceeded.
|
|
763
|
-
check(
|
|
764
|
-
userId: string,
|
|
765
|
-
operation: string,
|
|
766
|
-
estimatedCost: number,
|
|
767
|
-
): Promise<void>;
|
|
719
|
+
const OP_PUBLISH = 0x01;
|
|
720
|
+
const OP_SUBSCRIBE = 0x02;
|
|
721
|
+
const OP_UNSUBSCRIBE = 0x03;
|
|
768
722
|
|
|
769
|
-
|
|
770
|
-
|
|
723
|
+
const OP_KV_ENSURE = 0x10;
|
|
724
|
+
const OP_KV_GET = 0x11;
|
|
725
|
+
const OP_KV_PUT = 0x12;
|
|
726
|
+
const OP_KV_DELETE = 0x13;
|
|
727
|
+
const OP_KV_KEYS = 0x14;
|
|
771
728
|
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
729
|
+
const OP_STREAM_ENSURE = 0x20;
|
|
730
|
+
const OP_JS_PUBLISH = 0x21;
|
|
731
|
+
const OP_JS_CONSUMER_CREATE = 0x22;
|
|
732
|
+
const OP_JS_CONSUMER_CONSUME = 0x23;
|
|
733
|
+
const OP_JS_ACK = 0x24;
|
|
734
|
+
const OP_JS_NAK = 0x25;
|
|
735
|
+
const OP_JS_WORKING = 0x26;
|
|
775
736
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
737
|
+
const OP_STATUS = 0x30;
|
|
738
|
+
|
|
739
|
+
const PUSH_SUB_MESSAGE = 0x01;
|
|
740
|
+
const PUSH_JS_MESSAGE = 0x02;
|
|
741
|
+
|
|
742
|
+
const STATUS_OK = 0x00;
|
|
743
|
+
|
|
744
|
+
// ── State ─────────────────────────────────────────────────────────────────
|
|
745
|
+
|
|
746
|
+
let _ws: WebSocket | null = null;
|
|
747
|
+
let _requestId = 0;
|
|
787
748
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
windowStart: number; // epoch ms
|
|
749
|
+
interface PendingBinaryRequest {
|
|
750
|
+
resolve: (payload: Buffer) => void;
|
|
751
|
+
reject: (error: Error) => void;
|
|
792
752
|
}
|
|
793
753
|
|
|
754
|
+
const _pending = new Map<number, PendingBinaryRequest>();
|
|
755
|
+
const _subHandlers = new Map<number, (subject: string, data: Buffer) => void>();
|
|
756
|
+
const _jsConsumerHandlers = new Map<number, (msgId: number, deliveryCount: number, data: Buffer) => void>();
|
|
757
|
+
|
|
758
|
+
// Track active subscriptions for resubscription on reconnect
|
|
759
|
+
const _activeSubs = new Map<number, { subject: string; handler: (subject: string, data: Buffer) => void }>();
|
|
760
|
+
|
|
794
761
|
const textEncoder = new TextEncoder();
|
|
795
762
|
const textDecoder = new TextDecoder();
|
|
796
763
|
|
|
797
|
-
|
|
798
|
-
|
|
764
|
+
// ── Frame encoding/decoding ───────────────────────────────────────────────
|
|
765
|
+
|
|
766
|
+
function encodeRequest(
|
|
767
|
+
requestId: number,
|
|
768
|
+
opcode: number,
|
|
769
|
+
subject: string,
|
|
770
|
+
payload: Uint8Array,
|
|
771
|
+
): Buffer {
|
|
772
|
+
const subjectBytes = textEncoder.encode(subject);
|
|
773
|
+
const buf = Buffer.allocUnsafe(4 + 1 + 2 + subjectBytes.length + payload.length);
|
|
774
|
+
buf.writeUInt32BE(requestId, 0);
|
|
775
|
+
buf[4] = opcode;
|
|
776
|
+
buf.writeUInt16BE(subjectBytes.length, 5);
|
|
777
|
+
buf.set(subjectBytes, 7);
|
|
778
|
+
buf.set(payload, 7 + subjectBytes.length);
|
|
779
|
+
return buf;
|
|
799
780
|
}
|
|
800
781
|
|
|
801
|
-
function
|
|
802
|
-
|
|
782
|
+
function encodeKeyPayload(key: string, value?: Uint8Array): Buffer {
|
|
783
|
+
const keyBytes = textEncoder.encode(key);
|
|
784
|
+
const buf = Buffer.allocUnsafe(2 + keyBytes.length + (value?.length ?? 0));
|
|
785
|
+
buf.writeUInt16BE(keyBytes.length, 0);
|
|
786
|
+
buf.set(keyBytes, 2);
|
|
787
|
+
if (value) buf.set(value, 2 + keyBytes.length);
|
|
788
|
+
return buf;
|
|
803
789
|
}
|
|
804
790
|
|
|
805
|
-
|
|
806
|
-
const {
|
|
807
|
-
windowSeconds = 3600,
|
|
808
|
-
maxPerWindow = 1.0,
|
|
809
|
-
maxQueueDepth = 100,
|
|
810
|
-
maxWaitMs = 300_000,
|
|
811
|
-
bucket,
|
|
812
|
-
} = config;
|
|
791
|
+
// ── Connection ────────────────────────────────────────────────────────────
|
|
813
792
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
793
|
+
/**
|
|
794
|
+
* Initialize the NATS proxy client. Must be called after the WebSocket is open.
|
|
795
|
+
* The WebSocket must be the same one used by DataProxyClient.
|
|
796
|
+
*/
|
|
797
|
+
export function initNatsProxy(ws: WebSocket): void {
|
|
798
|
+
_ws = ws;
|
|
799
|
+
}
|
|
821
800
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
return q;
|
|
829
|
-
}
|
|
801
|
+
/**
|
|
802
|
+
* Handle a binary message from the data-proxy WebSocket.
|
|
803
|
+
* Returns true if this was a binary NATS message (handled), false otherwise.
|
|
804
|
+
*/
|
|
805
|
+
export function handleNatsBinaryMessage(data: Buffer): boolean {
|
|
806
|
+
if (data.length < 5) return false;
|
|
830
807
|
|
|
831
|
-
|
|
808
|
+
const requestId = data.readUInt32BE(0);
|
|
832
809
|
|
|
833
|
-
//
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
windowStart: Date;
|
|
837
|
-
queue: QueueEntry[];
|
|
838
|
-
}
|
|
839
|
-
const usages = new Map<string, Usage>();
|
|
810
|
+
// Push frame (requestId === 0)
|
|
811
|
+
if (requestId === 0) {
|
|
812
|
+
const pushType = data[4];
|
|
840
813
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
usages.set(key, entry);
|
|
814
|
+
if (pushType === PUSH_SUB_MESSAGE) {
|
|
815
|
+
const subId = data.readUInt16BE(5);
|
|
816
|
+
const subjectLen = data.readUInt16BE(7);
|
|
817
|
+
const subject = textDecoder.decode(data.subarray(9, 9 + subjectLen));
|
|
818
|
+
const msgData = data.subarray(9 + subjectLen);
|
|
819
|
+
const handler = _subHandlers.get(subId);
|
|
820
|
+
if (handler) handler(subject, msgData);
|
|
821
|
+
return true;
|
|
850
822
|
}
|
|
851
|
-
// Reset window if expired
|
|
852
|
-
const age = (Date.now() - entry.windowStart.getTime()) / 1000;
|
|
853
|
-
if (age >= windowSeconds) {
|
|
854
|
-
entry.used = 0;
|
|
855
|
-
entry.windowStart = new Date();
|
|
856
|
-
}
|
|
857
|
-
return entry;
|
|
858
|
-
}
|
|
859
823
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
const
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
}
|
|
824
|
+
if (pushType === PUSH_JS_MESSAGE) {
|
|
825
|
+
const consumerId = data.readUInt16BE(5);
|
|
826
|
+
const msgId = data.readUInt32BE(7);
|
|
827
|
+
const deliveryCount = data.readUInt16BE(11);
|
|
828
|
+
const msgData = data.subarray(13);
|
|
829
|
+
const handler = _jsConsumerHandlers.get(consumerId);
|
|
830
|
+
if (handler) handler(msgId, deliveryCount, msgData);
|
|
831
|
+
return true;
|
|
869
832
|
}
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
// ─── NATS KV MODE ────────────────────────────────────────────────────────
|
|
873
833
|
|
|
874
|
-
|
|
875
|
-
return `${userId}.${operation}`;
|
|
834
|
+
return false;
|
|
876
835
|
}
|
|
877
836
|
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
// Reset window if expired
|
|
887
|
-
if ((Date.now() - data.windowStart) / 1000 >= windowSeconds) {
|
|
888
|
-
return { data: { used: 0, windowStart: Date.now() }, revision: entry.revision };
|
|
889
|
-
}
|
|
890
|
-
return { data, revision: entry.revision };
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
async function kvWriteEntry(
|
|
894
|
-
key: string,
|
|
895
|
-
value: KvUsage,
|
|
896
|
-
revision: number,
|
|
897
|
-
): Promise<void> {
|
|
898
|
-
const encoded = encodeKvUsage(value);
|
|
899
|
-
if (revision === 0) {
|
|
900
|
-
await bucket!.create(key, encoded);
|
|
837
|
+
// Response frame
|
|
838
|
+
const status = data[4];
|
|
839
|
+
const payload = data.subarray(5);
|
|
840
|
+
const pending = _pending.get(requestId);
|
|
841
|
+
if (pending) {
|
|
842
|
+
_pending.delete(requestId);
|
|
843
|
+
if (status === STATUS_OK) {
|
|
844
|
+
pending.resolve(payload);
|
|
901
845
|
} else {
|
|
902
|
-
|
|
846
|
+
pending.reject(new Error(textDecoder.decode(payload)));
|
|
903
847
|
}
|
|
848
|
+
return true;
|
|
904
849
|
}
|
|
905
850
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
const q = getQueue(key);
|
|
913
|
-
while (q.length > 0) {
|
|
914
|
-
const next = q[0];
|
|
915
|
-
const { data } = await kvReadEntry(key);
|
|
916
|
-
if (data.used + next.cost <= maxPerWindow) {
|
|
917
|
-
q.shift();
|
|
918
|
-
next.resolve();
|
|
919
|
-
} else {
|
|
920
|
-
break;
|
|
921
|
-
}
|
|
922
|
-
}
|
|
851
|
+
return false;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
function sendBinary(buf: Buffer): void {
|
|
855
|
+
if (_ws?.readyState === WebSocket.OPEN) {
|
|
856
|
+
_ws.send(buf);
|
|
923
857
|
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
function request(opcode: number, subject: string, payload: Uint8Array = new Uint8Array(0)): Promise<Buffer> {
|
|
861
|
+
const id = ++_requestId;
|
|
862
|
+
const frame = encodeRequest(id, opcode, subject, payload);
|
|
924
863
|
|
|
925
|
-
|
|
864
|
+
return new Promise<Buffer>((resolve, reject) => {
|
|
865
|
+
_pending.set(id, { resolve, reject });
|
|
866
|
+
sendBinary(frame);
|
|
867
|
+
});
|
|
868
|
+
}
|
|
926
869
|
|
|
927
|
-
|
|
928
|
-
// NATS KV mode
|
|
929
|
-
return {
|
|
930
|
-
async check(userId, operation, estimatedCost) {
|
|
931
|
-
const key = kvKey(userId, operation);
|
|
932
|
-
const { data } = await kvReadEntry(key);
|
|
870
|
+
// ── Public API: Pub/Sub ───────────────────────────────────────────────────
|
|
933
871
|
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
872
|
+
/**
|
|
873
|
+
* Publish a message to a NATS subject (fire-and-forget).
|
|
874
|
+
*/
|
|
875
|
+
export function natsProxyPublish(subject: string, payload: Uint8Array): void {
|
|
876
|
+
if (_ws?.readyState !== WebSocket.OPEN) return;
|
|
877
|
+
const id = ++_requestId;
|
|
878
|
+
sendBinary(encodeRequest(id, OP_PUBLISH, subject, payload));
|
|
879
|
+
// Fire and forget — don't wait for response
|
|
880
|
+
_pending.set(id, {
|
|
881
|
+
resolve: () => {},
|
|
882
|
+
reject: () => {},
|
|
883
|
+
});
|
|
884
|
+
}
|
|
937
885
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
886
|
+
/**
|
|
887
|
+
* Subscribe to a NATS subject. Returns an unsubscribe function.
|
|
888
|
+
*/
|
|
889
|
+
export async function natsProxySubscribe(
|
|
890
|
+
subject: string,
|
|
891
|
+
handler: (subject: string, data: Buffer) => void,
|
|
892
|
+
): Promise<() => void> {
|
|
893
|
+
const resp = await request(OP_SUBSCRIBE, subject);
|
|
894
|
+
const subId = resp.readUInt16BE(0);
|
|
895
|
+
_subHandlers.set(subId, handler);
|
|
896
|
+
_activeSubs.set(subId, { subject, handler });
|
|
942
897
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
898
|
+
return () => {
|
|
899
|
+
_subHandlers.delete(subId);
|
|
900
|
+
_activeSubs.delete(subId);
|
|
901
|
+
const unsubPayload = Buffer.allocUnsafe(2);
|
|
902
|
+
unsubPayload.writeUInt16BE(subId, 0);
|
|
903
|
+
const id = ++_requestId;
|
|
904
|
+
sendBinary(encodeRequest(id, OP_UNSUBSCRIBE, '', unsubPayload));
|
|
905
|
+
_pending.set(id, { resolve: () => {}, reject: () => {} });
|
|
906
|
+
};
|
|
907
|
+
}
|
|
948
908
|
|
|
949
|
-
|
|
950
|
-
const timer = setTimeout(() => {
|
|
951
|
-
const idx = q.findIndex((item) => item.resolve === resolveWrapper);
|
|
952
|
-
<span class="missing-if-branch" title="else path not taken" >E</span>if (idx >= 0) q.splice(idx, 1);
|
|
953
|
-
reject(new RateLimitError(userId, operation, data.used, maxPerWindow));
|
|
954
|
-
}, maxWaitMs);
|
|
909
|
+
// ── Public API: KV ────────────────────────────────────────────────────────
|
|
955
910
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
911
|
+
export async function natsProxyKvEnsure(
|
|
912
|
+
name: string,
|
|
913
|
+
opts?: Record<string, unknown>,
|
|
914
|
+
): Promise<void> {
|
|
915
|
+
await request(OP_KV_ENSURE, name, textEncoder.encode(JSON.stringify(opts ?? {})));
|
|
916
|
+
}
|
|
960
917
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
918
|
+
export async function natsProxyKvGet(
|
|
919
|
+
name: string,
|
|
920
|
+
key: string,
|
|
921
|
+
): Promise<Buffer | null> {
|
|
922
|
+
const resp = await request(OP_KV_GET, name, encodeKeyPayload(key));
|
|
923
|
+
return resp.length === 0 ? null : resp;
|
|
924
|
+
}
|
|
964
925
|
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
926
|
+
export async function natsProxyKvPut(
|
|
927
|
+
name: string,
|
|
928
|
+
key: string,
|
|
929
|
+
value: Uint8Array,
|
|
930
|
+
): Promise<void> {
|
|
931
|
+
await request(OP_KV_PUT, name, encodeKeyPayload(key, value));
|
|
932
|
+
}
|
|
968
933
|
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
try {
|
|
976
|
-
await kvWriteEntry(key, updated, revision);
|
|
977
|
-
// After successful write, try to drain the local queue
|
|
978
|
-
await kvDrainQueue(key, userId, operation);
|
|
979
|
-
return;
|
|
980
|
-
} catch {
|
|
981
|
-
// Revision conflict — retry
|
|
982
|
-
if (attempt === MAX_RETRIES - 1) throw new Error('[RateLimit] KV write conflict after max retries');
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
},
|
|
934
|
+
export async function natsProxyKvDelete(
|
|
935
|
+
name: string,
|
|
936
|
+
key: string,
|
|
937
|
+
): Promise<void> {
|
|
938
|
+
await request(OP_KV_DELETE, name, encodeKeyPayload(key));
|
|
939
|
+
}
|
|
986
940
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
userId,
|
|
993
|
-
operation,
|
|
994
|
-
used: data.used,
|
|
995
|
-
limit: maxPerWindow,
|
|
996
|
-
windowStart: new Date(data.windowStart),
|
|
997
|
-
queued: q.length,
|
|
998
|
-
};
|
|
999
|
-
},
|
|
1000
|
-
};
|
|
1001
|
-
}
|
|
941
|
+
export async function natsProxyKvKeys(name: string): Promise<string[]> {
|
|
942
|
+
const resp = await request(OP_KV_KEYS, name);
|
|
943
|
+
if (resp.length === 0) return [];
|
|
944
|
+
return JSON.parse(textDecoder.decode(resp)) as string[];
|
|
945
|
+
}
|
|
1002
946
|
|
|
1003
|
-
|
|
1004
|
-
return {
|
|
1005
|
-
async check(userId, operation, estimatedCost) {
|
|
1006
|
-
const key = getKey(userId, operation);
|
|
1007
|
-
const entry = getUsageEntry(key);
|
|
947
|
+
// ── Public API: JetStream ─────────────────────────────────────────────────
|
|
1008
948
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
}
|
|
949
|
+
export async function natsProxyEnsureStream(config: Record<string, unknown>): Promise<void> {
|
|
950
|
+
await request(OP_STREAM_ENSURE, '', textEncoder.encode(JSON.stringify(config)));
|
|
951
|
+
}
|
|
1013
952
|
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
throw new RateLimitError(userId, operation, entry.used, maxPerWindow);
|
|
1018
|
-
}
|
|
953
|
+
export async function natsProxyJsPublish(subject: string, payload: Uint8Array): Promise<void> {
|
|
954
|
+
await request(OP_JS_PUBLISH, subject, payload);
|
|
955
|
+
}
|
|
1019
956
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
957
|
+
export async function natsProxyJsConsumerCreate(
|
|
958
|
+
streamName: string,
|
|
959
|
+
config: Record<string, unknown>,
|
|
960
|
+
): Promise<void> {
|
|
961
|
+
await request(OP_JS_CONSUMER_CREATE, streamName, textEncoder.encode(JSON.stringify(config)));
|
|
962
|
+
}
|
|
1024
963
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
}, maxWaitMs);
|
|
964
|
+
export interface JsProxyMessage {
|
|
965
|
+
data: Buffer;
|
|
966
|
+
deliveryCount: number;
|
|
967
|
+
ack: () => void;
|
|
968
|
+
nak: (delayMs?: number) => void;
|
|
969
|
+
working: () => void;
|
|
970
|
+
}
|
|
1033
971
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
972
|
+
export async function natsProxyJsConsumerConsume(
|
|
973
|
+
streamName: string,
|
|
974
|
+
consumerName: string,
|
|
975
|
+
handler: (msg: JsProxyMessage) => void,
|
|
976
|
+
): Promise<{ stop: () => void }> {
|
|
977
|
+
const resp = await request(
|
|
978
|
+
OP_JS_CONSUMER_CONSUME,
|
|
979
|
+
streamName,
|
|
980
|
+
textEncoder.encode(consumerName),
|
|
981
|
+
);
|
|
982
|
+
const consumerId = resp.readUInt16BE(0);
|
|
1044
983
|
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
984
|
+
_jsConsumerHandlers.set(consumerId, (msgId, deliveryCount, data) => {
|
|
985
|
+
handler({
|
|
986
|
+
data,
|
|
987
|
+
deliveryCount,
|
|
988
|
+
ack: () => {
|
|
989
|
+
const payload = Buffer.allocUnsafe(6);
|
|
990
|
+
payload.writeUInt16BE(consumerId, 0);
|
|
991
|
+
payload.writeUInt32BE(msgId, 2);
|
|
992
|
+
const id = ++_requestId;
|
|
993
|
+
sendBinary(encodeRequest(id, OP_JS_ACK, '', payload));
|
|
994
|
+
_pending.set(id, { resolve: () => {}, reject: () => {} });
|
|
995
|
+
},
|
|
996
|
+
nak: (delayMs = 0) => {
|
|
997
|
+
const payload = Buffer.allocUnsafe(10);
|
|
998
|
+
payload.writeUInt16BE(consumerId, 0);
|
|
999
|
+
payload.writeUInt32BE(msgId, 2);
|
|
1000
|
+
payload.writeUInt32BE(delayMs, 6);
|
|
1001
|
+
const id = ++_requestId;
|
|
1002
|
+
sendBinary(encodeRequest(id, OP_JS_NAK, '', payload));
|
|
1003
|
+
_pending.set(id, { resolve: () => {}, reject: () => {} });
|
|
1004
|
+
},
|
|
1005
|
+
working: () => {
|
|
1006
|
+
const payload = Buffer.allocUnsafe(6);
|
|
1007
|
+
payload.writeUInt16BE(consumerId, 0);
|
|
1008
|
+
payload.writeUInt32BE(msgId, 2);
|
|
1009
|
+
const id = ++_requestId;
|
|
1010
|
+
sendBinary(encodeRequest(id, OP_JS_WORKING, '', payload));
|
|
1011
|
+
_pending.set(id, { resolve: () => {}, reject: () => {} });
|
|
1012
|
+
},
|
|
1013
|
+
});
|
|
1014
|
+
});
|
|
1052
1015
|
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
const entry = getUsageEntry(key);
|
|
1057
|
-
return {
|
|
1058
|
-
userId,
|
|
1059
|
-
operation,
|
|
1060
|
-
used: entry.used,
|
|
1061
|
-
limit: maxPerWindow,
|
|
1062
|
-
windowStart: entry.windowStart,
|
|
1063
|
-
queued: entry.queue.length,
|
|
1064
|
-
};
|
|
1016
|
+
return {
|
|
1017
|
+
stop: () => {
|
|
1018
|
+
_jsConsumerHandlers.delete(consumerId);
|
|
1065
1019
|
},
|
|
1066
1020
|
};
|
|
1067
1021
|
}
|
|
1022
|
+
|
|
1023
|
+
// ── Public API: Status ────────────────────────────────────────────────────
|
|
1024
|
+
|
|
1025
|
+
export async function natsProxyStatus(): Promise<{ connected: boolean; rtt?: number }> {
|
|
1026
|
+
const resp = await request(OP_STATUS, '');
|
|
1027
|
+
return JSON.parse(textDecoder.decode(resp)) as { connected: boolean; rtt?: number };
|
|
1028
|
+
}
|
|
1068
1029
|
</pre></td></tr></table></pre>
|
|
1069
1030
|
|
|
1070
1031
|
<div class='push'></div><!-- for sticky footer -->
|
|
@@ -1072,16 +1033,16 @@ export function createRateLimiter(config: RateLimitConfig = {}): RateLimiter {
|
|
|
1072
1033
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
1073
1034
|
Code coverage generated by
|
|
1074
1035
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
1075
|
-
at 2026-04-
|
|
1036
|
+
at 2026-04-11T01:13:16.301Z
|
|
1076
1037
|
</div>
|
|
1077
|
-
<script src="
|
|
1038
|
+
<script src="prettify.js"></script>
|
|
1078
1039
|
<script>
|
|
1079
1040
|
window.onload = function () {
|
|
1080
1041
|
prettyPrint();
|
|
1081
1042
|
};
|
|
1082
1043
|
</script>
|
|
1083
|
-
<script src="
|
|
1084
|
-
<script src="
|
|
1044
|
+
<script src="sorter.js"></script>
|
|
1045
|
+
<script src="block-navigation.js"></script>
|
|
1085
1046
|
</body>
|
|
1086
1047
|
</html>
|
|
1087
1048
|
|