@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 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 getIngestPayloadSize(device, buckets, sessions) {
4840
- const payload = {
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
- return Buffer.byteLength(JSON.stringify(payload));
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(device, buckets, sessions, onProgress);
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 bucketBatches = Math.ceil(changedBuckets.length / BATCH_SIZE);
5600
- const sessionBatches = Math.ceil(
5601
- changedSessions.length / SESSION_BATCH_SIZE
5667
+ const uploadBatches = buildUploadBatches(
5668
+ device,
5669
+ changedBuckets,
5670
+ changedSessions
5602
5671
  );
5603
- const totalBatches = Math.max(bucketBatches, sessionBatches, 1);
5604
- const batchPayloadSizes = Array.from(
5605
- { length: totalBatches },
5606
- (_, batchIdx) => getIngestPayloadSize(
5607
- device,
5608
- changedBuckets.slice(
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 batch = changedBuckets.slice(
5644
- batchIdx * BATCH_SIZE,
5645
- (batchIdx + 1) * BATCH_SIZE
5646
- );
5647
- const batchSessions = changedSessions.slice(
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;