github-issue-tower-defence-management 1.132.0 → 1.133.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.
- package/CHANGELOG.md +14 -0
- package/README.md +7 -7
- package/bin/adapter/entry-points/cli/index.js +4 -4
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.js +2 -1
- package/bin/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.js.map +1 -1
- package/bin/adapter/entry-points/handlers/OauthTokenSelectHandler.js +2 -1
- package/bin/adapter/entry-points/handlers/OauthTokenSelectHandler.js.map +1 -1
- package/bin/adapter/proxy/TokenListLoader.js +4 -5
- package/bin/adapter/proxy/TokenListLoader.js.map +1 -1
- package/bin/adapter/repositories/NodeTmuxSessionRepository.js +19 -0
- package/bin/adapter/repositories/NodeTmuxSessionRepository.js.map +1 -1
- package/bin/adapter/repositories/clSessionScopeUnitName.js +10 -0
- package/bin/adapter/repositories/clSessionScopeUnitName.js.map +1 -0
- package/bin/domain/usecases/LiveSessionOauthTokenSelectUseCase.js +5 -4
- package/bin/domain/usecases/LiveSessionOauthTokenSelectUseCase.js.map +1 -1
- package/bin/domain/usecases/OauthTokenSelectUseCase.js +31 -4
- package/bin/domain/usecases/OauthTokenSelectUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/cli/index.ts +4 -4
- package/src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.ts +28 -24
- package/src/adapter/entry-points/handlers/OauthTokenSelectHandler.ts +28 -24
- package/src/adapter/proxy/TokenListLoader.test.ts +52 -0
- package/src/adapter/proxy/TokenListLoader.ts +25 -5
- package/src/adapter/repositories/NodeTmuxSessionRepository.test.ts +55 -0
- package/src/adapter/repositories/NodeTmuxSessionRepository.ts +27 -0
- package/src/adapter/repositories/clSessionScopeUnitName.test.ts +76 -0
- package/src/adapter/repositories/clSessionScopeUnitName.ts +5 -0
- package/src/domain/usecases/LiveSessionOauthTokenSelectUseCase.test.ts +74 -0
- package/src/domain/usecases/LiveSessionOauthTokenSelectUseCase.ts +13 -2
- package/src/domain/usecases/OauthTokenSelectUseCase.test.ts +162 -0
- package/src/domain/usecases/OauthTokenSelectUseCase.ts +47 -2
- package/types/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/OauthTokenSelectHandler.d.ts.map +1 -1
- package/types/adapter/proxy/TokenListLoader.d.ts +1 -0
- package/types/adapter/proxy/TokenListLoader.d.ts.map +1 -1
- package/types/adapter/repositories/NodeTmuxSessionRepository.d.ts +1 -0
- package/types/adapter/repositories/NodeTmuxSessionRepository.d.ts.map +1 -1
- package/types/adapter/repositories/clSessionScopeUnitName.d.ts +2 -0
- package/types/adapter/repositories/clSessionScopeUnitName.d.ts.map +1 -0
- package/types/domain/usecases/LiveSessionOauthTokenSelectUseCase.d.ts +2 -2
- package/types/domain/usecases/LiveSessionOauthTokenSelectUseCase.d.ts.map +1 -1
- package/types/domain/usecases/OauthTokenSelectUseCase.d.ts +6 -1
- package/types/domain/usecases/OauthTokenSelectUseCase.d.ts.map +1 -1
|
@@ -247,3 +247,165 @@ describe('OauthTokenSelectUseCase', () => {
|
|
|
247
247
|
expect(alive?.eligible).toBe(true);
|
|
248
248
|
});
|
|
249
249
|
});
|
|
250
|
+
|
|
251
|
+
const sweepingRandom = (count: number): (() => number) => {
|
|
252
|
+
let index = 0;
|
|
253
|
+
return () => {
|
|
254
|
+
const value = (index + 0.5) / count;
|
|
255
|
+
index += 1;
|
|
256
|
+
return value;
|
|
257
|
+
};
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const throwingRandom = (): number => {
|
|
261
|
+
throw new Error('random source must not be consulted');
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const withSelectionWeight = (
|
|
265
|
+
base: OauthTokenCandidate,
|
|
266
|
+
selectionWeight: number,
|
|
267
|
+
): OauthTokenCandidate => ({ ...base, selectionWeight });
|
|
268
|
+
|
|
269
|
+
describe('OauthTokenSelectUseCase selectionWeight', () => {
|
|
270
|
+
const useCase = new OauthTokenSelectUseCase();
|
|
271
|
+
|
|
272
|
+
it('keeps the deterministic soonest-7d selection and never consults random when weights are uniform', () => {
|
|
273
|
+
const result = useCase.run(
|
|
274
|
+
[
|
|
275
|
+
candidate(
|
|
276
|
+
'far',
|
|
277
|
+
snapshot({ sevenDayUtilization: 0.1, sevenDayReset: NOW + 6 * DAY }),
|
|
278
|
+
),
|
|
279
|
+
candidate(
|
|
280
|
+
'soon',
|
|
281
|
+
snapshot({ sevenDayUtilization: 0.1, sevenDayReset: NOW + 2 * DAY }),
|
|
282
|
+
),
|
|
283
|
+
],
|
|
284
|
+
NOW,
|
|
285
|
+
throwingRandom,
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
expect(result.selected?.name).toBe('soon');
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('treats an absent selectionWeight the same as weight 1 (uniform, deterministic)', () => {
|
|
292
|
+
const result = useCase.run(
|
|
293
|
+
[
|
|
294
|
+
withSelectionWeight(
|
|
295
|
+
candidate('far', snapshot({ sevenDayReset: NOW + 6 * DAY })),
|
|
296
|
+
1,
|
|
297
|
+
),
|
|
298
|
+
candidate('soon', snapshot({ sevenDayReset: NOW + 2 * DAY })),
|
|
299
|
+
],
|
|
300
|
+
NOW,
|
|
301
|
+
throwingRandom,
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
expect(result.selected?.name).toBe('soon');
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('selects a sole eligible low-weight token without consulting random (no starvation)', () => {
|
|
308
|
+
const result = useCase.run(
|
|
309
|
+
[
|
|
310
|
+
withSelectionWeight(candidate('lowWeightOnly', snapshot({})), 0.01),
|
|
311
|
+
candidate('blocked', snapshot({ fiveHourUtilization: 0.9 })),
|
|
312
|
+
],
|
|
313
|
+
NOW,
|
|
314
|
+
throwingRandom,
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
expect(result.selected?.name).toBe('lowWeightOnly');
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('chooses a lower-weight token proportionally less often among eligible candidates', () => {
|
|
321
|
+
const count = 1000;
|
|
322
|
+
const random = sweepingRandom(count);
|
|
323
|
+
const selectionCounts = new Map<string, number>();
|
|
324
|
+
|
|
325
|
+
for (let i = 0; i < count; i += 1) {
|
|
326
|
+
const result = useCase.run(
|
|
327
|
+
[
|
|
328
|
+
withSelectionWeight(candidate('heavy', snapshot({})), 1),
|
|
329
|
+
withSelectionWeight(candidate('light', snapshot({})), 0.5),
|
|
330
|
+
],
|
|
331
|
+
NOW,
|
|
332
|
+
random,
|
|
333
|
+
);
|
|
334
|
+
const name = result.selected?.name ?? 'none';
|
|
335
|
+
selectionCounts.set(name, (selectionCounts.get(name) ?? 0) + 1);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const heavy = selectionCounts.get('heavy') ?? 0;
|
|
339
|
+
const light = selectionCounts.get('light') ?? 0;
|
|
340
|
+
expect(heavy + light).toBe(count);
|
|
341
|
+
expect(light).toBeGreaterThan(0);
|
|
342
|
+
expect(light).toBeLessThan(heavy);
|
|
343
|
+
expect(Math.abs(light / count - 1 / 3)).toBeLessThan(0.02);
|
|
344
|
+
expect(Math.abs(heavy / count - 2 / 3)).toBeLessThan(0.02);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
it('chooses a higher-weight token more often among eligible candidates', () => {
|
|
348
|
+
const count = 1000;
|
|
349
|
+
const random = sweepingRandom(count);
|
|
350
|
+
const selectionCounts = new Map<string, number>();
|
|
351
|
+
|
|
352
|
+
for (let i = 0; i < count; i += 1) {
|
|
353
|
+
const result = useCase.run(
|
|
354
|
+
[
|
|
355
|
+
withSelectionWeight(candidate('double', snapshot({})), 2),
|
|
356
|
+
withSelectionWeight(candidate('single', snapshot({})), 1),
|
|
357
|
+
],
|
|
358
|
+
NOW,
|
|
359
|
+
random,
|
|
360
|
+
);
|
|
361
|
+
const name = result.selected?.name ?? 'none';
|
|
362
|
+
selectionCounts.set(name, (selectionCounts.get(name) ?? 0) + 1);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const double = selectionCounts.get('double') ?? 0;
|
|
366
|
+
const single = selectionCounts.get('single') ?? 0;
|
|
367
|
+
expect(double).toBeGreaterThan(single);
|
|
368
|
+
expect(single).toBeGreaterThan(0);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it('gives a zero-weight token no chance while other eligible tokens exist', () => {
|
|
372
|
+
const count = 100;
|
|
373
|
+
const random = sweepingRandom(count);
|
|
374
|
+
const selectionCounts = new Map<string, number>();
|
|
375
|
+
|
|
376
|
+
for (let i = 0; i < count; i += 1) {
|
|
377
|
+
const result = useCase.run(
|
|
378
|
+
[
|
|
379
|
+
withSelectionWeight(candidate('zero', snapshot({})), 0),
|
|
380
|
+
withSelectionWeight(candidate('positive', snapshot({})), 1),
|
|
381
|
+
],
|
|
382
|
+
NOW,
|
|
383
|
+
random,
|
|
384
|
+
);
|
|
385
|
+
const name = result.selected?.name ?? 'none';
|
|
386
|
+
selectionCounts.set(name, (selectionCounts.get(name) ?? 0) + 1);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
expect(selectionCounts.get('zero') ?? 0).toBe(0);
|
|
390
|
+
expect(selectionCounts.get('positive') ?? 0).toBe(count);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('falls back to the deterministic best when every eligible weight is zero', () => {
|
|
394
|
+
const result = useCase.run(
|
|
395
|
+
[
|
|
396
|
+
withSelectionWeight(
|
|
397
|
+
candidate('far', snapshot({ sevenDayReset: NOW + 6 * DAY })),
|
|
398
|
+
0,
|
|
399
|
+
),
|
|
400
|
+
withSelectionWeight(
|
|
401
|
+
candidate('soon', snapshot({ sevenDayReset: NOW + 2 * DAY })),
|
|
402
|
+
0,
|
|
403
|
+
),
|
|
404
|
+
],
|
|
405
|
+
NOW,
|
|
406
|
+
throwingRandom,
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
expect(result.selected?.name).toBe('soon');
|
|
410
|
+
});
|
|
411
|
+
});
|
|
@@ -12,6 +12,16 @@ export type OauthTokenCandidate = {
|
|
|
12
12
|
subscriptionDisabled: boolean;
|
|
13
13
|
unifiedRejected: boolean;
|
|
14
14
|
fableRejected: boolean;
|
|
15
|
+
selectionWeight?: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type SelectionRandom = () => number;
|
|
19
|
+
|
|
20
|
+
export const DEFAULT_SELECTION_WEIGHT = 1;
|
|
21
|
+
|
|
22
|
+
export const selectionWeightOf = (candidate: OauthTokenCandidate): number => {
|
|
23
|
+
const weight = candidate.selectionWeight ?? DEFAULT_SELECTION_WEIGHT;
|
|
24
|
+
return weight > 0 ? weight : 0;
|
|
15
25
|
};
|
|
16
26
|
|
|
17
27
|
export type OauthTokenCandidateMetrics = {
|
|
@@ -34,10 +44,38 @@ const SEVEN_DAYS_IN_SECONDS = 7 * SECONDS_PER_DAY;
|
|
|
34
44
|
export const FIVE_HOUR_MIN_FREE_RATIO = 0.6;
|
|
35
45
|
export const SEVEN_DAY_MIN_FREE_RATIO = 0.07;
|
|
36
46
|
|
|
47
|
+
export const selectWeightedCandidate = <Entry>(
|
|
48
|
+
eligible: Entry[],
|
|
49
|
+
candidateOf: (entry: Entry) => OauthTokenCandidate,
|
|
50
|
+
deterministicBest: Entry,
|
|
51
|
+
random: SelectionRandom,
|
|
52
|
+
): Entry => {
|
|
53
|
+
if (eligible.length <= 1) {
|
|
54
|
+
return deterministicBest;
|
|
55
|
+
}
|
|
56
|
+
const weights = eligible.map((entry) =>
|
|
57
|
+
selectionWeightOf(candidateOf(entry)),
|
|
58
|
+
);
|
|
59
|
+
const totalWeight = weights.reduce((sum, weight) => sum + weight, 0);
|
|
60
|
+
const uniform = weights.every((weight) => weight === weights[0]);
|
|
61
|
+
if (uniform || totalWeight <= 0) {
|
|
62
|
+
return deterministicBest;
|
|
63
|
+
}
|
|
64
|
+
let threshold = random() * totalWeight;
|
|
65
|
+
for (let index = 0; index < eligible.length; index += 1) {
|
|
66
|
+
threshold -= weights[index];
|
|
67
|
+
if (threshold < 0) {
|
|
68
|
+
return eligible[index];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return eligible[eligible.length - 1];
|
|
72
|
+
};
|
|
73
|
+
|
|
37
74
|
export class OauthTokenSelectUseCase {
|
|
38
75
|
run = (
|
|
39
76
|
candidates: OauthTokenCandidate[],
|
|
40
77
|
nowEpochSeconds: number,
|
|
78
|
+
random: SelectionRandom = Math.random,
|
|
41
79
|
): OauthTokenSelectResult => {
|
|
42
80
|
const evaluated = candidates.map((candidate) => ({
|
|
43
81
|
candidate,
|
|
@@ -51,13 +89,20 @@ export class OauthTokenSelectUseCase {
|
|
|
51
89
|
return { selected: null, metrics };
|
|
52
90
|
}
|
|
53
91
|
|
|
54
|
-
const
|
|
92
|
+
const deterministicBest = eligible.reduce((bestEntry, currentEntry) =>
|
|
55
93
|
currentEntry.metric.sevenDayEndEpoch < bestEntry.metric.sevenDayEndEpoch
|
|
56
94
|
? currentEntry
|
|
57
95
|
: bestEntry,
|
|
58
96
|
);
|
|
59
97
|
|
|
60
|
-
|
|
98
|
+
const selected = selectWeightedCandidate(
|
|
99
|
+
eligible,
|
|
100
|
+
(entry) => entry.candidate,
|
|
101
|
+
deterministicBest,
|
|
102
|
+
random,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
return { selected: selected.candidate, metrics };
|
|
61
106
|
};
|
|
62
107
|
|
|
63
108
|
private evaluate = (
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveSessionOauthTokenSelectHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,yEAAyE,CAAC;AACtH,OAAO,EAEL,kCAAkC,EACnC,MAAM,6DAA6D,CAAC;
|
|
1
|
+
{"version":3,"file":"LiveSessionOauthTokenSelectHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/LiveSessionOauthTokenSelectHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,yEAAyE,CAAC;AACtH,OAAO,EAEL,kCAAkC,EACnC,MAAM,6DAA6D,CAAC;AAerE,MAAM,MAAM,uCAAuC,GAAG;IACpD,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,wCAAwC,GAAG;IACrD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAEF,qBAAa,kCAAkC;IAE3C,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,qBAAqB;gBADrB,OAAO,GAAE,kCAA6E,EACtF,qBAAqB,GAAE,2BAAmE;IAG7G,MAAM,GACJ,OAAO,uCAAuC,KAC7C,wCAAwC,CAkEzC;IAEF,OAAO,CAAC,iBAAiB,CAyBvB;CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OauthTokenSelectHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/OauthTokenSelectHandler.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"OauthTokenSelectHandler.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/handlers/OauthTokenSelectHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,uBAAuB,EACxB,MAAM,kDAAkD,CAAC;AAQ1D,MAAM,MAAM,4BAA4B,GAAG;IACzC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAKF,eAAO,MAAM,wBAAwB,GACnC,cAAc,MAAM,GAAG,IAAI,KAC1B,MAAM,GAAG,IASX,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,mBAAmB,MAAM,GAAG,IAAI,KAC/B,MASF,CAAC;AAEF,qBAAa,uBAAuB;IAEhC,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,GAAE,uBAAuD;IAGnF,MAAM,GACJ,OAAO,4BAA4B,KAClC,6BAA6B,CA4D9B;IAEF,OAAO,CAAC,iBAAiB,CAuBvB;CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TokenListLoader.d.ts","sourceRoot":"","sources":["../../../src/adapter/proxy/TokenListLoader.ts"],"names":[],"mappings":"AAiBA,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"TokenListLoader.d.ts","sourceRoot":"","sources":["../../../src/adapter/proxy/TokenListLoader.ts"],"names":[],"mappings":"AAiBA,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAYF,eAAO,MAAM,gBAAgB,GAAI,UAAU,MAAM,KAAG,UAAU,EAAE,GAAG,IAmClE,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,KAAG,MAAM,EAAE,GAAG,IAIxD,CAAC"}
|
|
@@ -9,5 +9,6 @@ export declare class NodeTmuxSessionRepository implements TmuxSessionRepository
|
|
|
9
9
|
listInteractiveProcessCommandLines: () => Promise<string[]>;
|
|
10
10
|
launchDetachedSession: (sessionName: string, launcherCommand: string, issueUrl: string) => Promise<void>;
|
|
11
11
|
killSession: (sessionName: string) => Promise<void>;
|
|
12
|
+
private stopClSessionScope;
|
|
12
13
|
}
|
|
13
14
|
//# sourceMappingURL=NodeTmuxSessionRepository.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeTmuxSessionRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/NodeTmuxSessionRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6DAA6D,CAAC;AACjG,OAAO,EAAE,qBAAqB,EAAE,MAAM,gEAAgE,CAAC;AACvG,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"NodeTmuxSessionRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/NodeTmuxSessionRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6DAA6D,CAAC;AACjG,OAAO,EAAE,qBAAqB,EAAE,MAAM,gEAAgE,CAAC;AACvG,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAGxE,qBAAa,yBAA0B,YAAW,qBAAqB;IACzD,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBAAlB,kBAAkB,EAAE,kBAAkB;IAEnE,oBAAoB,QAAa,OAAO,CAAC,MAAM,EAAE,CAAC,CAYhD;IAEF,4BAA4B,QAAa,OAAO,CAAC,eAAe,EAAE,CAAC,CAkBjE;IAEF,kCAAkC,QAAa,OAAO,CAAC,MAAM,EAAE,CAAC,CAY9D;IAEF,qBAAqB,GACnB,aAAa,MAAM,EACnB,iBAAiB,MAAM,EACvB,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAAC,CAcd;IAEF,WAAW,GAAU,aAAa,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC,CAatD;IAEF,OAAO,CAAC,kBAAkB,CAuBxB;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clSessionScopeUnitName.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/clSessionScopeUnitName.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,GAAI,aAAa,MAAM,KAAG,MAI5D,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ClaudeLiveSession } from './adapter-interfaces/ClaudeLiveSessionRepository';
|
|
2
|
-
import { OauthTokenCandidate, OauthTokenSelectUseCase } from './OauthTokenSelectUseCase';
|
|
2
|
+
import { OauthTokenCandidate, OauthTokenSelectUseCase, SelectionRandom } from './OauthTokenSelectUseCase';
|
|
3
3
|
export type LiveSessionOauthTokenCandidateMetrics = {
|
|
4
4
|
name: string;
|
|
5
5
|
fiveHourFreeRatio: number;
|
|
@@ -16,7 +16,7 @@ export type LiveSessionOauthTokenSelectResult = {
|
|
|
16
16
|
export declare class LiveSessionOauthTokenSelectUseCase {
|
|
17
17
|
private readonly rateLimitSelectUseCase;
|
|
18
18
|
constructor(rateLimitSelectUseCase?: OauthTokenSelectUseCase);
|
|
19
|
-
run: (candidates: OauthTokenCandidate[], liveSessions: ClaudeLiveSession[], nowEpochSeconds: number) => LiveSessionOauthTokenSelectResult;
|
|
19
|
+
run: (candidates: OauthTokenCandidate[], liveSessions: ClaudeLiveSession[], nowEpochSeconds: number, random?: SelectionRandom) => LiveSessionOauthTokenSelectResult;
|
|
20
20
|
private preferred;
|
|
21
21
|
private liveSessionCountByToken;
|
|
22
22
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveSessionOauthTokenSelectUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/LiveSessionOauthTokenSelectUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kDAAkD,CAAC;AACrF,OAAO,EACL,mBAAmB,EACnB,uBAAuB,
|
|
1
|
+
{"version":3,"file":"LiveSessionOauthTokenSelectUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/LiveSessionOauthTokenSelectUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kDAAkD,CAAC;AACrF,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,eAAe,EAEhB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,qCAAqC,GAAG;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,iCAAiC,GAAG;IAC9C,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,qCAAqC,EAAE,CAAC;CAClD,CAAC;AAEF,qBAAa,kCAAkC;IAE3C,OAAO,CAAC,QAAQ,CAAC,sBAAsB;gBAAtB,sBAAsB,GAAE,uBAAuD;IAGlG,GAAG,GACD,YAAY,mBAAmB,EAAE,EACjC,cAAc,iBAAiB,EAAE,EACjC,iBAAiB,MAAM,EACvB,SAAQ,eAA6B,KACpC,iCAAiC,CA+ClC;IAEF,OAAO,CAAC,SAAS,CAUf;IAEF,OAAO,CAAC,uBAAuB,CAe7B;CACH"}
|
|
@@ -11,7 +11,11 @@ export type OauthTokenCandidate = {
|
|
|
11
11
|
subscriptionDisabled: boolean;
|
|
12
12
|
unifiedRejected: boolean;
|
|
13
13
|
fableRejected: boolean;
|
|
14
|
+
selectionWeight?: number;
|
|
14
15
|
};
|
|
16
|
+
export type SelectionRandom = () => number;
|
|
17
|
+
export declare const DEFAULT_SELECTION_WEIGHT = 1;
|
|
18
|
+
export declare const selectionWeightOf: (candidate: OauthTokenCandidate) => number;
|
|
15
19
|
export type OauthTokenCandidateMetrics = {
|
|
16
20
|
name: string;
|
|
17
21
|
fiveHourFreeRatio: number;
|
|
@@ -26,8 +30,9 @@ export type OauthTokenSelectResult = {
|
|
|
26
30
|
};
|
|
27
31
|
export declare const FIVE_HOUR_MIN_FREE_RATIO = 0.6;
|
|
28
32
|
export declare const SEVEN_DAY_MIN_FREE_RATIO = 0.07;
|
|
33
|
+
export declare const selectWeightedCandidate: <Entry>(eligible: Entry[], candidateOf: (entry: Entry) => OauthTokenCandidate, deterministicBest: Entry, random: SelectionRandom) => Entry;
|
|
29
34
|
export declare class OauthTokenSelectUseCase {
|
|
30
|
-
run: (candidates: OauthTokenCandidate[], nowEpochSeconds: number) => OauthTokenSelectResult;
|
|
35
|
+
run: (candidates: OauthTokenCandidate[], nowEpochSeconds: number, random?: SelectionRandom) => OauthTokenSelectResult;
|
|
31
36
|
private evaluate;
|
|
32
37
|
private exclusionReason;
|
|
33
38
|
private fiveHourFreeRatio;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OauthTokenSelectUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/OauthTokenSelectUseCase.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC1C,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"OauthTokenSelectUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/OauthTokenSelectUseCase.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC1C,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC;AAE3C,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,eAAO,MAAM,iBAAiB,GAAI,WAAW,mBAAmB,KAAG,MAGlE,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,0BAA0B,EAAE,CAAC;CACvC,CAAC;AAKF,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAE7C,eAAO,MAAM,uBAAuB,GAAI,KAAK,EAC3C,UAAU,KAAK,EAAE,EACjB,aAAa,CAAC,KAAK,EAAE,KAAK,KAAK,mBAAmB,EAClD,mBAAmB,KAAK,EACxB,QAAQ,eAAe,KACtB,KAoBF,CAAC;AAEF,qBAAa,uBAAuB;IAClC,GAAG,GACD,YAAY,mBAAmB,EAAE,EACjC,iBAAiB,MAAM,EACvB,SAAQ,eAA6B,KACpC,sBAAsB,CA2BvB;IAEF,OAAO,CAAC,QAAQ,CAiCd;IAEF,OAAO,CAAC,eAAe,CAuBrB;IAEF,OAAO,CAAC,iBAAiB,CAWvB;IAEF,OAAO,CAAC,iBAAiB,CAWvB;IAEF,OAAO,CAAC,gBAAgB,CActB;IAEF,OAAO,CAAC,aAAa,CAGwC;IAE7D,OAAO,CAAC,wBAAwB,CAG9B;IAEF,OAAO,CAAC,SAAS,CAAsD;CACxE"}
|