@cortexkit/antigravity-auth-core 3.0.21 → 3.0.23
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/common-auth-embedded/fs/refresh-file-lock.js +2 -2
- package/dist/common-auth-embedded/fs/with-lock.js +37 -10
- package/dist/common-auth-embedded/quota/format.d.ts +9 -4
- package/dist/common-auth-embedded/quota/format.js +45 -26
- package/dist/common-auth-embedded/source-output.json +18 -18
- package/package.json +1 -1
|
@@ -244,8 +244,8 @@ export async function acquireRefreshFileLockWithClock(options) {
|
|
|
244
244
|
}
|
|
245
245
|
catch (readError) {
|
|
246
246
|
// The holder can release after exclusive creation reports a collision.
|
|
247
|
-
// Only absence permits
|
|
248
|
-
//
|
|
247
|
+
// Only absence permits acquisition to continue here. Sharing failures
|
|
248
|
+
// escape to withLock's deadline-bounded retry, never to stale eviction.
|
|
249
249
|
if (readError.code !== 'ENOENT')
|
|
250
250
|
throw readError;
|
|
251
251
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { join, resolve } from 'node:path';
|
|
2
|
+
import { PrivateFileError, windowsPrivateFiles } from './private-files.js';
|
|
1
3
|
import { acquireRefreshFileLock } from './refresh-file-lock.js';
|
|
2
4
|
export function lockPathFor(target, name) {
|
|
3
5
|
return `${target}.${name}.lock`;
|
|
@@ -18,20 +20,42 @@ export class LockOwnershipError extends Error {
|
|
|
18
20
|
this.details = details;
|
|
19
21
|
}
|
|
20
22
|
}
|
|
23
|
+
function isChangingLockRead(error, target, name) {
|
|
24
|
+
if (!windowsPrivateFiles ||
|
|
25
|
+
!(error instanceof PrivateFileError) ||
|
|
26
|
+
error.reason !== 'io-error' ||
|
|
27
|
+
(error.win32Code !== 32 && error.win32Code !== 303) ||
|
|
28
|
+
(error.stage !== 'read' && error.stage !== 'verify'))
|
|
29
|
+
return false;
|
|
30
|
+
const path = resolve(lockPathFor(target, name));
|
|
31
|
+
return error.path === path || error.path === join(path, 'owner.json');
|
|
32
|
+
}
|
|
21
33
|
export async function withLock(target, options, fn) {
|
|
22
34
|
const started = performance.now();
|
|
23
35
|
for (;;) {
|
|
24
36
|
options.signal?.throwIfAborted();
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
: {}),
|
|
34
|
-
|
|
37
|
+
let lock;
|
|
38
|
+
let changingReadError;
|
|
39
|
+
try {
|
|
40
|
+
lock = await acquireRefreshFileLock({
|
|
41
|
+
path: target,
|
|
42
|
+
name: options.name,
|
|
43
|
+
ttlMs: options.ttlMs,
|
|
44
|
+
renew: options.renew ?? false,
|
|
45
|
+
...(options.onStep ? { onStep: options.onStep } : {}),
|
|
46
|
+
...(options.onRenewalTimer
|
|
47
|
+
? { onRenewalTimer: options.onRenewalTimer }
|
|
48
|
+
: {}),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (!isChangingLockRead(error, target, options.name))
|
|
53
|
+
throw error;
|
|
54
|
+
// Sharing violations (32) and delete-pending opens (303) do not reveal
|
|
55
|
+
// ownership or expiry. Retry exclusive creation, never infer a stale lock.
|
|
56
|
+
lock = null;
|
|
57
|
+
changingReadError = error;
|
|
58
|
+
}
|
|
35
59
|
if (lock) {
|
|
36
60
|
try {
|
|
37
61
|
options.signal?.throwIfAborted();
|
|
@@ -43,6 +67,9 @@ export async function withLock(target, options, fn) {
|
|
|
43
67
|
}
|
|
44
68
|
const remaining = options.timeoutMs - (performance.now() - started);
|
|
45
69
|
if (remaining <= 0) {
|
|
70
|
+
// Keep persistent native IO failures distinguishable from a live holder.
|
|
71
|
+
if (changingReadError)
|
|
72
|
+
throw changingReadError;
|
|
46
73
|
throw new LockContentionError({
|
|
47
74
|
target,
|
|
48
75
|
name: options.name,
|
|
@@ -30,6 +30,8 @@ export interface QuotaTextOptions {
|
|
|
30
30
|
}
|
|
31
31
|
export interface QuotaWindowPart {
|
|
32
32
|
kind: 'window' | 'budget';
|
|
33
|
+
/** Unknown windows have no dated percentage; budgets retain their own wording. */
|
|
34
|
+
reading: 'known' | 'unknown';
|
|
33
35
|
/** The display name of a quota window, or `credits` for the budget. */
|
|
34
36
|
name: string;
|
|
35
37
|
/**
|
|
@@ -45,7 +47,8 @@ export interface QuotaWindowPart {
|
|
|
45
47
|
remainingPercent?: number;
|
|
46
48
|
/** A bare relative reset span such as `4d`, only when the reset is future. */
|
|
47
49
|
resetIn?: string;
|
|
48
|
-
|
|
50
|
+
/** The reading time, omitted for a window with no reading. */
|
|
51
|
+
checkedAt?: number;
|
|
49
52
|
/** Whether the reset followed this reading and has arrived by `now`. */
|
|
50
53
|
resetSinceReading: boolean;
|
|
51
54
|
}
|
|
@@ -64,9 +67,11 @@ export interface QuotaParts {
|
|
|
64
67
|
*/
|
|
65
68
|
export declare function quotaWindowName(limit: Pick<ProjectedLimit, 'scope' | 'label' | 'windowMinutes'>): string;
|
|
66
69
|
/**
|
|
67
|
-
* Structured quota wording for layouts that need one row per window.
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
+
* Structured quota wording for layouts that need one row per window.
|
|
71
|
+
* Windows without a dated percentage remain as explicit unknown parts. Limits
|
|
72
|
+
* marked absent (not reported) or retired (no longer tracked) remain omitted.
|
|
73
|
+
* Reported windows, future resets and the optional age keep the shared
|
|
74
|
+
* formatter's wording and order.
|
|
70
75
|
*/
|
|
71
76
|
export declare function quotaWindowParts(quota: ProjectedQuota | undefined, options: QuotaTextOptions): QuotaParts;
|
|
72
77
|
/**
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
//
|
|
6
6
|
// The rules: a window is named by its length (`5h`, `7d`), or, for a window
|
|
7
7
|
// that binds only one model family, by the label the plugin stored it under.
|
|
8
|
-
// Every figure is "% left". A window the provider did not
|
|
9
|
-
// record or a retirement tombstone) is left out rather than
|
|
10
|
-
// reported". A reset is a short time from now (`resets 2h`).
|
|
11
|
-
// than fifteen minutes says how old it is (`checked 3h ago`).
|
|
8
|
+
// Every reported window figure is "% left". A window the provider did not
|
|
9
|
+
// report (an absence record or a retirement tombstone) is left out rather than
|
|
10
|
+
// written as "not reported". A reset is a short time from now (`resets 2h`).
|
|
11
|
+
// A reading older than fifteen minutes says how old it is (`checked 3h ago`).
|
|
12
12
|
//
|
|
13
13
|
// Like the rest of this module it reads no clock: `now` is a parameter.
|
|
14
14
|
import { ALL_SCOPE } from './map.js';
|
|
@@ -97,12 +97,14 @@ function displayOrder(left, right) {
|
|
|
97
97
|
return left.label < right.label ? -1 : left.label > right.label ? 1 : 0;
|
|
98
98
|
}
|
|
99
99
|
/**
|
|
100
|
-
* Structured quota wording for layouts that need one row per window.
|
|
101
|
-
*
|
|
102
|
-
*
|
|
100
|
+
* Structured quota wording for layouts that need one row per window.
|
|
101
|
+
* Windows without a dated percentage remain as explicit unknown parts. Limits
|
|
102
|
+
* marked absent (not reported) or retired (no longer tracked) remain omitted.
|
|
103
|
+
* Reported windows, future resets and the optional age keep the shared
|
|
104
|
+
* formatter's wording and order.
|
|
103
105
|
*/
|
|
104
106
|
export function quotaWindowParts(quota, options) {
|
|
105
|
-
const { windows, age } = scopedWindowParts(quota, options);
|
|
107
|
+
const { windows, age } = scopedWindowParts(quota, options, true);
|
|
106
108
|
const parts = windows.map(({ part }) => part);
|
|
107
109
|
return age === undefined ? { windows: parts } : { windows: parts, age };
|
|
108
110
|
}
|
|
@@ -125,34 +127,47 @@ function withShortNames(windows) {
|
|
|
125
127
|
}
|
|
126
128
|
return windows;
|
|
127
129
|
}
|
|
130
|
+
function hasWindowReading(limit) {
|
|
131
|
+
return (Number.isFinite(limit.remainingPercent) && Number.isFinite(limit.checkedAt));
|
|
132
|
+
}
|
|
128
133
|
/**
|
|
129
134
|
* `quotaWindowParts` with each window's scope kept beside it. The narrow form
|
|
130
135
|
* needs the scope to name and pick model-scoped windows; the public parts do
|
|
131
|
-
* not carry
|
|
136
|
+
* not carry the scope.
|
|
132
137
|
*/
|
|
133
|
-
function scopedWindowParts(quota, options) {
|
|
138
|
+
function scopedWindowParts(quota, options, includeUnknown = false) {
|
|
134
139
|
if (!quota)
|
|
135
140
|
return { windows: [] };
|
|
136
141
|
const { now } = options;
|
|
137
142
|
const readings = quota.limits
|
|
138
|
-
.filter((limit) => limit.kind === 'reading' &&
|
|
143
|
+
.filter((limit) => limit.kind === 'reading' && (includeUnknown || hasWindowReading(limit)))
|
|
139
144
|
.sort(displayOrder);
|
|
140
145
|
const windows = readings.map((limit) => {
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
scope: limit.scope,
|
|
144
|
-
...(limit.windowMinutes === undefined
|
|
145
|
-
? {}
|
|
146
|
-
: { windowMinutes: limit.windowMinutes }),
|
|
147
|
-
part: {
|
|
146
|
+
const part = hasWindowReading(limit)
|
|
147
|
+
? {
|
|
148
148
|
kind: 'window',
|
|
149
|
+
reading: 'known',
|
|
149
150
|
name: quotaWindowName(limit),
|
|
150
151
|
short: '',
|
|
151
|
-
figure: percentLeft(limit.remainingPercent
|
|
152
|
-
remainingPercent,
|
|
152
|
+
figure: percentLeft(limit.remainingPercent),
|
|
153
|
+
remainingPercent: clampPercent(limit.remainingPercent),
|
|
153
154
|
checkedAt: limit.checkedAt,
|
|
154
155
|
...resetDetails(limit.resetsAt, limit.checkedAt, now),
|
|
155
|
-
}
|
|
156
|
+
}
|
|
157
|
+
: {
|
|
158
|
+
kind: 'window',
|
|
159
|
+
reading: 'unknown',
|
|
160
|
+
name: quotaWindowName(limit),
|
|
161
|
+
short: '',
|
|
162
|
+
figure: 'no reading',
|
|
163
|
+
resetSinceReading: false,
|
|
164
|
+
};
|
|
165
|
+
return {
|
|
166
|
+
scope: limit.scope,
|
|
167
|
+
...(limit.windowMinutes === undefined
|
|
168
|
+
? {}
|
|
169
|
+
: { windowMinutes: limit.windowMinutes }),
|
|
170
|
+
part,
|
|
156
171
|
};
|
|
157
172
|
});
|
|
158
173
|
const budget = quota.budget;
|
|
@@ -168,6 +183,7 @@ function scopedWindowParts(quota, options) {
|
|
|
168
183
|
spent: budget.reached,
|
|
169
184
|
part: {
|
|
170
185
|
kind: 'budget',
|
|
186
|
+
reading: 'known',
|
|
171
187
|
name: 'credits',
|
|
172
188
|
short: '',
|
|
173
189
|
figure,
|
|
@@ -180,8 +196,11 @@ function scopedWindowParts(quota, options) {
|
|
|
180
196
|
});
|
|
181
197
|
}
|
|
182
198
|
withShortNames(windows);
|
|
183
|
-
|
|
184
|
-
|
|
199
|
+
const readingTimes = windows.flatMap(({ part }) => part.reading === 'known' && part.checkedAt !== undefined
|
|
200
|
+
? [part.checkedAt]
|
|
201
|
+
: []);
|
|
202
|
+
if (readingTimes.length > 0) {
|
|
203
|
+
const age = now - Math.min(...readingTimes);
|
|
185
204
|
if (age > (options.staleAfterMs ?? QUOTA_STALE_AFTER_MS)) {
|
|
186
205
|
return { windows, age: `checked ${shortSpan(age)} ago` };
|
|
187
206
|
}
|
|
@@ -357,13 +376,13 @@ function narrowTextParts(quota, options) {
|
|
|
357
376
|
export function quotaTextParts(quota, options) {
|
|
358
377
|
if (options.form === 'narrow')
|
|
359
378
|
return narrowTextParts(quota, options);
|
|
360
|
-
const
|
|
379
|
+
const { windows, age } = scopedWindowParts(quota, options);
|
|
361
380
|
const full = (options.form ?? 'full') === 'full';
|
|
362
|
-
const text =
|
|
381
|
+
const text = windows.map(({ part }) => {
|
|
363
382
|
const reset = full && part.resetIn ? `, resets ${part.resetIn}` : '';
|
|
364
383
|
return `${part.kind === 'budget' ? '' : `${part.name} `}${part.figure}${reset}`;
|
|
365
384
|
});
|
|
366
|
-
return
|
|
385
|
+
return age === undefined ? text : [...text, age];
|
|
367
386
|
}
|
|
368
387
|
/**
|
|
369
388
|
* A row's quota as one line: `5h 58% left · 7d 90% left` in the compact
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": 1,
|
|
3
3
|
"package": "@cortexkit/common-auth",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.33.0",
|
|
5
5
|
"artifactStatus": "published",
|
|
6
6
|
"publicRoots": {
|
|
7
7
|
"./store": {
|
|
@@ -37,15 +37,15 @@
|
|
|
37
37
|
"import": "./dist/pi-slot/index.js"
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
|
-
"input": "tools/common-auth-build/inputs/cortexkit-common-auth-0.
|
|
41
|
-
"tarballSha256": "
|
|
42
|
-
"sri": "sha512-
|
|
40
|
+
"input": "tools/common-auth-build/inputs/cortexkit-common-auth-0.33.0.tgz",
|
|
41
|
+
"tarballSha256": "bba9f56f7fb353c9c712113722c7c9361f0e13e930c73f57314185b13032a24c",
|
|
42
|
+
"sri": "sha512-cbbyqXTK1TYQZNHb2xA/ueZGQsBvAX6H9hTlQcZZxM7SR/u7tsscyBAWw38ViXl1n/gwkqgsvs2Vbs6cZ0hOrw==",
|
|
43
43
|
"canonicalFiles": 147,
|
|
44
|
-
"canonicalBytes":
|
|
44
|
+
"canonicalBytes": 1003209,
|
|
45
45
|
"generator": {
|
|
46
46
|
"path": "packages/opencode/scripts/embed-common-auth.ts",
|
|
47
47
|
"version": 4,
|
|
48
|
-
"sha256": "
|
|
48
|
+
"sha256": "9f9ebaeb47c9c18874ed832504422c0791551627c34092885cb481c6fe23ef19"
|
|
49
49
|
},
|
|
50
50
|
"files": [
|
|
51
51
|
{
|
|
@@ -603,9 +603,9 @@
|
|
|
603
603
|
{
|
|
604
604
|
"source": "package/dist/fs/refresh-file-lock.js",
|
|
605
605
|
"output": "fs/refresh-file-lock.js",
|
|
606
|
-
"bytes":
|
|
607
|
-
"sourceSha256": "
|
|
608
|
-
"outputSha256": "
|
|
606
|
+
"bytes": 37831,
|
|
607
|
+
"sourceSha256": "e0fdcc7a45548f3c88ea49bbe000f6e4022fb9c219f0510aa934492adb72a505",
|
|
608
|
+
"outputSha256": "e0fdcc7a45548f3c88ea49bbe000f6e4022fb9c219f0510aa934492adb72a505",
|
|
609
609
|
"transform": "verbatim"
|
|
610
610
|
},
|
|
611
611
|
{
|
|
@@ -619,9 +619,9 @@
|
|
|
619
619
|
{
|
|
620
620
|
"source": "package/dist/fs/with-lock.js",
|
|
621
621
|
"output": "fs/with-lock.js",
|
|
622
|
-
"bytes":
|
|
623
|
-
"sourceSha256": "
|
|
624
|
-
"outputSha256": "
|
|
622
|
+
"bytes": 3003,
|
|
623
|
+
"sourceSha256": "690fb43c6a0eb6a02eac024b8b58caa39775a37d0064118dab879a0e5ac8c996",
|
|
624
|
+
"outputSha256": "690fb43c6a0eb6a02eac024b8b58caa39775a37d0064118dab879a0e5ac8c996",
|
|
625
625
|
"transform": "verbatim"
|
|
626
626
|
},
|
|
627
627
|
{
|
|
@@ -763,17 +763,17 @@
|
|
|
763
763
|
{
|
|
764
764
|
"source": "package/dist/quota/format.d.ts",
|
|
765
765
|
"output": "quota/format.d.ts",
|
|
766
|
-
"bytes":
|
|
767
|
-
"sourceSha256": "
|
|
768
|
-
"outputSha256": "
|
|
766
|
+
"bytes": 5816,
|
|
767
|
+
"sourceSha256": "1865f4a06b8bd06b3dda73b59a7becc3eb2d13036134c1a34b8b6dce12678f21",
|
|
768
|
+
"outputSha256": "1865f4a06b8bd06b3dda73b59a7becc3eb2d13036134c1a34b8b6dce12678f21",
|
|
769
769
|
"transform": "verbatim"
|
|
770
770
|
},
|
|
771
771
|
{
|
|
772
772
|
"source": "package/dist/quota/format.js",
|
|
773
773
|
"output": "quota/format.js",
|
|
774
|
-
"bytes":
|
|
775
|
-
"sourceSha256": "
|
|
776
|
-
"outputSha256": "
|
|
774
|
+
"bytes": 18881,
|
|
775
|
+
"sourceSha256": "ffd69317391a225fb8e75550c22ea401480626cde762c52e61001955952ee013",
|
|
776
|
+
"outputSha256": "ffd69317391a225fb8e75550c22ea401480626cde762c52e61001955952ee013",
|
|
777
777
|
"transform": "verbatim"
|
|
778
778
|
},
|
|
779
779
|
{
|
package/package.json
CHANGED