@yishiguji/tokenarena 0.8.7 → 0.8.8
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/dist/index.js +103 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4836,14 +4836,19 @@ import { URL as URL2 } from "url";
|
|
|
4836
4836
|
var MAX_RETRIES = 3;
|
|
4837
4837
|
var INITIAL_DELAY = 1e3;
|
|
4838
4838
|
var TIMEOUT_MS = 6e4;
|
|
4839
|
-
function
|
|
4840
|
-
|
|
4839
|
+
function buildIngestPayload(device, buckets, sessions, options) {
|
|
4840
|
+
return {
|
|
4841
4841
|
schemaVersion: 2,
|
|
4842
4842
|
device,
|
|
4843
4843
|
buckets,
|
|
4844
|
-
sessions: sessions ?? []
|
|
4844
|
+
sessions: sessions ?? [],
|
|
4845
|
+
...options?.syncAchievements === void 0 ? {} : { syncAchievements: options.syncAchievements }
|
|
4845
4846
|
};
|
|
4846
|
-
|
|
4847
|
+
}
|
|
4848
|
+
function getIngestPayloadSize(device, buckets, sessions, options) {
|
|
4849
|
+
return Buffer.byteLength(
|
|
4850
|
+
JSON.stringify(buildIngestPayload(device, buckets, sessions, options))
|
|
4851
|
+
);
|
|
4847
4852
|
}
|
|
4848
4853
|
var ApiClient = class {
|
|
4849
4854
|
constructor(apiUrl, apiKey) {
|
|
@@ -4855,11 +4860,17 @@ var ApiClient = class {
|
|
|
4855
4860
|
/**
|
|
4856
4861
|
* Ingest buckets and sessions to server
|
|
4857
4862
|
*/
|
|
4858
|
-
async ingest(device, buckets, sessions, onProgress) {
|
|
4863
|
+
async ingest(device, buckets, sessions, onProgress, options) {
|
|
4859
4864
|
let lastError;
|
|
4860
4865
|
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
4861
4866
|
try {
|
|
4862
|
-
return await this.sendIngest(
|
|
4867
|
+
return await this.sendIngest(
|
|
4868
|
+
device,
|
|
4869
|
+
buckets,
|
|
4870
|
+
sessions,
|
|
4871
|
+
onProgress,
|
|
4872
|
+
options
|
|
4873
|
+
);
|
|
4863
4874
|
} catch (err) {
|
|
4864
4875
|
lastError = err;
|
|
4865
4876
|
const httpErr = err;
|
|
@@ -4874,16 +4885,11 @@ var ApiClient = class {
|
|
|
4874
4885
|
}
|
|
4875
4886
|
throw lastError;
|
|
4876
4887
|
}
|
|
4877
|
-
sendIngest(device, buckets, sessions, onProgress) {
|
|
4888
|
+
sendIngest(device, buckets, sessions, onProgress, options) {
|
|
4878
4889
|
return new Promise((resolve4, reject) => {
|
|
4879
4890
|
const url = new URL2("/api/usage/ingest", this.apiUrl);
|
|
4880
4891
|
const body = Buffer.from(
|
|
4881
|
-
JSON.stringify(
|
|
4882
|
-
schemaVersion: 2,
|
|
4883
|
-
device,
|
|
4884
|
-
buckets,
|
|
4885
|
-
sessions: sessions ?? []
|
|
4886
|
-
})
|
|
4892
|
+
JSON.stringify(buildIngestPayload(device, buckets, sessions, options))
|
|
4887
4893
|
);
|
|
4888
4894
|
const totalBytes = body.length;
|
|
4889
4895
|
const mod = url.protocol === "https:" ? https : http;
|
|
@@ -5316,6 +5322,7 @@ function getDetectedTools() {
|
|
|
5316
5322
|
// src/services/sync-service.ts
|
|
5317
5323
|
var BATCH_SIZE = 100;
|
|
5318
5324
|
var SESSION_BATCH_SIZE = 500;
|
|
5325
|
+
var MAX_INGEST_PAYLOAD_BYTES = 8 * 1024 * 1024;
|
|
5319
5326
|
var PROGRESS_BAR_WIDTH = 28;
|
|
5320
5327
|
function formatBytes(bytes) {
|
|
5321
5328
|
if (bytes < 1024) return `${bytes}B`;
|
|
@@ -5327,6 +5334,9 @@ function renderProgressBar(progress) {
|
|
|
5327
5334
|
const filled = Math.round(safeProgress * PROGRESS_BAR_WIDTH);
|
|
5328
5335
|
return `${"\u2588".repeat(filled)}${"\u2591".repeat(PROGRESS_BAR_WIDTH - filled)}`;
|
|
5329
5336
|
}
|
|
5337
|
+
function shouldSyncAchievementsForBatch(batchIndex, totalBatches) {
|
|
5338
|
+
return batchIndex === totalBatches - 1;
|
|
5339
|
+
}
|
|
5330
5340
|
function writeUploadProgress(sent, total, batchNum, totalBatches) {
|
|
5331
5341
|
const pct = total > 0 ? Math.round(sent / total * 100) : 100;
|
|
5332
5342
|
const progressBar = renderProgressBar(total > 0 ? sent / total : 1);
|
|
@@ -5456,6 +5466,64 @@ var SyncFailure = class extends Error {
|
|
|
5456
5466
|
kind;
|
|
5457
5467
|
causeError;
|
|
5458
5468
|
};
|
|
5469
|
+
function splitOversizedUploadBatch(device, buckets, sessions) {
|
|
5470
|
+
const payloadSize = getIngestPayloadSize(device, buckets, sessions, {
|
|
5471
|
+
syncAchievements: true
|
|
5472
|
+
});
|
|
5473
|
+
if (payloadSize <= MAX_INGEST_PAYLOAD_BYTES) {
|
|
5474
|
+
return [{ buckets, sessions }];
|
|
5475
|
+
}
|
|
5476
|
+
if (buckets.length + sessions.length <= 1) {
|
|
5477
|
+
throw new SyncFailure(
|
|
5478
|
+
`A single usage record exceeds the ${formatBytes(MAX_INGEST_PAYLOAD_BYTES)} ingest payload limit. Reduce the record size before syncing.`,
|
|
5479
|
+
"error"
|
|
5480
|
+
);
|
|
5481
|
+
}
|
|
5482
|
+
if (sessions.length > 1 && sessions.length >= buckets.length) {
|
|
5483
|
+
const midpoint = Math.ceil(sessions.length / 2);
|
|
5484
|
+
return [
|
|
5485
|
+
...splitOversizedUploadBatch(
|
|
5486
|
+
device,
|
|
5487
|
+
buckets,
|
|
5488
|
+
sessions.slice(0, midpoint)
|
|
5489
|
+
),
|
|
5490
|
+
...splitOversizedUploadBatch(device, [], sessions.slice(midpoint))
|
|
5491
|
+
];
|
|
5492
|
+
}
|
|
5493
|
+
if (buckets.length > 1) {
|
|
5494
|
+
const midpoint = Math.ceil(buckets.length / 2);
|
|
5495
|
+
return [
|
|
5496
|
+
...splitOversizedUploadBatch(
|
|
5497
|
+
device,
|
|
5498
|
+
buckets.slice(0, midpoint),
|
|
5499
|
+
sessions
|
|
5500
|
+
),
|
|
5501
|
+
...splitOversizedUploadBatch(device, buckets.slice(midpoint), [])
|
|
5502
|
+
];
|
|
5503
|
+
}
|
|
5504
|
+
return [
|
|
5505
|
+
...splitOversizedUploadBatch(device, buckets, []),
|
|
5506
|
+
...splitOversizedUploadBatch(device, [], sessions)
|
|
5507
|
+
];
|
|
5508
|
+
}
|
|
5509
|
+
function buildUploadBatches(device, buckets, sessions) {
|
|
5510
|
+
const batches = [];
|
|
5511
|
+
let bucketOffset = 0;
|
|
5512
|
+
let sessionOffset = 0;
|
|
5513
|
+
while (bucketOffset < buckets.length || sessionOffset < sessions.length) {
|
|
5514
|
+
const batchBuckets = buckets.slice(bucketOffset, bucketOffset + BATCH_SIZE);
|
|
5515
|
+
const batchSessions = sessions.slice(
|
|
5516
|
+
sessionOffset,
|
|
5517
|
+
sessionOffset + SESSION_BATCH_SIZE
|
|
5518
|
+
);
|
|
5519
|
+
batches.push(
|
|
5520
|
+
...splitOversizedUploadBatch(device, batchBuckets, batchSessions)
|
|
5521
|
+
);
|
|
5522
|
+
bucketOffset += batchBuckets.length;
|
|
5523
|
+
sessionOffset += batchSessions.length;
|
|
5524
|
+
}
|
|
5525
|
+
return batches;
|
|
5526
|
+
}
|
|
5459
5527
|
async function runSync(config, opts = {}) {
|
|
5460
5528
|
const { quiet = false, source = "manual", throws = false } = opts;
|
|
5461
5529
|
const lock = tryAcquireSyncLock(source);
|
|
@@ -5596,24 +5664,19 @@ async function runSync(config, opts = {}) {
|
|
|
5596
5664
|
markSyncSucceeded(source, { buckets: 0, sessions: 0 });
|
|
5597
5665
|
return { buckets: 0, sessions: 0 };
|
|
5598
5666
|
}
|
|
5599
|
-
const
|
|
5600
|
-
|
|
5601
|
-
|
|
5667
|
+
const uploadBatches = buildUploadBatches(
|
|
5668
|
+
device,
|
|
5669
|
+
changedBuckets,
|
|
5670
|
+
changedSessions
|
|
5602
5671
|
);
|
|
5603
|
-
const totalBatches =
|
|
5604
|
-
const batchPayloadSizes =
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
batchIdx * BATCH_SIZE,
|
|
5610
|
-
(batchIdx + 1) * BATCH_SIZE
|
|
5611
|
-
),
|
|
5612
|
-
changedSessions.slice(
|
|
5613
|
-
batchIdx * SESSION_BATCH_SIZE,
|
|
5614
|
-
(batchIdx + 1) * SESSION_BATCH_SIZE
|
|
5672
|
+
const totalBatches = uploadBatches.length;
|
|
5673
|
+
const batchPayloadSizes = uploadBatches.map(
|
|
5674
|
+
(batch, batchIdx) => getIngestPayloadSize(device, batch.buckets, batch.sessions, {
|
|
5675
|
+
syncAchievements: shouldSyncAchievementsForBatch(
|
|
5676
|
+
batchIdx,
|
|
5677
|
+
totalBatches
|
|
5615
5678
|
)
|
|
5616
|
-
)
|
|
5679
|
+
})
|
|
5617
5680
|
);
|
|
5618
5681
|
const totalPayloadBytes = batchPayloadSizes.reduce(
|
|
5619
5682
|
(sum, size) => sum + size,
|
|
@@ -5640,14 +5703,11 @@ async function runSync(config, opts = {}) {
|
|
|
5640
5703
|
);
|
|
5641
5704
|
}
|
|
5642
5705
|
for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {
|
|
5643
|
-
const
|
|
5644
|
-
|
|
5645
|
-
(
|
|
5646
|
-
|
|
5647
|
-
const batchSessions =
|
|
5648
|
-
batchIdx * SESSION_BATCH_SIZE,
|
|
5649
|
-
(batchIdx + 1) * SESSION_BATCH_SIZE
|
|
5650
|
-
);
|
|
5706
|
+
const uploadBatch = uploadBatches[batchIdx];
|
|
5707
|
+
if (!uploadBatch) {
|
|
5708
|
+
throw new SyncFailure("Upload batch planning failed.", "error");
|
|
5709
|
+
}
|
|
5710
|
+
const { buckets: batch, sessions: batchSessions } = uploadBatch;
|
|
5651
5711
|
const batchNum = batchIdx + 1;
|
|
5652
5712
|
const result = await apiClient.ingest(
|
|
5653
5713
|
device,
|
|
@@ -5660,6 +5720,12 @@ async function runSync(config, opts = {}) {
|
|
|
5660
5720
|
batchNum,
|
|
5661
5721
|
totalBatches
|
|
5662
5722
|
);
|
|
5723
|
+
},
|
|
5724
|
+
{
|
|
5725
|
+
syncAchievements: shouldSyncAchievementsForBatch(
|
|
5726
|
+
batchIdx,
|
|
5727
|
+
totalBatches
|
|
5728
|
+
)
|
|
5663
5729
|
}
|
|
5664
5730
|
);
|
|
5665
5731
|
totalIngested += result.ingested ?? batch.length;
|