@cortexkit/common-auth 0.2.0 → 0.2.1

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.
@@ -1,6 +1,6 @@
1
1
  import type { StoredCredential } from './schema.js';
2
2
  /** Every library operation that can fail, as named in the failure value. */
3
- export type PoolOperation = 'add' | 'replace' | 'rotate' | 'disable' | 'recordIdentity' | 'refresh' | 'pull';
3
+ export type PoolOperation = 'initialize' | 'add' | 'replace' | 'rotate' | 'disable' | 'recordIdentity' | 'refresh' | 'pull';
4
4
  /**
5
5
  * How far an operation got before it failed.
6
6
  *
@@ -3,7 +3,7 @@ export type { PoolFailureKind, PoolFailurePhase, PoolOperation, } from './errors
3
3
  export { PoolOperationError, PoolReentryError } from './errors.js';
4
4
  export type { PoolLogger } from './hooks.js';
5
5
  export { countUnknownIdentityRows, DUPLICATE_IDENTITY_REASON, } from './identity.js';
6
- export type { HoldPoint, WriteStep } from './mutate.js';
6
+ export type { HoldPoint, InitializeOutcome, WriteStep } from './mutate.js';
7
7
  export type { OpenPoolStoreOptions, PoolLoad, PoolStore, } from './pool.js';
8
8
  export { openPoolStore } from './pool.js';
9
9
  export type { PullHook, PullRequest } from './pull.js';
@@ -92,6 +92,19 @@ export declare class Transaction {
92
92
  commitState(committed?: StoredCredential): Promise<void>;
93
93
  private write;
94
94
  }
95
+ /** What `initializePool` did. */
96
+ export type InitializeOutcome = 'initialized' | 'already-ready';
97
+ /**
98
+ * Adds the pool key to a config that holds a legacy roster without one, under
99
+ * the store-lock list, in one config write: `commonAuthPool` with the schema
100
+ * version and no row entries, the legacy roster and every other top-level key
101
+ * kept, except the keys named in `dropKeys`. The state file is not touched.
102
+ * This is the only write the store makes to a pending-migration config; it is
103
+ * where a plugin's migration starts, and every later row goes through the
104
+ * ordinary operations. A config that is already a pool is left alone; a load
105
+ * error refuses.
106
+ */
107
+ export declare function initializePool(ctx: StoreContext, dropKeys: readonly string[]): Promise<InitializeOutcome>;
95
108
  /**
96
109
  * Runs `fn` under the store-lock list. The pool must be ready: a pending
97
110
  * migration or a load error refuses before anything is written.
@@ -195,6 +195,51 @@ export class Transaction {
195
195
  await this.ctx.onStep?.(`after-${file}-write`, this.info);
196
196
  }
197
197
  }
198
+ /**
199
+ * Adds the pool key to a config that holds a legacy roster without one, under
200
+ * the store-lock list, in one config write: `commonAuthPool` with the schema
201
+ * version and no row entries, the legacy roster and every other top-level key
202
+ * kept, except the keys named in `dropKeys`. The state file is not touched.
203
+ * This is the only write the store makes to a pending-migration config; it is
204
+ * where a plugin's migration starts, and every later row goes through the
205
+ * ordinary operations. A config that is already a pool is left alone; a load
206
+ * error refuses.
207
+ */
208
+ export async function initializePool(ctx, dropKeys) {
209
+ const locks = new LockStack(ctx.lockDefaults, ctx.lockEnv);
210
+ const progress = { writes: 0 };
211
+ try {
212
+ for (const spec of ctx.storeLocks)
213
+ await locks.acquire(spec);
214
+ const result = await readPool(ctx);
215
+ if (result.status === 'error')
216
+ throw notReadyError(result, 'initialize', undefined);
217
+ if (result.status === 'ready')
218
+ return 'already-ready';
219
+ const next = {};
220
+ for (const [key, value] of Object.entries(result.config))
221
+ if (!dropKeys.includes(key))
222
+ next[key] = value;
223
+ next.version = LEGACY_STORE_VERSION;
224
+ next[POOL_KEY] = { schemaVersion: POOL_SCHEMA_VERSION, [POOL_ROWS_KEY]: {} };
225
+ const info = { operation: 'initialize', rowId: undefined };
226
+ await writeJsonAtomic(ctx.configPath, next, {
227
+ beforeRename: async () => {
228
+ await ctx.onStep?.('before-config-write', info);
229
+ await locks.assertAll();
230
+ },
231
+ });
232
+ progress.writes++;
233
+ await ctx.onStep?.('after-config-write', info);
234
+ return 'initialized';
235
+ }
236
+ catch (error) {
237
+ throw toFailure(error, 'initialize', undefined, progress);
238
+ }
239
+ finally {
240
+ await locks.releaseAll();
241
+ }
242
+ }
198
243
  /**
199
244
  * Runs `fn` under the store-lock list. The pool must be ready: a pending
200
245
  * migration or a load error refuses before anything is written.
@@ -1,7 +1,7 @@
1
1
  import { type Attribution } from './attribution.js';
2
2
  import type { PoolOperationError } from './errors.js';
3
3
  import type { PoolLogger } from './hooks.js';
4
- import { type HoldPoint, type StoreContext } from './mutate.js';
4
+ import { type HoldPoint, type InitializeOutcome, type StoreContext } from './mutate.js';
5
5
  import { type PullHook } from './pull.js';
6
6
  import { type ProviderRefresh, type RefreshOptions, type RefreshOutcome } from './refresh.js';
7
7
  import { type LockEnvironment, type PoolLockOptions, type PoolLockSpec } from './refresh-lock.js';
@@ -55,6 +55,17 @@ export interface PoolStore {
55
55
  load(): Promise<PoolLoad>;
56
56
  /** Reads the pool without firing anything. */
57
57
  read(): Promise<PoolLoad>;
58
+ /**
59
+ * Turns a pending-migration config into an empty pool (the pool key with no
60
+ * row entries) in one locked config write, dropping the named top-level
61
+ * keys and keeping the rest. The start of a plugin's migration; a ready
62
+ * pool is left alone. Failures carry operation `initialize`.
63
+ */
64
+ initialize(input?: {
65
+ dropKeys?: readonly string[];
66
+ }): Promise<{
67
+ status: InitializeOutcome;
68
+ }>;
58
69
  add(input: AddInput, options?: RowOperationOptions): Promise<AddResult>;
59
70
  replace(id: string, credential: PoolCredential, input?: {
60
71
  identity?: string;
@@ -1,5 +1,5 @@
1
1
  import { recordQuota } from './attribution.js';
2
- import { readPool } from './mutate.js';
2
+ import { initializePool, readPool, } from './mutate.js';
3
3
  import { PullScheduler } from './pull.js';
4
4
  import { refreshRow, } from './refresh.js';
5
5
  import { POOL_LOCK_DEFAULTS, } from './refresh-lock.js';
@@ -85,6 +85,9 @@ export function openPoolStore(options) {
85
85
  async read() {
86
86
  return toLoad(await readPool(ctx));
87
87
  },
88
+ async initialize(input = {}) {
89
+ return { status: await initializePool(ctx, input.dropKeys ?? []) };
90
+ },
88
91
  add: (input, callOptions) => addRow(rt, input, callOptions),
89
92
  replace: (id, credential, input, callOptions) => replaceRow(rt, id, credential, input, callOptions),
90
93
  rotate: (id, credential, input, callOptions) => rotateRow(rt, id, credential, input, callOptions),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/common-auth",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Shared plumbing for the CortexKit auth plugins: loopback RPC, file locks and atomic writes, logger, sidebar state file, TUI preferences and TUI build.",
5
5
  "license": "MIT",
6
6
  "repository": {