@cortexkit/antigravity-auth-core 3.0.28 → 3.0.30
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.map +1 -1
- package/dist/account-selector.js +26 -3
- package/dist/account-selector.js.map +1 -1
- package/dist/common-auth-embedded/claustrum/consumer.d.ts +12 -0
- package/dist/common-auth-embedded/claustrum/consumer.js +36 -0
- package/dist/common-auth-embedded/claustrum/custody.d.ts +16 -4
- package/dist/common-auth-embedded/claustrum/custody.js +74 -9
- package/dist/common-auth-embedded/claustrum/hub.d.ts +3 -2
- package/dist/common-auth-embedded/claustrum/hub.js +8 -0
- package/dist/common-auth-embedded/claustrum/index.d.ts +1 -0
- package/dist/common-auth-embedded/claustrum/roster.d.ts +2 -0
- package/dist/common-auth-embedded/claustrum/roster.js +2 -0
- package/dist/common-auth-embedded/claustrum/usage.d.ts +41 -0
- package/dist/common-auth-embedded/claustrum/usage.js +145 -0
- package/dist/common-auth-embedded/commands/builtins.d.ts +5 -0
- package/dist/common-auth-embedded/commands/builtins.js +38 -0
- package/dist/common-auth-embedded/fs/private-files.d.ts +5 -0
- package/dist/common-auth-embedded/fs/private-files.js +7 -0
- package/dist/common-auth-embedded/fs/refresh-file-lock.js +142 -47
- package/dist/common-auth-embedded/fs/with-lock.js +2 -5
- package/dist/common-auth-embedded/routing/admission.d.ts +7 -2
- package/dist/common-auth-embedded/routing/admission.js +17 -7
- package/dist/common-auth-embedded/source-output.json +126 -94
- package/dist/common-auth-embedded/store/attribution.js +3 -2
- package/dist/common-auth-embedded/store/errors.d.ts +1 -1
- package/dist/common-auth-embedded/store/hooks.d.ts +5 -1
- package/dist/common-auth-embedded/store/hooks.js +20 -5
- package/dist/common-auth-embedded/store/index.d.ts +1 -0
- package/dist/common-auth-embedded/store/limits-namespace.d.ts +7 -0
- package/dist/common-auth-embedded/store/limits-namespace.js +34 -0
- package/dist/common-auth-embedded/store/pool.d.ts +10 -1
- package/dist/common-auth-embedded/store/pool.js +2 -0
- package/dist/common-auth-embedded/store/provider-state.js +5 -5
- package/dist/common-auth-embedded/store/refresh.js +1 -1
- package/dist/common-auth-embedded/store/schema.js +9 -4
- package/dist/common-auth-embedded/store/settings.d.ts +2 -0
- package/dist/common-auth-embedded/store/settings.js +11 -4
- package/package.json +1 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { writeJsonAtomic } from '../fs/atomic-write.js';
|
|
2
|
+
import { assertLimitsWriteAllowed, runInsideHook } from './hooks.js';
|
|
3
|
+
import { notReadyError, readPool, runOperation } from './mutate.js';
|
|
4
|
+
/** A namespace merge and its check of current row bindings share one locked config snapshot. */
|
|
5
|
+
export async function updatePoolLimitsNamespace(rt, mutator) {
|
|
6
|
+
assertLimitsWriteAllowed();
|
|
7
|
+
const { ctx } = rt;
|
|
8
|
+
await runOperation(ctx, 'updateLimitsNamespace', undefined, undefined, async (locks, progress) => {
|
|
9
|
+
for (const spec of ctx.storeLocks)
|
|
10
|
+
await locks.acquire(spec);
|
|
11
|
+
const result = await readPool(ctx);
|
|
12
|
+
if (result.status !== 'ready')
|
|
13
|
+
throw notReadyError(result, 'updateLimitsNamespace', undefined);
|
|
14
|
+
const rows = result.rows.map(({ id, credentialEpoch, identity }) => ({
|
|
15
|
+
id,
|
|
16
|
+
credentialEpoch,
|
|
17
|
+
identity,
|
|
18
|
+
}));
|
|
19
|
+
const envelope = await runInsideHook('updateLimitsNamespace', () => mutator(structuredClone(result.config.commonAuthLimits), rows));
|
|
20
|
+
const config = { ...result.config, commonAuthLimits: envelope };
|
|
21
|
+
const info = {
|
|
22
|
+
operation: 'updateLimitsNamespace',
|
|
23
|
+
rowId: undefined,
|
|
24
|
+
};
|
|
25
|
+
await writeJsonAtomic(ctx.configPath, config, {
|
|
26
|
+
beforeRename: async () => {
|
|
27
|
+
await ctx.onStep?.('before-config-write', info);
|
|
28
|
+
await locks.assertAll();
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
progress.writes++;
|
|
32
|
+
await ctx.onStep?.('after-config-write', info);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { QuotaCommitTimer } from '../quota/commit-interval.js';
|
|
|
2
2
|
import { type Attribution } from './attribution.js';
|
|
3
3
|
import type { PoolOperationError } from './errors.js';
|
|
4
4
|
import type { PoolLogger } from './hooks.js';
|
|
5
|
+
import { type PoolLimitsMutator } from './limits-namespace.js';
|
|
5
6
|
import { type HoldPoint, type InitializeOutcome, type StoreContext } from './mutate.js';
|
|
6
7
|
import { type ProviderStateMutator, type UpdateProviderStateResult } from './provider-state.js';
|
|
7
8
|
import { type PublicationReceipt, type PublishOptions, type PublishPlan, type PublishResult } from './publication.js';
|
|
@@ -191,9 +192,17 @@ export interface PoolStore {
|
|
|
191
192
|
/**
|
|
192
193
|
* One locked write of the plugin's settings (since 0.2.6) beside the pool,
|
|
193
194
|
* in the config file. Refuses a result that sets a pool-owned key
|
|
194
|
-
* (`invalid-input`).
|
|
195
|
+
* (`invalid-input`). Carries commonAuthLimits through unchanged and refuses
|
|
196
|
+
* an explicit alteration to it. Takes `extraLocks`, then the store locks.
|
|
195
197
|
*/
|
|
196
198
|
updateSettings(mutator: SettingsMutator, options?: UpdateSettingsOptions): Promise<UpdateSettingsResult>;
|
|
199
|
+
/**
|
|
200
|
+
* Merges commonAuthLimits with current row bindings in one config write.
|
|
201
|
+
* Requires a ready pool and takes only the store locks. May run in an
|
|
202
|
+
* onPersisted/onFailure hook or a pull, but not in a lock-held mutator.
|
|
203
|
+
* Optional so existing structural implementations remain compatible.
|
|
204
|
+
*/
|
|
205
|
+
updateLimitsNamespace?(mutator: PoolLimitsMutator): Promise<void>;
|
|
197
206
|
/**
|
|
198
207
|
* Records the identity a lookup found for the row's credential. Since
|
|
199
208
|
* 0.3.1 it takes the credential epoch the lookup was issued for, and
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { recordQuota } from './attribution.js';
|
|
2
|
+
import { updatePoolLimitsNamespace, } from './limits-namespace.js';
|
|
2
3
|
import { initializePool, readPool, } from './mutate.js';
|
|
3
4
|
import { updateProviderStateRow, } from './provider-state.js';
|
|
4
5
|
import { publication, publishRoster, } from './publication.js';
|
|
@@ -126,6 +127,7 @@ export function openPoolStore(options) {
|
|
|
126
127
|
reorder: (ids, callOptions) => reorderRows(rt, ids, callOptions),
|
|
127
128
|
readSettings: () => readPoolSettings(rt),
|
|
128
129
|
updateSettings: (mutator, callOptions) => updatePoolSettings(rt, mutator, callOptions),
|
|
130
|
+
updateLimitsNamespace: (mutator) => updatePoolLimitsNamespace(rt, mutator),
|
|
129
131
|
recordIdentity: (id, identity, attribution, callOptions) => recordRowIdentity(rt, id, identity, attribution, callOptions),
|
|
130
132
|
refresh: (id, provider, callOptions) => refreshRow(rt, id, provider, callOptions),
|
|
131
133
|
recordQuota: record,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assertNotInsideHook, runInsideHook } from './hooks.js';
|
|
1
|
+
import { assertNotInsideHook, runInsideCodec, runInsideHook } from './hooks.js';
|
|
2
2
|
import { runOperation, withTransaction } from './mutate.js';
|
|
3
3
|
import { readRow, refusal, requireBound, rowLockSpec, unknownRow, } from './runtime.js';
|
|
4
4
|
import { boundProviderStateDigest, CREDENTIAL_STAMP_KEY, credentialDigest, isCredentialEpoch, isRecord, PROVIDER_STATE_KEY, parseStamp, providerStateDigest, rowLockKey, } from './schema.js';
|
|
@@ -21,7 +21,7 @@ export function acceptProviderState(codec, operation, id, value, what = 'the pro
|
|
|
21
21
|
}
|
|
22
22
|
if (normalized === undefined)
|
|
23
23
|
throw refusal(operation, id, 'invalid-provider-state', `${what} cannot be stored as JSON`);
|
|
24
|
-
if (!codec.validate(normalized))
|
|
24
|
+
if (!runInsideCodec(() => codec.validate(normalized)))
|
|
25
25
|
throw refusal(operation, id, 'invalid-provider-state', `the provider-state codec rejected ${what}`);
|
|
26
26
|
return normalized;
|
|
27
27
|
}
|
|
@@ -35,7 +35,7 @@ export function mergedProviderState(codec, operation, id, onDisk, incoming) {
|
|
|
35
35
|
return { kind: 'set', value: incoming };
|
|
36
36
|
return {
|
|
37
37
|
kind: 'set',
|
|
38
|
-
value: acceptProviderState(codec, operation, id, codec.merge(structuredClone(onDisk), structuredClone(incoming)), 'the merged provider state'),
|
|
38
|
+
value: acceptProviderState(codec, operation, id, runInsideCodec(() => codec.merge?.(structuredClone(onDisk), structuredClone(incoming))), 'the merged provider state'),
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
@@ -48,7 +48,7 @@ export function mergedProviderState(codec, operation, id, onDisk, incoming) {
|
|
|
48
48
|
export function replacementProviderState(codec, row, credentialEpoch, identity, incoming) {
|
|
49
49
|
const hook = codec?.onReplace;
|
|
50
50
|
const next = hook
|
|
51
|
-
? hook(row.providerState === undefined
|
|
51
|
+
? runInsideCodec(() => hook(row.providerState === undefined
|
|
52
52
|
? undefined
|
|
53
53
|
: structuredClone(row.providerState), {
|
|
54
54
|
id: row.id,
|
|
@@ -60,7 +60,7 @@ export function replacementProviderState(codec, row, credentialEpoch, identity,
|
|
|
60
60
|
...(incoming !== undefined
|
|
61
61
|
? { incoming: structuredClone(incoming) }
|
|
62
62
|
: {}),
|
|
63
|
-
})
|
|
63
|
+
}))
|
|
64
64
|
: incoming;
|
|
65
65
|
if (next === undefined)
|
|
66
66
|
return { kind: 'clear' };
|
|
@@ -200,7 +200,7 @@ export async function refreshRow(rt, id, provider, options = {}) {
|
|
|
200
200
|
if (options.onPersisted) {
|
|
201
201
|
try {
|
|
202
202
|
const persisted = options.onPersisted;
|
|
203
|
-
await runInsideHook('refresh', () => persisted(id, commit.stored));
|
|
203
|
+
await runInsideHook('refresh', () => persisted(id, commit.stored), true);
|
|
204
204
|
}
|
|
205
205
|
catch (cause) {
|
|
206
206
|
throw new PoolOperationError({
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
+
import { runInsideCodec } from './hooks.js';
|
|
2
3
|
/** Top-level key of the config file that holds everything the pool adds. */
|
|
3
4
|
export const POOL_KEY = 'commonAuthPool';
|
|
4
5
|
/** The pool schema this library reads and writes. */
|
|
@@ -182,7 +183,9 @@ export function stampFor(credential, credentialEpoch, binding, options = {}) {
|
|
|
182
183
|
* digest the store writes.
|
|
183
184
|
*/
|
|
184
185
|
export function providerStateDigest(codec, value) {
|
|
185
|
-
const bound = codec?.credentialBound
|
|
186
|
+
const bound = codec?.credentialBound
|
|
187
|
+
? runInsideCodec(() => codec.credentialBound?.(value))
|
|
188
|
+
: value;
|
|
186
189
|
return createHash('sha256')
|
|
187
190
|
.update(`provider-state\0${JSON.stringify(bound ?? null)}`)
|
|
188
191
|
.digest('hex');
|
|
@@ -420,8 +423,10 @@ function parseEntry(raw, codec) {
|
|
|
420
423
|
return undefined;
|
|
421
424
|
if ('disabledReason' in raw && typeof raw.disabledReason !== 'string')
|
|
422
425
|
return undefined;
|
|
423
|
-
const quota = 'quota' in raw && codec.decode
|
|
424
|
-
|
|
426
|
+
const quota = 'quota' in raw && codec.decode
|
|
427
|
+
? runInsideCodec(() => codec.decode?.(raw.quota))
|
|
428
|
+
: raw.quota;
|
|
429
|
+
if ('quota' in raw && !runInsideCodec(() => codec.validate(quota)))
|
|
425
430
|
return undefined;
|
|
426
431
|
if ('staged' in raw && !parseReservation(raw.staged))
|
|
427
432
|
return undefined;
|
|
@@ -666,7 +671,7 @@ function providerStateFields(account, credential, credentialEpoch, identity, cod
|
|
|
666
671
|
const value = account[PROVIDER_STATE_KEY];
|
|
667
672
|
// The value is validated before it is projected, so the projection only
|
|
668
673
|
// ever sees a value of the shape the codec accepts.
|
|
669
|
-
if (!codec
|
|
674
|
+
if (!codec || !runInsideCodec(() => codec.validate(value)))
|
|
670
675
|
return { providerStateDropped: 'invalid' };
|
|
671
676
|
if (providerStateDigest(codec, value) !== digest)
|
|
672
677
|
return { providerStateDropped: 'uncovered' };
|
|
@@ -59,5 +59,7 @@ export declare function readPoolSettings(rt: StoreRuntime): Promise<SettingsRead
|
|
|
59
59
|
* pool-owned key refuses (`invalid-input`) with nothing written; a result
|
|
60
60
|
* equal to the current settings writes nothing. The state file is never
|
|
61
61
|
* touched, and the pool-owned keys are written back exactly as read.
|
|
62
|
+
* commonAuthLimits is also carried through unchanged, even when omitted by
|
|
63
|
+
* the mutator; an explicit change to it refuses before writing anything.
|
|
62
64
|
*/
|
|
63
65
|
export declare function updatePoolSettings(rt: StoreRuntime, mutator: SettingsMutator, options?: UpdateSettingsOptions): Promise<UpdateSettingsResult>;
|
|
@@ -36,12 +36,13 @@ function defineKey(target, key, value) {
|
|
|
36
36
|
/**
|
|
37
37
|
* The next config: the pool-owned keys exactly as read, every settings key
|
|
38
38
|
* from `next` in its existing position, settings keys `next` dropped left
|
|
39
|
-
* out, and new settings keys appended.
|
|
39
|
+
* out, and new settings keys appended. The limits envelope is always carried
|
|
40
|
+
* through from disk; ordinary settings mutators do not own that namespace.
|
|
40
41
|
*/
|
|
41
42
|
function composeConfig(config, next) {
|
|
42
43
|
const out = {};
|
|
43
44
|
for (const [key, value] of Object.entries(config)) {
|
|
44
|
-
if (POOL_OWNED_KEYS.includes(key))
|
|
45
|
+
if (POOL_OWNED_KEYS.includes(key) || key === 'commonAuthLimits')
|
|
45
46
|
defineKey(out, key, value);
|
|
46
47
|
else if (Object.hasOwn(next, key))
|
|
47
48
|
defineKey(out, key, next[key]);
|
|
@@ -82,6 +83,8 @@ export async function readPoolSettings(rt) {
|
|
|
82
83
|
* pool-owned key refuses (`invalid-input`) with nothing written; a result
|
|
83
84
|
* equal to the current settings writes nothing. The state file is never
|
|
84
85
|
* touched, and the pool-owned keys are written back exactly as read.
|
|
86
|
+
* commonAuthLimits is also carried through unchanged, even when omitted by
|
|
87
|
+
* the mutator; an explicit change to it refuses before writing anything.
|
|
85
88
|
*/
|
|
86
89
|
export async function updatePoolSettings(rt, mutator, options = {}) {
|
|
87
90
|
assertNotInsideHook('updateSettings');
|
|
@@ -109,9 +112,13 @@ export async function updatePoolSettings(rt, mutator, options = {}) {
|
|
|
109
112
|
const owned = POOL_OWNED_KEYS.filter((key) => Object.hasOwn(next, key));
|
|
110
113
|
if (owned.length > 0)
|
|
111
114
|
throw settingsRefusal(`settings cannot set the pool-owned key(s) ${owned.join(', ')}`);
|
|
112
|
-
if (
|
|
113
|
-
|
|
115
|
+
if (Object.hasOwn(next, 'commonAuthLimits') &&
|
|
116
|
+
(!Object.hasOwn(current, 'commonAuthLimits') ||
|
|
117
|
+
!isDeepStrictEqual(next.commonAuthLimits, current.commonAuthLimits)))
|
|
118
|
+
throw settingsRefusal('settings cannot alter commonAuthLimits; use updateLimitsNamespace');
|
|
114
119
|
const config = composeConfig(result.config, next);
|
|
120
|
+
if (isDeepStrictEqual(settingsOf(config), current))
|
|
121
|
+
return { settings: current, outcome: 'unchanged' };
|
|
115
122
|
const info = { operation: 'updateSettings', rowId: undefined };
|
|
116
123
|
await writeJsonAtomic(ctx.configPath, config, {
|
|
117
124
|
beforeRename: async () => {
|
package/package.json
CHANGED