@cortexkit/common-auth 0.2.4 → 0.2.6
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/auth-menu/accounts.d.ts +88 -0
- package/dist/auth-menu/accounts.js +401 -0
- package/dist/auth-menu/ansi.d.ts +24 -0
- package/dist/auth-menu/ansi.js +67 -0
- package/dist/auth-menu/confirm.d.ts +7 -0
- package/dist/auth-menu/confirm.js +21 -0
- package/dist/auth-menu/doctor.d.ts +52 -0
- package/dist/auth-menu/doctor.js +81 -0
- package/dist/auth-menu/index.d.ts +17 -1
- package/dist/auth-menu/index.js +12 -2
- package/dist/auth-menu/login.d.ts +47 -0
- package/dist/auth-menu/login.js +63 -0
- package/dist/auth-menu/menu.d.ts +59 -0
- package/dist/auth-menu/menu.js +73 -0
- package/dist/auth-menu/opencode-v1.d.ts +49 -0
- package/dist/auth-menu/opencode-v1.js +47 -0
- package/dist/auth-menu/select.d.ts +21 -0
- package/dist/auth-menu/select.js +153 -0
- package/dist/auth-menu/terminal.d.ts +43 -0
- package/dist/auth-menu/terminal.js +19 -0
- package/dist/cachekeep/index.d.ts +4 -1
- package/dist/cachekeep/index.js +2 -2
- package/dist/cachekeep/manager.d.ts +214 -0
- package/dist/cachekeep/manager.js +424 -0
- package/dist/cachekeep/window.d.ts +13 -0
- package/dist/cachekeep/window.js +33 -0
- package/dist/commands/builtins.d.ts +71 -0
- package/dist/commands/builtins.js +508 -0
- package/dist/commands/index.d.ts +10 -1
- package/dist/commands/index.js +5 -2
- package/dist/commands/menu.d.ts +39 -0
- package/dist/commands/menu.js +249 -0
- package/dist/commands/model.d.ts +188 -0
- package/dist/commands/model.js +16 -0
- package/dist/commands/pi.d.ts +22 -0
- package/dist/commands/pi.js +178 -0
- package/dist/commands/seam.d.ts +36 -0
- package/dist/commands/seam.js +185 -0
- package/dist/dump/index.d.ts +90 -1
- package/dist/dump/index.js +292 -2
- package/dist/store/errors.d.ts +1 -1
- package/dist/store/index.d.ts +2 -0
- package/dist/store/index.js +1 -0
- package/dist/store/pool.d.ts +12 -0
- package/dist/store/pool.js +3 -0
- package/dist/store/settings.d.ts +63 -0
- package/dist/store/settings.js +120 -0
- package/package.json +1 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { PoolOperationError } from './errors.js';
|
|
2
|
+
import type { PoolLockSpec } from './refresh-lock.js';
|
|
3
|
+
import type { StoreRuntime } from './runtime.js';
|
|
4
|
+
/**
|
|
5
|
+
* Top-level config keys the pool owns: the legacy `version`, the legacy
|
|
6
|
+
* roster (`accounts`) and the pool's own key. A settings write never reads
|
|
7
|
+
* them into the settings it hands out and refuses a result that sets them,
|
|
8
|
+
* so the roster and the per-row entries change only through row operations.
|
|
9
|
+
*/
|
|
10
|
+
export declare const POOL_OWNED_KEYS: readonly string[];
|
|
11
|
+
/** The plugin's settings: every top-level config key except the pool-owned ones. */
|
|
12
|
+
export type PoolSettings = Record<string, unknown>;
|
|
13
|
+
export type SettingsRead = {
|
|
14
|
+
status: 'ready';
|
|
15
|
+
settings: PoolSettings;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The config still holds a legacy roster with no pool key. Its settings
|
|
19
|
+
* read the same way; `updateSettings` refuses until the pool is initialized.
|
|
20
|
+
*/
|
|
21
|
+
| {
|
|
22
|
+
status: 'pending-migration';
|
|
23
|
+
settings: PoolSettings;
|
|
24
|
+
} | {
|
|
25
|
+
status: 'error';
|
|
26
|
+
file: 'config' | 'state';
|
|
27
|
+
reason: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Receives a private copy of the current settings and either edits it in
|
|
31
|
+
* place (returning nothing) or returns the complete next settings object.
|
|
32
|
+
* It runs under the store locks, so it must not call back into the store:
|
|
33
|
+
* a store operation called from inside it is refused (`PoolReentryError`).
|
|
34
|
+
*/
|
|
35
|
+
export type SettingsMutator = (settings: PoolSettings) => PoolSettings | undefined | Promise<PoolSettings | undefined>;
|
|
36
|
+
/**
|
|
37
|
+
* Options of `updateSettings`. It names no row, so its failure hook is
|
|
38
|
+
* handed only the failure; like `reorder` it takes the extra locks, then the
|
|
39
|
+
* store locks, and no row or provider-wide lock.
|
|
40
|
+
*/
|
|
41
|
+
export interface UpdateSettingsOptions {
|
|
42
|
+
/** Called once, awaited, on every non-success path, before the extra locks release. */
|
|
43
|
+
onFailure?: (error: PoolOperationError) => void | Promise<void>;
|
|
44
|
+
/** Locks taken, in this order, before the store locks. */
|
|
45
|
+
extraLocks?: readonly PoolLockSpec[];
|
|
46
|
+
}
|
|
47
|
+
export type UpdateSettingsResult = {
|
|
48
|
+
/** The settings now on disk. */
|
|
49
|
+
settings: PoolSettings;
|
|
50
|
+
/** `unchanged` when the mutator left the settings as they were; nothing was written. */
|
|
51
|
+
outcome: 'updated' | 'unchanged';
|
|
52
|
+
};
|
|
53
|
+
/** Reads the settings without taking a lock or writing anything. */
|
|
54
|
+
export declare function readPoolSettings(rt: StoreRuntime): Promise<SettingsRead>;
|
|
55
|
+
/**
|
|
56
|
+
* One locked read-modify-write of the plugin's settings in the config file
|
|
57
|
+
* the pool lives in. The pool must be ready (a pending migration or a load
|
|
58
|
+
* error refuses before the mutator runs). A mutator result that sets a
|
|
59
|
+
* pool-owned key refuses (`invalid-input`) with nothing written; a result
|
|
60
|
+
* equal to the current settings writes nothing. The state file is never
|
|
61
|
+
* touched, and the pool-owned keys are written back exactly as read.
|
|
62
|
+
*/
|
|
63
|
+
export declare function updatePoolSettings(rt: StoreRuntime, mutator: SettingsMutator, options?: UpdateSettingsOptions): Promise<UpdateSettingsResult>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
2
|
+
import { writeJsonAtomic } from '../fs/atomic-write.js';
|
|
3
|
+
import { PoolOperationError } from './errors.js';
|
|
4
|
+
import { assertNotInsideHook, runInsideHook } from './hooks.js';
|
|
5
|
+
import { notReadyError, readPool, runOperation } from './mutate.js';
|
|
6
|
+
import { isRecord, POOL_KEY } from './schema.js';
|
|
7
|
+
/**
|
|
8
|
+
* Top-level config keys the pool owns: the legacy `version`, the legacy
|
|
9
|
+
* roster (`accounts`) and the pool's own key. A settings write never reads
|
|
10
|
+
* them into the settings it hands out and refuses a result that sets them,
|
|
11
|
+
* so the roster and the per-row entries change only through row operations.
|
|
12
|
+
*/
|
|
13
|
+
export const POOL_OWNED_KEYS = Object.freeze([
|
|
14
|
+
'version',
|
|
15
|
+
'accounts',
|
|
16
|
+
POOL_KEY,
|
|
17
|
+
]);
|
|
18
|
+
function settingsOf(config) {
|
|
19
|
+
const settings = {};
|
|
20
|
+
for (const [key, value] of Object.entries(config))
|
|
21
|
+
if (!POOL_OWNED_KEYS.includes(key))
|
|
22
|
+
defineKey(settings, key, value);
|
|
23
|
+
return settings;
|
|
24
|
+
}
|
|
25
|
+
/** Sets a key as an own data property, so a `__proto__` key stays a plain key. */
|
|
26
|
+
function defineKey(target, key, value) {
|
|
27
|
+
Object.defineProperty(target, key, {
|
|
28
|
+
value,
|
|
29
|
+
enumerable: true,
|
|
30
|
+
writable: true,
|
|
31
|
+
configurable: true,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The next config: the pool-owned keys exactly as read, every settings key
|
|
36
|
+
* from `next` in its existing position, settings keys `next` dropped left
|
|
37
|
+
* out, and new settings keys appended.
|
|
38
|
+
*/
|
|
39
|
+
function composeConfig(config, next) {
|
|
40
|
+
const out = {};
|
|
41
|
+
for (const [key, value] of Object.entries(config)) {
|
|
42
|
+
if (POOL_OWNED_KEYS.includes(key))
|
|
43
|
+
defineKey(out, key, value);
|
|
44
|
+
else if (Object.hasOwn(next, key))
|
|
45
|
+
defineKey(out, key, next[key]);
|
|
46
|
+
}
|
|
47
|
+
for (const [key, value] of Object.entries(next))
|
|
48
|
+
if (!Object.hasOwn(config, key))
|
|
49
|
+
defineKey(out, key, value);
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
function settingsRefusal(message) {
|
|
53
|
+
return new PoolOperationError({
|
|
54
|
+
operation: 'updateSettings',
|
|
55
|
+
phase: 'before-first-write',
|
|
56
|
+
retryable: false,
|
|
57
|
+
kind: 'invalid-input',
|
|
58
|
+
message,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/** Reads the settings without taking a lock or writing anything. */
|
|
62
|
+
export async function readPoolSettings(rt) {
|
|
63
|
+
const result = await readPool(rt.ctx);
|
|
64
|
+
if (result.status === 'error')
|
|
65
|
+
return result;
|
|
66
|
+
return { status: result.status, settings: settingsOf(result.config) };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* One locked read-modify-write of the plugin's settings in the config file
|
|
70
|
+
* the pool lives in. The pool must be ready (a pending migration or a load
|
|
71
|
+
* error refuses before the mutator runs). A mutator result that sets a
|
|
72
|
+
* pool-owned key refuses (`invalid-input`) with nothing written; a result
|
|
73
|
+
* equal to the current settings writes nothing. The state file is never
|
|
74
|
+
* touched, and the pool-owned keys are written back exactly as read.
|
|
75
|
+
*/
|
|
76
|
+
export async function updatePoolSettings(rt, mutator, options = {}) {
|
|
77
|
+
assertNotInsideHook('updateSettings');
|
|
78
|
+
const { ctx } = rt;
|
|
79
|
+
const onFailure = options.onFailure;
|
|
80
|
+
return runOperation(ctx, 'updateSettings', undefined, onFailure && ((_rowId, error) => onFailure(error)), async (locks, progress) => {
|
|
81
|
+
for (const extra of options.extraLocks ?? [])
|
|
82
|
+
await locks.acquire(extra);
|
|
83
|
+
// `mark` is where the store locks start on the lock stack. They are
|
|
84
|
+
// released at the end of this block, so `onFailure` runs holding only
|
|
85
|
+
// the caller's extra locks, as it does for every other store operation.
|
|
86
|
+
const mark = locks.held.length;
|
|
87
|
+
try {
|
|
88
|
+
for (const spec of ctx.storeLocks)
|
|
89
|
+
await locks.acquire(spec);
|
|
90
|
+
const result = await readPool(ctx);
|
|
91
|
+
if (result.status !== 'ready')
|
|
92
|
+
throw notReadyError(result, 'updateSettings', undefined);
|
|
93
|
+
const current = settingsOf(result.config);
|
|
94
|
+
const draft = structuredClone(current);
|
|
95
|
+
const returned = await runInsideHook('updateSettings', () => mutator(draft));
|
|
96
|
+
const next = returned === undefined ? draft : returned;
|
|
97
|
+
if (!isRecord(next))
|
|
98
|
+
throw settingsRefusal('the settings mutator must produce an object');
|
|
99
|
+
const owned = POOL_OWNED_KEYS.filter((key) => Object.hasOwn(next, key));
|
|
100
|
+
if (owned.length > 0)
|
|
101
|
+
throw settingsRefusal(`settings cannot set the pool-owned key(s) ${owned.join(', ')}`);
|
|
102
|
+
if (isDeepStrictEqual(next, current))
|
|
103
|
+
return { settings: current, outcome: 'unchanged' };
|
|
104
|
+
const config = composeConfig(result.config, next);
|
|
105
|
+
const info = { operation: 'updateSettings', rowId: undefined };
|
|
106
|
+
await writeJsonAtomic(ctx.configPath, config, {
|
|
107
|
+
beforeRename: async () => {
|
|
108
|
+
await ctx.onStep?.('before-config-write', info);
|
|
109
|
+
await locks.assertAll();
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
progress.writes++;
|
|
113
|
+
await ctx.onStep?.('after-config-write', info);
|
|
114
|
+
return { settings: settingsOf(config), outcome: 'updated' };
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
await locks.releaseTo(mark);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/common-auth",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Shared code for the CortexKit auth plugins: account pool, quota and routing, commands and auth menu, OpenCode 2 hooks, Claustrum custody, and plumbing (loopback RPC, file locks, logger, sidebar state, TUI preferences and build).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|