@cortexkit/antigravity-auth-core 3.0.12 → 3.0.13
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/account-selector.d.ts +9 -1
- package/dist/account-selector.d.ts.map +1 -1
- package/dist/account-selector.js +23 -8
- package/dist/account-selector.js.map +1 -1
- package/dist/common-auth-embedded/claustrum/consumer.d.ts +77 -2
- package/dist/common-auth-embedded/claustrum/consumer.js +320 -35
- package/dist/common-auth-embedded/claustrum/custody.d.ts +36 -1
- package/dist/common-auth-embedded/claustrum/custody.js +95 -11
- package/dist/common-auth-embedded/claustrum/enrollment.js +37 -12
- package/dist/common-auth-embedded/claustrum/hub.d.ts +195 -0
- package/dist/common-auth-embedded/claustrum/hub.js +988 -0
- package/dist/common-auth-embedded/claustrum/index.d.ts +13 -3
- package/dist/common-auth-embedded/claustrum/index.js +37 -4
- package/dist/common-auth-embedded/claustrum/quota-writer.d.ts +8 -1
- package/dist/common-auth-embedded/claustrum/quota-writer.js +34 -12
- package/dist/common-auth-embedded/claustrum/roster.d.ts +49 -1
- package/dist/common-auth-embedded/claustrum/roster.js +187 -12
- package/dist/common-auth-embedded/claustrum/shutdown.js +42 -0
- package/dist/common-auth-embedded/fs/file-read-cache.js +57 -0
- package/dist/common-auth-embedded/fs/refresh-file-lock.d.ts +1 -1
- package/dist/common-auth-embedded/fs/refresh-file-lock.js +20 -11
- package/dist/common-auth-embedded/quota/commit-interval.d.ts +9 -0
- package/dist/common-auth-embedded/quota/commit-interval.js +18 -0
- package/dist/common-auth-embedded/source-output.json +115 -67
- package/dist/common-auth-embedded/store/mutate.d.ts +2 -0
- package/dist/common-auth-embedded/store/mutate.js +4 -0
- package/dist/common-auth-embedded/store/pool.d.ts +6 -1
- package/dist/common-auth-embedded/store/pool.js +1 -1
- package/dist/common-auth-embedded/store/quota-writer.js +27 -13
- package/dist/common-auth-embedded/store/settings.d.ts +1 -1
- package/dist/common-auth-embedded/store/settings.js +16 -6
- package/dist/model-registry.d.ts +2 -2
- package/dist/model-registry.d.ts.map +1 -1
- package/dist/model-registry.js +6 -4
- package/dist/model-registry.js.map +1 -1
- package/dist/quota-manager.d.ts +1 -1
- package/dist/quota-manager.d.ts.map +1 -1
- package/dist/quota-manager.js +12 -4
- package/dist/quota-manager.js.map +1 -1
- package/dist/quota-presentation.d.ts.map +1 -1
- package/dist/quota-presentation.js +8 -0
- package/dist/quota-presentation.js.map +1 -1
- package/dist/quota-types.d.ts +1 -1
- package/dist/quota-types.d.ts.map +1 -1
- package/dist/quota-types.js +5 -0
- package/dist/quota-types.js.map +1 -1
- package/dist/vault-account-source.d.ts +6 -1
- package/dist/vault-account-source.d.ts.map +1 -1
- package/dist/vault-account-source.js +9 -0
- package/dist/vault-account-source.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { lstat } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
async function identity(path) {
|
|
4
|
+
try {
|
|
5
|
+
const metadata = await lstat(path);
|
|
6
|
+
// Do not follow a symlink: its target can change without changing the link.
|
|
7
|
+
return metadata.isFile() ? metadata : undefined;
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
return error.code === 'ENOENT'
|
|
11
|
+
? 'absent'
|
|
12
|
+
: undefined;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function sameIdentity(left, right) {
|
|
16
|
+
if (left === 'absent' || right === 'absent')
|
|
17
|
+
return left === right;
|
|
18
|
+
return (left.dev === right.dev &&
|
|
19
|
+
left.ino === right.ino &&
|
|
20
|
+
left.size === right.size &&
|
|
21
|
+
left.mtimeMs === right.mtimeMs &&
|
|
22
|
+
left.ctimeMs === right.ctimeMs);
|
|
23
|
+
}
|
|
24
|
+
/** Process-local reads, capped at 64 path sets with one value per resolved set. */
|
|
25
|
+
export class FileReadCache {
|
|
26
|
+
#entries = new Map();
|
|
27
|
+
async read(paths, read, validateHit) {
|
|
28
|
+
const resolvedPaths = paths.map((path) => resolve(path));
|
|
29
|
+
const key = JSON.stringify(resolvedPaths);
|
|
30
|
+
const probed = await Promise.all(resolvedPaths.map(identity));
|
|
31
|
+
const identities = probed.every((entry) => entry !== undefined)
|
|
32
|
+
? probed
|
|
33
|
+
: undefined;
|
|
34
|
+
const cached = this.#entries.get(key);
|
|
35
|
+
if (identities &&
|
|
36
|
+
cached &&
|
|
37
|
+
identities.every((entry, index) => {
|
|
38
|
+
const previous = cached.identities[index];
|
|
39
|
+
return previous !== undefined && sameIdentity(entry, previous);
|
|
40
|
+
})) {
|
|
41
|
+
validateHit?.(identities);
|
|
42
|
+
return cached.value;
|
|
43
|
+
}
|
|
44
|
+
// A failed probe or read must not leave a previous successful value reusable.
|
|
45
|
+
this.#entries.delete(key);
|
|
46
|
+
const value = await read(resolvedPaths);
|
|
47
|
+
if (identities) {
|
|
48
|
+
if (this.#entries.size >= 64) {
|
|
49
|
+
const oldest = this.#entries.keys().next().value;
|
|
50
|
+
if (oldest !== undefined)
|
|
51
|
+
this.#entries.delete(oldest);
|
|
52
|
+
}
|
|
53
|
+
this.#entries.set(key, { identities, value });
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -28,7 +28,7 @@ type RefreshFileLockOptions = {
|
|
|
28
28
|
onContended?: () => void;
|
|
29
29
|
/** Synchronous, never awaited; throws and returned promise/thenable rejections are isolated. */
|
|
30
30
|
onRenewalTimer?: (event: 'scheduled' | 'cancelled') => void;
|
|
31
|
-
onStep?: (step: 'stale-marker-stat' | 'stale-marker-claimed' | 'stale-lock-observed' | 'lock-read-ready' | 'lock-missing' | 'stale-lock-confirmed' | 'stale-lock-removed' | 'stale-lock-recreated' | 'eviction-marker-acquired' | 'renewal-owner-confirmed' | 'renewal-marker-unavailable' | 'renewal-write-fenced' | 'renewal-write-ready' | 'renewal-write-finished' | 'relinquish-read' | 'renewal-finished' | 'release-owner-confirmed') => void | Promise<void>;
|
|
31
|
+
onStep?: (step: 'stale-marker-stat' | 'stale-marker-claimed' | 'stale-lock-observed' | 'lease-contention-read-ready' | 'lock-read-ready' | 'lock-missing' | 'stale-lock-confirmed' | 'stale-lock-removed' | 'stale-lock-recreated' | 'eviction-marker-acquired' | 'renewal-owner-confirmed' | 'renewal-marker-unavailable' | 'renewal-write-fenced' | 'renewal-write-ready' | 'renewal-write-finished' | 'relinquish-read' | 'renewal-finished' | 'release-owner-confirmed') => void | Promise<void>;
|
|
32
32
|
};
|
|
33
33
|
/** Filesystem leases share wall time across all callers and processes. */
|
|
34
34
|
export declare function acquireRefreshFileLock(options: RefreshFileLockOptions): Promise<RefreshFileLock | null>;
|
|
@@ -178,19 +178,28 @@ export async function acquireRefreshFileLockWithClock(options) {
|
|
|
178
178
|
}
|
|
179
179
|
async function leaseContention(error) {
|
|
180
180
|
const code = error.code;
|
|
181
|
-
if (code
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
181
|
+
if (code !== 'EEXIST' && code !== 'EISDIR')
|
|
182
|
+
return false;
|
|
183
|
+
if (windowsPrivateFiles) {
|
|
184
|
+
if (options.onStep)
|
|
185
|
+
await options.onStep('lease-contention-read-ready');
|
|
186
|
+
try {
|
|
187
|
+
if (code === 'EISDIR') {
|
|
188
|
+
await verifyPrivate(lockPath, 'directory', true);
|
|
189
|
+
await readPrivateText(legacyOwnerPath, true);
|
|
190
|
+
}
|
|
191
|
+
else
|
|
192
|
+
await readOwner();
|
|
193
|
+
}
|
|
194
|
+
catch (readError) {
|
|
195
|
+
// The holder can release after exclusive creation reports a collision.
|
|
196
|
+
// Only absence permits another acquisition attempt; security and sharing
|
|
197
|
+
// refusals must still escape rather than being treated as contention.
|
|
198
|
+
if (readError.code !== 'ENOENT')
|
|
199
|
+
throw readError;
|
|
190
200
|
}
|
|
191
|
-
return true;
|
|
192
201
|
}
|
|
193
|
-
return
|
|
202
|
+
return true;
|
|
194
203
|
}
|
|
195
204
|
async function tryAcquire() {
|
|
196
205
|
if (windowsPrivateFiles)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const QUOTA_COMMIT_INTERVAL_MS = 30000;
|
|
2
|
+
export interface QuotaCommitTimer {
|
|
3
|
+
now(): number;
|
|
4
|
+
schedule(delayMs: number, run: () => Promise<void>): {
|
|
5
|
+
cancel(): void;
|
|
6
|
+
unref?(): void;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export declare const quotaCommitTimer: QuotaCommitTimer;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Atomic quota commits create locks, markers and a renamed temp file. Keep
|
|
2
|
+
// those filesystem events at least 30 s apart under normal load; routing sees
|
|
3
|
+
// pending readings immediately, while other processes may lag by one interval.
|
|
4
|
+
// Shutdown drains and a full bounded pool queue can commit sooner.
|
|
5
|
+
// The vault shares one gate per resolved path; each pool handle has its own.
|
|
6
|
+
// N pool handles on one file can therefore make N normal commits per interval
|
|
7
|
+
// in one process. These gates do not coordinate with other processes.
|
|
8
|
+
export const QUOTA_COMMIT_INTERVAL_MS = 30_000;
|
|
9
|
+
export const quotaCommitTimer = {
|
|
10
|
+
now: () => performance.now(),
|
|
11
|
+
schedule(delayMs, run) {
|
|
12
|
+
const timer = setTimeout(() => void run(), delayMs);
|
|
13
|
+
return {
|
|
14
|
+
cancel: () => clearTimeout(timer),
|
|
15
|
+
unref: () => timer.unref?.(),
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": 1,
|
|
3
3
|
"package": "@cortexkit/common-auth",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.27.1",
|
|
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-
|
|
43
|
-
"canonicalFiles":
|
|
44
|
-
"canonicalBytes":
|
|
40
|
+
"input": "tools/common-auth-build/inputs/cortexkit-common-auth-0.27.1.tgz",
|
|
41
|
+
"tarballSha256": "a74507a1f746c9d591501ab24a630fe8bab20fb305c92738770902f003edb387",
|
|
42
|
+
"sri": "sha512-k5oKV38HxXKqwVi7qU8K9fD+P0ca7kXu52TlulHJoiGO0Q8Ebv0URtW1UXKLYawOm3ZwfVwFEBzAhuj8kMh6rg==",
|
|
43
|
+
"canonicalFiles": 147,
|
|
44
|
+
"canonicalBytes": 981509,
|
|
45
45
|
"generator": {
|
|
46
46
|
"path": "packages/opencode/scripts/embed-common-auth.ts",
|
|
47
47
|
"version": 3,
|
|
48
|
-
"sha256": "
|
|
48
|
+
"sha256": "79e2db6c01d1048f7a8b90a5105848710890e68ebb0ff096ec5623ec96eb1012"
|
|
49
49
|
},
|
|
50
50
|
"files": [
|
|
51
51
|
{
|
|
@@ -227,33 +227,33 @@
|
|
|
227
227
|
{
|
|
228
228
|
"source": "package/dist/claustrum/consumer.d.ts",
|
|
229
229
|
"output": "claustrum/consumer.d.ts",
|
|
230
|
-
"bytes":
|
|
231
|
-
"sourceSha256": "
|
|
232
|
-
"outputSha256": "
|
|
230
|
+
"bytes": 13309,
|
|
231
|
+
"sourceSha256": "a33f8fb2750424f1dd1e80ee6e0f260d4d5b6bdf6be3b00b2ae503bfbadb4d17",
|
|
232
|
+
"outputSha256": "a33f8fb2750424f1dd1e80ee6e0f260d4d5b6bdf6be3b00b2ae503bfbadb4d17",
|
|
233
233
|
"transform": "verbatim"
|
|
234
234
|
},
|
|
235
235
|
{
|
|
236
236
|
"source": "package/dist/claustrum/consumer.js",
|
|
237
237
|
"output": "claustrum/consumer.js",
|
|
238
|
-
"bytes":
|
|
239
|
-
"sourceSha256": "
|
|
240
|
-
"outputSha256": "
|
|
238
|
+
"bytes": 38516,
|
|
239
|
+
"sourceSha256": "46a8be88c8e5270d06bda0042235d7081dea06eaf1ae15f9a5fdf2ed93e478fd",
|
|
240
|
+
"outputSha256": "46a8be88c8e5270d06bda0042235d7081dea06eaf1ae15f9a5fdf2ed93e478fd",
|
|
241
241
|
"transform": "verbatim"
|
|
242
242
|
},
|
|
243
243
|
{
|
|
244
244
|
"source": "package/dist/claustrum/custody.d.ts",
|
|
245
245
|
"output": "claustrum/custody.d.ts",
|
|
246
|
-
"bytes":
|
|
247
|
-
"sourceSha256": "
|
|
248
|
-
"outputSha256": "
|
|
246
|
+
"bytes": 16192,
|
|
247
|
+
"sourceSha256": "ac8a3f2a47ec04ba0b6b5f69425db6672aa7660cd9249853f05fb2b4669698c2",
|
|
248
|
+
"outputSha256": "ac8a3f2a47ec04ba0b6b5f69425db6672aa7660cd9249853f05fb2b4669698c2",
|
|
249
249
|
"transform": "verbatim"
|
|
250
250
|
},
|
|
251
251
|
{
|
|
252
252
|
"source": "package/dist/claustrum/custody.js",
|
|
253
253
|
"output": "claustrum/custody.js",
|
|
254
|
-
"bytes":
|
|
255
|
-
"sourceSha256": "
|
|
256
|
-
"outputSha256": "
|
|
254
|
+
"bytes": 30242,
|
|
255
|
+
"sourceSha256": "cfa9c256d59ac4740f5b88fc1662a3bbb29078973cbeaf6225448c305fa580a2",
|
|
256
|
+
"outputSha256": "cfa9c256d59ac4740f5b88fc1662a3bbb29078973cbeaf6225448c305fa580a2",
|
|
257
257
|
"transform": "verbatim"
|
|
258
258
|
},
|
|
259
259
|
{
|
|
@@ -267,9 +267,9 @@
|
|
|
267
267
|
{
|
|
268
268
|
"source": "package/dist/claustrum/enrollment.js",
|
|
269
269
|
"output": "claustrum/enrollment.js",
|
|
270
|
-
"bytes":
|
|
271
|
-
"sourceSha256": "
|
|
272
|
-
"outputSha256": "
|
|
270
|
+
"bytes": 36501,
|
|
271
|
+
"sourceSha256": "0a6aa09a8927ae9ba11e4cc4fbe81cd8a3248d5f7db71e8592667bc870899078",
|
|
272
|
+
"outputSha256": "0a6aa09a8927ae9ba11e4cc4fbe81cd8a3248d5f7db71e8592667bc870899078",
|
|
273
273
|
"transform": "verbatim"
|
|
274
274
|
},
|
|
275
275
|
{
|
|
@@ -304,20 +304,36 @@
|
|
|
304
304
|
"outputSha256": "59bd24af8dbf5d923750b6e2fb15de2ce8a59aa59e11a6740527e50d5f7f93d6",
|
|
305
305
|
"transform": "verbatim"
|
|
306
306
|
},
|
|
307
|
+
{
|
|
308
|
+
"source": "package/dist/claustrum/hub.d.ts",
|
|
309
|
+
"output": "claustrum/hub.d.ts",
|
|
310
|
+
"bytes": 9169,
|
|
311
|
+
"sourceSha256": "07a5c385738649ec5c03b6afb7a916011e565c9f9d5463b280b9896024d8f0c0",
|
|
312
|
+
"outputSha256": "07a5c385738649ec5c03b6afb7a916011e565c9f9d5463b280b9896024d8f0c0",
|
|
313
|
+
"transform": "verbatim"
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"source": "package/dist/claustrum/hub.js",
|
|
317
|
+
"output": "claustrum/hub.js",
|
|
318
|
+
"bytes": 40718,
|
|
319
|
+
"sourceSha256": "50d57557ccd6e59989424e0df63df75570d97cdb5f71da37ce865d75f76297fd",
|
|
320
|
+
"outputSha256": "50d57557ccd6e59989424e0df63df75570d97cdb5f71da37ce865d75f76297fd",
|
|
321
|
+
"transform": "verbatim"
|
|
322
|
+
},
|
|
307
323
|
{
|
|
308
324
|
"source": "package/dist/claustrum/index.d.ts",
|
|
309
325
|
"output": "claustrum/index.d.ts",
|
|
310
|
-
"bytes":
|
|
311
|
-
"sourceSha256": "
|
|
312
|
-
"outputSha256": "
|
|
326
|
+
"bytes": 4728,
|
|
327
|
+
"sourceSha256": "524bec258d060b75e6aeefa1e39e102e9ad7370e6c74ba2c033fcc418a1db4d7",
|
|
328
|
+
"outputSha256": "524bec258d060b75e6aeefa1e39e102e9ad7370e6c74ba2c033fcc418a1db4d7",
|
|
313
329
|
"transform": "verbatim"
|
|
314
330
|
},
|
|
315
331
|
{
|
|
316
332
|
"source": "package/dist/claustrum/index.js",
|
|
317
333
|
"output": "claustrum/index.js",
|
|
318
|
-
"bytes":
|
|
319
|
-
"sourceSha256": "
|
|
320
|
-
"outputSha256": "
|
|
334
|
+
"bytes": 3938,
|
|
335
|
+
"sourceSha256": "9868c6c475ba9390118bd45c3b5dafe18a51c13cfe4e61700496e9096143a42b",
|
|
336
|
+
"outputSha256": "9868c6c475ba9390118bd45c3b5dafe18a51c13cfe4e61700496e9096143a42b",
|
|
321
337
|
"transform": "verbatim"
|
|
322
338
|
},
|
|
323
339
|
{
|
|
@@ -355,33 +371,41 @@
|
|
|
355
371
|
{
|
|
356
372
|
"source": "package/dist/claustrum/quota-writer.d.ts",
|
|
357
373
|
"output": "claustrum/quota-writer.d.ts",
|
|
358
|
-
"bytes":
|
|
359
|
-
"sourceSha256": "
|
|
360
|
-
"outputSha256": "
|
|
374
|
+
"bytes": 1483,
|
|
375
|
+
"sourceSha256": "c3cafec7057092a67d443667bee50b19333dcf3a8d14b63c9fbe4ac3989ba389",
|
|
376
|
+
"outputSha256": "c3cafec7057092a67d443667bee50b19333dcf3a8d14b63c9fbe4ac3989ba389",
|
|
361
377
|
"transform": "verbatim"
|
|
362
378
|
},
|
|
363
379
|
{
|
|
364
380
|
"source": "package/dist/claustrum/quota-writer.js",
|
|
365
381
|
"output": "claustrum/quota-writer.js",
|
|
366
|
-
"bytes":
|
|
367
|
-
"sourceSha256": "
|
|
368
|
-
"outputSha256": "
|
|
382
|
+
"bytes": 8527,
|
|
383
|
+
"sourceSha256": "5375e7d8a300e73f4398d610090834095fd22ba4b3830f3c62d142a67dcbe9fd",
|
|
384
|
+
"outputSha256": "5375e7d8a300e73f4398d610090834095fd22ba4b3830f3c62d142a67dcbe9fd",
|
|
369
385
|
"transform": "verbatim"
|
|
370
386
|
},
|
|
371
387
|
{
|
|
372
388
|
"source": "package/dist/claustrum/roster.d.ts",
|
|
373
389
|
"output": "claustrum/roster.d.ts",
|
|
374
|
-
"bytes":
|
|
375
|
-
"sourceSha256": "
|
|
376
|
-
"outputSha256": "
|
|
390
|
+
"bytes": 15102,
|
|
391
|
+
"sourceSha256": "30fc3b4d572e43a08a700ff169ebcb52206d1200f7ca678d2bff0a3369aaa005",
|
|
392
|
+
"outputSha256": "30fc3b4d572e43a08a700ff169ebcb52206d1200f7ca678d2bff0a3369aaa005",
|
|
377
393
|
"transform": "verbatim"
|
|
378
394
|
},
|
|
379
395
|
{
|
|
380
396
|
"source": "package/dist/claustrum/roster.js",
|
|
381
397
|
"output": "claustrum/roster.js",
|
|
382
|
-
"bytes":
|
|
383
|
-
"sourceSha256": "
|
|
384
|
-
"outputSha256": "
|
|
398
|
+
"bytes": 39326,
|
|
399
|
+
"sourceSha256": "f46fc75edcf4e418f02a5699c7395f1f44abd2e28b77067b89f7622af5890214",
|
|
400
|
+
"outputSha256": "f46fc75edcf4e418f02a5699c7395f1f44abd2e28b77067b89f7622af5890214",
|
|
401
|
+
"transform": "verbatim"
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
"source": "package/dist/claustrum/shutdown.js",
|
|
405
|
+
"output": "claustrum/shutdown.js",
|
|
406
|
+
"bytes": 1270,
|
|
407
|
+
"sourceSha256": "6ccb19ab5e9bb84a978cb47a32b443abe432b4edfe69a318e45bb404ef75c45e",
|
|
408
|
+
"outputSha256": "6ccb19ab5e9bb84a978cb47a32b443abe432b4edfe69a318e45bb404ef75c45e",
|
|
385
409
|
"transform": "verbatim"
|
|
386
410
|
},
|
|
387
411
|
{
|
|
@@ -512,6 +536,14 @@
|
|
|
512
536
|
"outputSha256": "80779a8078e673ef68deaa7fdee3a0e1322078521a1f4156c0a595814c374044",
|
|
513
537
|
"transform": "verbatim"
|
|
514
538
|
},
|
|
539
|
+
{
|
|
540
|
+
"source": "package/dist/fs/file-read-cache.js",
|
|
541
|
+
"output": "fs/file-read-cache.js",
|
|
542
|
+
"bytes": 2121,
|
|
543
|
+
"sourceSha256": "484d18996d76c44125c880347b3d3dcd10bb352743acf44c588d0b38e8e0f1a7",
|
|
544
|
+
"outputSha256": "484d18996d76c44125c880347b3d3dcd10bb352743acf44c588d0b38e8e0f1a7",
|
|
545
|
+
"transform": "verbatim"
|
|
546
|
+
},
|
|
515
547
|
{
|
|
516
548
|
"source": "package/dist/fs/index.d.ts",
|
|
517
549
|
"output": "fs/index.d.ts",
|
|
@@ -563,17 +595,17 @@
|
|
|
563
595
|
{
|
|
564
596
|
"source": "package/dist/fs/refresh-file-lock.d.ts",
|
|
565
597
|
"output": "fs/refresh-file-lock.d.ts",
|
|
566
|
-
"bytes":
|
|
567
|
-
"sourceSha256": "
|
|
568
|
-
"outputSha256": "
|
|
598
|
+
"bytes": 2157,
|
|
599
|
+
"sourceSha256": "cbce15eb313d425501780dd4be657cbbaa7e41064bab4ae64fea91fbd54918e9",
|
|
600
|
+
"outputSha256": "cbce15eb313d425501780dd4be657cbbaa7e41064bab4ae64fea91fbd54918e9",
|
|
569
601
|
"transform": "verbatim"
|
|
570
602
|
},
|
|
571
603
|
{
|
|
572
604
|
"source": "package/dist/fs/refresh-file-lock.js",
|
|
573
605
|
"output": "fs/refresh-file-lock.js",
|
|
574
|
-
"bytes":
|
|
575
|
-
"sourceSha256": "
|
|
576
|
-
"outputSha256": "
|
|
606
|
+
"bytes": 30222,
|
|
607
|
+
"sourceSha256": "314dadbe39b9f0664b6f2f6abff674197c8d86f61ba657e2031d5a8b08ec1030",
|
|
608
|
+
"outputSha256": "314dadbe39b9f0664b6f2f6abff674197c8d86f61ba657e2031d5a8b08ec1030",
|
|
577
609
|
"transform": "verbatim"
|
|
578
610
|
},
|
|
579
611
|
{
|
|
@@ -712,6 +744,22 @@
|
|
|
712
744
|
"outputSha256": "4e496ce03a8a23536b467168f1dc6a7ceffb06d00ae80cb8a8868f311b2f3a8a",
|
|
713
745
|
"transform": "verbatim"
|
|
714
746
|
},
|
|
747
|
+
{
|
|
748
|
+
"source": "package/dist/quota/commit-interval.d.ts",
|
|
749
|
+
"output": "quota/commit-interval.d.ts",
|
|
750
|
+
"bytes": 283,
|
|
751
|
+
"sourceSha256": "8b1d8b541a382d1ce366d65d9845e9d3848445cf075751b68ad963fb660ee04a",
|
|
752
|
+
"outputSha256": "8b1d8b541a382d1ce366d65d9845e9d3848445cf075751b68ad963fb660ee04a",
|
|
753
|
+
"transform": "verbatim"
|
|
754
|
+
},
|
|
755
|
+
{
|
|
756
|
+
"source": "package/dist/quota/commit-interval.js",
|
|
757
|
+
"output": "quota/commit-interval.js",
|
|
758
|
+
"bytes": 864,
|
|
759
|
+
"sourceSha256": "3281afb6df69d83a7c5898e1163287f34104068ddd4085b7460c4bb392967491",
|
|
760
|
+
"outputSha256": "3281afb6df69d83a7c5898e1163287f34104068ddd4085b7460c4bb392967491",
|
|
761
|
+
"transform": "verbatim"
|
|
762
|
+
},
|
|
715
763
|
{
|
|
716
764
|
"source": "package/dist/quota/format.d.ts",
|
|
717
765
|
"output": "quota/format.d.ts",
|
|
@@ -963,33 +1011,33 @@
|
|
|
963
1011
|
{
|
|
964
1012
|
"source": "package/dist/store/mutate.d.ts",
|
|
965
1013
|
"output": "store/mutate.d.ts",
|
|
966
|
-
"bytes":
|
|
967
|
-
"sourceSha256": "
|
|
968
|
-
"outputSha256": "
|
|
1014
|
+
"bytes": 9196,
|
|
1015
|
+
"sourceSha256": "4a46be98d9eb24a690e95f26b69bd3c461d5f225170bd31fcb89147c7baac41c",
|
|
1016
|
+
"outputSha256": "4a46be98d9eb24a690e95f26b69bd3c461d5f225170bd31fcb89147c7baac41c",
|
|
969
1017
|
"transform": "verbatim"
|
|
970
1018
|
},
|
|
971
1019
|
{
|
|
972
1020
|
"source": "package/dist/store/mutate.js",
|
|
973
1021
|
"output": "store/mutate.js",
|
|
974
|
-
"bytes":
|
|
975
|
-
"sourceSha256": "
|
|
976
|
-
"outputSha256": "
|
|
1022
|
+
"bytes": 20171,
|
|
1023
|
+
"sourceSha256": "d61d08f2caed6d7a803ca4c67511e5133d28f21a90a7417f76e23b49ed00591d",
|
|
1024
|
+
"outputSha256": "d61d08f2caed6d7a803ca4c67511e5133d28f21a90a7417f76e23b49ed00591d",
|
|
977
1025
|
"transform": "verbatim"
|
|
978
1026
|
},
|
|
979
1027
|
{
|
|
980
1028
|
"source": "package/dist/store/pool.d.ts",
|
|
981
1029
|
"output": "store/pool.d.ts",
|
|
982
|
-
"bytes":
|
|
983
|
-
"sourceSha256": "
|
|
984
|
-
"outputSha256": "
|
|
1030
|
+
"bytes": 12144,
|
|
1031
|
+
"sourceSha256": "64d6e7dd5600f436422e6d309a22b7f874a6afdd866873226ab1f4d5091ebc43",
|
|
1032
|
+
"outputSha256": "64d6e7dd5600f436422e6d309a22b7f874a6afdd866873226ab1f4d5091ebc43",
|
|
985
1033
|
"transform": "verbatim"
|
|
986
1034
|
},
|
|
987
1035
|
{
|
|
988
1036
|
"source": "package/dist/store/pool.js",
|
|
989
1037
|
"output": "store/pool.js",
|
|
990
|
-
"bytes":
|
|
991
|
-
"sourceSha256": "
|
|
992
|
-
"outputSha256": "
|
|
1038
|
+
"bytes": 6358,
|
|
1039
|
+
"sourceSha256": "1503b5c0f461678f9710a5fe22e345092de70e537a114e57b0cb651795928031",
|
|
1040
|
+
"outputSha256": "1503b5c0f461678f9710a5fe22e345092de70e537a114e57b0cb651795928031",
|
|
993
1041
|
"transform": "verbatim"
|
|
994
1042
|
},
|
|
995
1043
|
{
|
|
@@ -1043,9 +1091,9 @@
|
|
|
1043
1091
|
{
|
|
1044
1092
|
"source": "package/dist/store/quota-writer.js",
|
|
1045
1093
|
"output": "store/quota-writer.js",
|
|
1046
|
-
"bytes":
|
|
1047
|
-
"sourceSha256": "
|
|
1048
|
-
"outputSha256": "
|
|
1094
|
+
"bytes": 12960,
|
|
1095
|
+
"sourceSha256": "7816549913b030045e5f7848dd57ca11841a3aa6051c30c96a7d09f82341700e",
|
|
1096
|
+
"outputSha256": "7816549913b030045e5f7848dd57ca11841a3aa6051c30c96a7d09f82341700e",
|
|
1049
1097
|
"transform": "verbatim"
|
|
1050
1098
|
},
|
|
1051
1099
|
{
|
|
@@ -1139,17 +1187,17 @@
|
|
|
1139
1187
|
{
|
|
1140
1188
|
"source": "package/dist/store/settings.d.ts",
|
|
1141
1189
|
"output": "store/settings.d.ts",
|
|
1142
|
-
"bytes":
|
|
1143
|
-
"sourceSha256": "
|
|
1144
|
-
"outputSha256": "
|
|
1190
|
+
"bytes": 2994,
|
|
1191
|
+
"sourceSha256": "32446dea1f8431e3fb7e38940d1dec7259dbd5c794b4117efe3875be92405fef",
|
|
1192
|
+
"outputSha256": "32446dea1f8431e3fb7e38940d1dec7259dbd5c794b4117efe3875be92405fef",
|
|
1145
1193
|
"transform": "verbatim"
|
|
1146
1194
|
},
|
|
1147
1195
|
{
|
|
1148
1196
|
"source": "package/dist/store/settings.js",
|
|
1149
1197
|
"output": "store/settings.js",
|
|
1150
|
-
"bytes":
|
|
1151
|
-
"sourceSha256": "
|
|
1152
|
-
"outputSha256": "
|
|
1198
|
+
"bytes": 5766,
|
|
1199
|
+
"sourceSha256": "5ed4e0458800923b843b9b8f0671cca0c04cb26e428453e3bcc8b6d06b51470f",
|
|
1200
|
+
"outputSha256": "5ed4e0458800923b843b9b8f0671cca0c04cb26e428453e3bcc8b6d06b51470f",
|
|
1153
1201
|
"transform": "verbatim"
|
|
1154
1202
|
},
|
|
1155
1203
|
{
|
|
@@ -52,6 +52,8 @@ export type ReadResult = ({
|
|
|
52
52
|
kind?: 'snapshot-contended';
|
|
53
53
|
retryable?: true;
|
|
54
54
|
};
|
|
55
|
+
/** Settings need only the config classification, not a joined roster snapshot. */
|
|
56
|
+
export declare function readPoolConfig(path: string): Promise<import("./schema.js").ConfigClassification>;
|
|
55
57
|
/**
|
|
56
58
|
* Validate config/state/config bytes without locks. Roster replacement writes
|
|
57
59
|
* config before deleting old state credentials. Re-read a changed config so an
|
|
@@ -28,6 +28,10 @@ function parseFile(text) {
|
|
|
28
28
|
return { exists: true, parseError };
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
+
/** Settings need only the config classification, not a joined roster snapshot. */
|
|
32
|
+
export async function readPoolConfig(path) {
|
|
33
|
+
return classifyConfig(parseFile(await readText(path)));
|
|
34
|
+
}
|
|
31
35
|
/**
|
|
32
36
|
* Validate config/state/config bytes without locks. Roster replacement writes
|
|
33
37
|
* config before deleting old state credentials. Re-read a changed config so an
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { QuotaCommitTimer } from '../quota/commit-interval.js';
|
|
1
2
|
import { type Attribution } from './attribution.js';
|
|
2
3
|
import type { PoolOperationError } from './errors.js';
|
|
3
4
|
import type { PoolLogger } from './hooks.js';
|
|
@@ -24,11 +25,15 @@ export interface OpenPoolStoreOptions {
|
|
|
24
25
|
* older reading replaces. Accepted readings appear in read/load
|
|
25
26
|
* immediately, merged the same way; the returned promise still rejects
|
|
26
27
|
* current-row refusals before queueing. Await dispose or close at shutdown
|
|
27
|
-
* to drain
|
|
28
|
+
* to attempt a bounded drain; readings still pending at its timeout are
|
|
29
|
+
* discarded. Normal quota commits are at least 30 seconds apart; a full
|
|
30
|
+
* queue commits early so response handling never waits for that interval.
|
|
28
31
|
*/
|
|
29
32
|
coalesceQuota?: boolean;
|
|
30
33
|
/** Bounded quota drain on close/dispose, in milliseconds; defaults to 1,000. */
|
|
31
34
|
quotaDrainTimeoutMs?: number;
|
|
35
|
+
/** Monotonic clock and scheduling seam for detached quota commits. */
|
|
36
|
+
quotaCommitTimer?: QuotaCommitTimer;
|
|
32
37
|
/**
|
|
33
38
|
* The codec of the provider state kept beside each row's credential (see
|
|
34
39
|
* `ProviderStateCodec`). Without it no row shows a provider state, and
|
|
@@ -82,7 +82,7 @@ export function openPoolStore(options) {
|
|
|
82
82
|
firePull: (id, reason) => pulls.fire(id, reason),
|
|
83
83
|
};
|
|
84
84
|
const quotaWriter = options.coalesceQuota
|
|
85
|
-
? new PoolQuotaWriter(rt, options.quotaDrainTimeoutMs)
|
|
85
|
+
? new PoolQuotaWriter(rt, options.quotaDrainTimeoutMs, options.quotaCommitTimer)
|
|
86
86
|
: undefined;
|
|
87
87
|
const record = (id, attribution, observation) => quotaWriter
|
|
88
88
|
? quotaWriter.record(id, attribution, observation)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createLogger } from '../logger/index.js';
|
|
2
|
+
import { QUOTA_COMMIT_INTERVAL_MS, quotaCommitTimer, } from '../quota/commit-interval.js';
|
|
2
3
|
import { assertQuotaEpoch, assertQuotaRow, mergedQuota, } from './attribution.js';
|
|
3
4
|
import { PoolOperationError } from './errors.js';
|
|
4
5
|
import { toFailure, withTransaction } from './mutate.js';
|
|
@@ -24,19 +25,22 @@ export const POOL_QUOTA_QUEUE_LIMIT = 128;
|
|
|
24
25
|
export class PoolQuotaWriter {
|
|
25
26
|
rt;
|
|
26
27
|
timeoutMs;
|
|
28
|
+
clock;
|
|
27
29
|
pending = new Map();
|
|
28
30
|
warned = new Set();
|
|
29
31
|
wake = new Set();
|
|
30
32
|
logger;
|
|
31
33
|
timer;
|
|
34
|
+
committedAt;
|
|
32
35
|
running;
|
|
33
36
|
closing;
|
|
34
37
|
closed = false;
|
|
35
38
|
stopped = false;
|
|
36
39
|
failures = 0;
|
|
37
|
-
constructor(rt, timeoutMs = 1_000) {
|
|
40
|
+
constructor(rt, timeoutMs = 1_000, clock = quotaCommitTimer) {
|
|
38
41
|
this.rt = rt;
|
|
39
42
|
this.timeoutMs = timeoutMs;
|
|
43
|
+
this.clock = clock;
|
|
40
44
|
this.logger = rt.ctx.logger ?? createLogger('store');
|
|
41
45
|
}
|
|
42
46
|
async record(id, attribution, observation) {
|
|
@@ -126,25 +130,33 @@ export class PoolQuotaWriter {
|
|
|
126
130
|
schedule(delay) {
|
|
127
131
|
if (this.running || this.timer || !this.pending.size || this.stopped)
|
|
128
132
|
return;
|
|
129
|
-
|
|
133
|
+
const remaining = this.closed
|
|
134
|
+
? 0
|
|
135
|
+
: (this.committedAt ?? -Infinity) +
|
|
136
|
+
QUOTA_COMMIT_INTERVAL_MS -
|
|
137
|
+
this.clock.now();
|
|
138
|
+
this.timer = this.clock.schedule(Math.max(delay, remaining), () => {
|
|
130
139
|
this.timer = undefined;
|
|
131
|
-
this.flush();
|
|
132
|
-
}
|
|
140
|
+
return this.flush();
|
|
141
|
+
});
|
|
133
142
|
if (!this.closed)
|
|
134
143
|
this.timer.unref?.();
|
|
135
144
|
}
|
|
136
|
-
|
|
137
|
-
|
|
145
|
+
cancelTimer() {
|
|
146
|
+
this.timer?.cancel();
|
|
147
|
+
this.timer = undefined;
|
|
148
|
+
}
|
|
149
|
+
// A full queue overrides the interval: response handling must not wait for
|
|
150
|
+
// a quota commit slot. A flush already running is left to finish.
|
|
138
151
|
flushNow() {
|
|
139
152
|
if (this.running)
|
|
140
153
|
return;
|
|
141
|
-
|
|
142
|
-
this.timer = undefined;
|
|
154
|
+
this.cancelTimer();
|
|
143
155
|
this.flush();
|
|
144
156
|
}
|
|
145
157
|
flush() {
|
|
146
158
|
if (this.running || this.stopped || !this.pending.size)
|
|
147
|
-
return;
|
|
159
|
+
return this.running ?? Promise.resolve();
|
|
148
160
|
// Every queued reading, each row's in arrival order.
|
|
149
161
|
const batch = [...this.pending.values()].flat();
|
|
150
162
|
// Short lock attempts allow retries to pick up freshly queued readings and
|
|
@@ -208,8 +220,10 @@ export class PoolQuotaWriter {
|
|
|
208
220
|
tx.setEntry(id, { ...entry, quota, needsFirstReading: false });
|
|
209
221
|
changed = true;
|
|
210
222
|
}
|
|
211
|
-
if (changed && !this.stopped)
|
|
223
|
+
if (changed && !this.stopped) {
|
|
212
224
|
await tx.commitConfig();
|
|
225
|
+
this.committedAt = this.clock.now();
|
|
226
|
+
}
|
|
213
227
|
}, { completeTorn: false });
|
|
214
228
|
const flushed = new Set(batch);
|
|
215
229
|
for (const [id, queue] of this.pending) {
|
|
@@ -240,6 +254,7 @@ export class PoolQuotaWriter {
|
|
|
240
254
|
this.schedule(delay);
|
|
241
255
|
}
|
|
242
256
|
})();
|
|
257
|
+
return this.running;
|
|
243
258
|
}
|
|
244
259
|
warn(message, data) {
|
|
245
260
|
try {
|
|
@@ -257,8 +272,7 @@ export class PoolQuotaWriter {
|
|
|
257
272
|
return this.closing;
|
|
258
273
|
}
|
|
259
274
|
async drain() {
|
|
260
|
-
|
|
261
|
-
this.timer = undefined;
|
|
275
|
+
this.cancelTimer();
|
|
262
276
|
let deadline;
|
|
263
277
|
let wake;
|
|
264
278
|
const drained = new Promise((done) => {
|
|
@@ -281,7 +295,7 @@ export class PoolQuotaWriter {
|
|
|
281
295
|
finally {
|
|
282
296
|
this.stopped = true;
|
|
283
297
|
clearTimeout(deadline);
|
|
284
|
-
|
|
298
|
+
this.cancelTimer();
|
|
285
299
|
this.wake.delete(wake);
|
|
286
300
|
if (this.pending.size)
|
|
287
301
|
this.warn('pool quota drain timed out; pending readings left', {
|
|
@@ -50,7 +50,7 @@ export type UpdateSettingsResult = {
|
|
|
50
50
|
/** `unchanged` when the mutator left the settings as they were; nothing was written. */
|
|
51
51
|
outcome: 'updated' | 'unchanged';
|
|
52
52
|
};
|
|
53
|
-
/** Reads the settings without taking a lock or writing anything. */
|
|
53
|
+
/** Reads only the config's settings, without taking a lock or writing anything. */
|
|
54
54
|
export declare function readPoolSettings(rt: StoreRuntime): Promise<SettingsRead>;
|
|
55
55
|
/**
|
|
56
56
|
* One locked read-modify-write of the plugin's settings in the config file
|