@cortexkit/anthropic-auth-core 2.2.8 → 2.4.0

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.
Files changed (33) hide show
  1. package/dist/accounts.d.ts +2 -0
  2. package/dist/cachekeep.d.ts +6 -0
  3. package/dist/holder-registry.d.ts +159 -0
  4. package/dist/index.d.ts +4 -1
  5. package/dist/index.js +3877 -1299
  6. package/dist/internal-types/claustrum/consumer.d.ts +77 -2
  7. package/dist/internal-types/claustrum/custody.d.ts +36 -1
  8. package/dist/internal-types/claustrum/enrollment.d.ts +9 -0
  9. package/dist/internal-types/claustrum/hub.d.ts +195 -0
  10. package/dist/internal-types/claustrum/index.d.ts +13 -3
  11. package/dist/internal-types/claustrum/quota-writer.d.ts +8 -1
  12. package/dist/internal-types/claustrum/roster.d.ts +49 -1
  13. package/dist/internal-types/fs/refresh-file-lock.d.ts +1 -1
  14. package/dist/internal-types/quota/commit-interval.d.ts +9 -0
  15. package/dist/internal-types/setup/flags.d.ts +50 -0
  16. package/dist/internal-types/setup/index.d.ts +1 -0
  17. package/dist/internal-types/setup/register.d.ts +2 -0
  18. package/dist/internal-types/setup/types.d.ts +7 -1
  19. package/dist/internal-types/store/attribution.d.ts +5 -0
  20. package/dist/internal-types/store/mutate.d.ts +2 -0
  21. package/dist/internal-types/store/pool.d.ts +22 -0
  22. package/dist/internal-types/store/runtime.d.ts +2 -0
  23. package/dist/internal-types/store/settings.d.ts +1 -1
  24. package/dist/native-account-runtime.d.ts +8 -0
  25. package/dist/native-enrollment-authority.d.ts +2 -0
  26. package/dist/native-runtime-registry.d.ts +2 -2
  27. package/dist/native-vault-paths.d.ts +11 -2
  28. package/dist/native-vault-runtime.d.ts +2 -2
  29. package/dist/pool-paths.d.ts +8 -1
  30. package/dist/relocation-guard.d.ts +48 -0
  31. package/dist/state-layout-paths.d.ts +193 -0
  32. package/dist/sticky-routing.d.ts +8 -0
  33. package/package.json +2 -2
@@ -1,4 +1,6 @@
1
+ import { type StoreContext } from './mutate.js';
1
2
  import { type StoreRuntime } from './runtime.js';
3
+ import { type PoolRow } from './schema.js';
2
4
  /**
3
5
  * What a pull or refresh captured about its row (named by id alongside) when
4
6
  * it was issued. A result applies only while the row with that id still has
@@ -20,6 +22,9 @@ export interface Attribution {
20
22
  credentialEpoch: number;
21
23
  identity?: string;
22
24
  }
25
+ export declare function assertQuotaEpoch(id: string, attribution: Attribution): void;
26
+ export declare function assertQuotaRow(id: string, attribution: Attribution, row: PoolRow | undefined): asserts row is PoolRow;
27
+ export declare function mergedQuota(ctx: StoreContext, id: string, stored: unknown, observation: unknown): unknown;
23
28
  /**
24
29
  * Merges a quota observation into a row's stored map under the store locks,
25
30
  * after attribution passes. Needs no row lock, so it is permitted from
@@ -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
@@ -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';
@@ -16,6 +17,23 @@ export interface OpenPoolStoreOptions {
16
17
  configPath: string;
17
18
  statePath: string;
18
19
  quota: QuotaCodec;
20
+ /**
21
+ * Opt in to detached, coalesced quota publication, with any `quota` codec.
22
+ * Each accepted observation is queued whole for its row and binding, and
23
+ * the queue is applied in arrival order through `quota.merge` under the
24
+ * store locks, so the codec's own merge decides which fields a newer or
25
+ * older reading replaces. Accepted readings appear in read/load
26
+ * immediately, merged the same way; the returned promise still rejects
27
+ * current-row refusals before queueing. Await dispose or close at shutdown
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.
31
+ */
32
+ coalesceQuota?: boolean;
33
+ /** Bounded quota drain on close/dispose, in milliseconds; defaults to 1,000. */
34
+ quotaDrainTimeoutMs?: number;
35
+ /** Monotonic clock and scheduling seam for detached quota commits. */
36
+ quotaCommitTimer?: QuotaCommitTimer;
19
37
  /**
20
38
  * The codec of the provider state kept beside each row's credential (see
21
39
  * `ProviderStateCodec`). Without it no row shows a provider state, and
@@ -189,6 +207,10 @@ export interface PoolStore {
189
207
  }>;
190
208
  refresh(id: string, provider: ProviderRefresh, options?: RefreshOptions): Promise<RefreshOutcome>;
191
209
  recordQuota(id: string, attribution: Attribution, observation: unknown): Promise<void>;
210
+ /** Drain opted-in quota publication; subsequent coalesced readings refuse. Idempotent. */
211
+ close(): Promise<void>;
212
+ /** Same bounded quota drain as close(). Does not wait for provider pull hooks. */
213
+ dispose(): Promise<void>;
192
214
  /** Fires a pull for a row admission refused for want of a reading. */
193
215
  requestReading(id: string): void;
194
216
  /** Resolves once every pull fired so far has settled. */
@@ -1,3 +1,4 @@
1
+ import type { Attribution } from './attribution.js';
1
2
  import { type PoolOperation, PoolOperationError } from './errors.js';
2
3
  import { type ReadResult, type StoreContext } from './mutate.js';
3
4
  import type { PoolLockOptions, PoolLockSpec } from './refresh-lock.js';
@@ -10,6 +11,7 @@ export interface StoreRuntime {
10
11
  providerLock: PoolLockSpec;
11
12
  rowLockOptions: Partial<PoolLockOptions>;
12
13
  firePull(id: string, reason: PullReason): void;
14
+ publishQuota?: (id: string, attribution: Attribution, observation: unknown) => Promise<void>;
13
15
  }
14
16
  /**
15
17
  * The row lock's (name, path): keyed by the row's recorded wire identity when
@@ -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
@@ -13,6 +13,7 @@ import { type NativeLocalPoolBinding } from './pool-binding.ts';
13
13
  import { type NativePoolPaths } from './pool-paths.ts';
14
14
  import type { QuotaRequestDispatch } from './quota-manager.ts';
15
15
  import { type RelayConfig } from './relay.ts';
16
+ import { type RelocationGuard } from './relocation-guard.ts';
16
17
  export type { NativeAccountMetadataPatch, NativeAccountSnapshot, NativeAccountView, } from './native-account-view.ts';
17
18
  export interface NativeAccountRuntimeOptions {
18
19
  paths: NativePoolPaths;
@@ -47,8 +48,15 @@ export type NativeRelayUpdate = Partial<Omit<RelayConfig, 'token'>> & {
47
48
  };
48
49
  export interface NativeAccountRuntime {
49
50
  readonly onLockEvent?: (event: NativeLockEvent) => void;
51
+ /**
52
+ * Refuses once a newer version has moved this runtime's files. Hosts pass
53
+ * it to the routing stores they create, so their writes check it under
54
+ * the routing file's lock.
55
+ */
56
+ readonly relocationGuard?: RelocationGuard;
50
57
  readonly vault: NativeVaultRuntime;
51
58
  readonly quotaObservations: NativeQuotaObservations;
59
+ /** Waits for pending quota observations, quota submissions, and runtime metadata writes. An accepted pool quota update may not yet be on disk; close() drains the pool's pending quota writes. */
52
60
  drainQuotaPublications(): Promise<void>;
53
61
  drainRoutingPublications(): Promise<void>;
54
62
  /** Fresh private relay authorization for transport only; never include it in a status snapshot. */
@@ -1,5 +1,7 @@
1
1
  import { enrollmentAuthority, readClaustrumEnrollmentStatus } from "./internal-types/claustrum/index.js";
2
2
  import { NativeCustodyError } from './native-custody.ts';
3
+ /** Test-only reset for the once-per-process enrollment mode log. */
4
+ export declare function __resetEnrollmentModeLogForTests(): void;
3
5
  /**
4
6
  * Shown instead of `Native custody refused: invalid-token` when the
5
7
  * enrollment files could not be read because the private-files backend did
@@ -9,11 +9,11 @@ export declare function nativeRuntimeStorageKey(options: {
9
9
  export declare function nativeRuntimeConnectionFile(host: 'opencode' | 'pi', env: NodeJS.ProcessEnv): string;
10
10
  /** A release applies to the runtime entry acquired earlier, not to a later entry created with the same key. */
11
11
  export declare class NativeRuntimeRegistry<T extends {
12
- close(): void;
12
+ close(): void | Promise<void>;
13
13
  }> {
14
14
  private readonly entries;
15
15
  acquire(key: string, create: () => T): {
16
16
  use: () => T;
17
- close: () => void;
17
+ close: () => void | Promise<void>;
18
18
  };
19
19
  }
@@ -1,4 +1,5 @@
1
1
  import type { NativePoolPaths } from './pool-paths.ts';
2
+ import { type StateLayout } from './state-layout-paths.ts';
2
3
  /** Vault files have no migration journal: enrollment alone authorizes their use. */
3
4
  export interface NativeVaultPaths {
4
5
  config: string;
@@ -9,5 +10,13 @@ export interface NativeVaultPaths {
9
10
  storageId: string;
10
11
  legacySeedConfig: string;
11
12
  }
12
- /** Keep vault settings, metadata and affinity outside every local recovery file. */
13
- export declare function nativeVaultPaths(local: NativePoolPaths): NativeVaultPaths;
13
+ /**
14
+ * Keep vault settings, metadata and affinity outside every local recovery file.
15
+ *
16
+ * `layout` must be the one `local` was resolved in: the local paths don't say
17
+ * where the vault's state files are. It defaults to this process's layout
18
+ * decision. Vault settings stay beside the account file in every layout, and
19
+ * the storage id is always computed from the vault store state's
20
+ * legacy-layout path.
21
+ */
22
+ export declare function nativeVaultPaths(local: NativePoolPaths, layout?: StateLayout): NativeVaultPaths;
@@ -116,7 +116,7 @@ export interface NativeVaultRuntime {
116
116
  resetBackoff(receipt: NativeCustodyReceipt, kind?: 'refresh' | 'quota' | 'all'): Promise<boolean>;
117
117
  getOrCreateAuthLineage(receipt: NativeCustodyReceipt): Promise<string | undefined>;
118
118
  incrementPrimeUsage(receipt: NativeCustodyReceipt, delta?: PrimeUsageDelta): Promise<boolean>;
119
- close(): void;
119
+ close(): void | Promise<void>;
120
120
  }
121
121
  /** Publish the initial roster from validated account inventory. A caller importing captured state must fence that state through assertOwned, which runs again at the roster's actual publication. */
122
122
  export declare function publishNativeVaultRosterSeed(paths: Pick<NativeVaultPaths, 'roster'>, input: NativeRosterSeedInput, options?: {
@@ -136,4 +136,4 @@ export declare function nativeVaultRuntimeKey(options: NativeVaultRuntimeOptions
136
136
  /** Each handle owns one reference; disposing it cannot close another host session. */
137
137
  export declare function acquireNativeVaultRuntime(options: NativeVaultRuntimeOptions): NativeVaultRuntime;
138
138
  /** Each account lease wraps the shared vault runtime and tracks its own subscriptions, so releasing the lease removes those subscriptions. */
139
- export declare function leaseNativeVaultRuntime(use: () => NativeVaultRuntime, close: () => void): NativeVaultRuntime;
139
+ export declare function leaseNativeVaultRuntime(use: () => NativeVaultRuntime, close: () => void | Promise<void>): NativeVaultRuntime;
@@ -1,3 +1,4 @@
1
+ import { type StateLayout } from './state-layout-paths.ts';
1
2
  export interface NativePoolPaths {
2
3
  legacyConfig: string;
3
4
  legacyState: string;
@@ -19,5 +20,11 @@ export declare function canonicalPath(path: string): Promise<string>;
19
20
  /**
20
21
  * Separate runtime authority from import inputs so a stale legacy writer cannot
21
22
  * rewrite a stamped credential. Both independently configured paths matter.
23
+ *
24
+ * `layout` places the pool state, runtime, journal and custody roster; the pool
25
+ * config stays beside the account file in every layout. It defaults to this
26
+ * process's layout decision, so a re-resolution matches the first resolution.
27
+ * The storage id is always computed from the pool state's legacy-layout path,
28
+ * so moving files between layouts never changes it.
22
29
  */
23
- export declare function resolveNativePoolPaths(legacyConfig?: string, legacyState?: string): Promise<NativePoolPaths>;
30
+ export declare function resolveNativePoolPaths(legacyConfig?: string, legacyState?: string, layout?: StateLayout): Promise<NativePoolPaths>;
@@ -0,0 +1,48 @@
1
+ import type { NativePoolPaths } from './pool-paths.ts';
2
+ import { type RelocationPointer } from './state-layout-paths.ts';
3
+ /**
4
+ * Fixed text of the refusal a process gives once a newer version has moved
5
+ * the state files it uses. It names no path, because hosts show it on screen
6
+ * and in their own logs; the log line written with it names the folders.
7
+ */
8
+ export declare const RELOCATED_MESSAGE = "Anthropic account state was moved to a new folder by a newer anthropic-auth version. Update anthropic-auth in every OpenCode and Pi that uses this folder, then restart them.";
9
+ /**
10
+ * A runtime file this process uses has been replaced by a relocation
11
+ * tombstone: a newer version moved the dataset elsewhere, and this version
12
+ * can't follow it. Every later use of the old files is refused, so this
13
+ * process never writes beside state it no longer owns.
14
+ */
15
+ export declare class RelocatedError extends Error {
16
+ readonly code = "relocated";
17
+ /** The old runtime path that holds the tombstone. */
18
+ readonly runtimePath: string;
19
+ /** Where the tombstone says the state went. */
20
+ readonly relocatedTo: string;
21
+ constructor(runtimePath: string, pointer: RelocationPointer);
22
+ }
23
+ /**
24
+ * Checks whether a dataset has been moved, by looking for a relocation
25
+ * tombstone over its legacy runtime files. It takes no lock: callers run it
26
+ * inside a callback that already holds the lock a mover must hold to install
27
+ * the tombstone, so the check sees either no move or the tombstone.
28
+ */
29
+ export interface RelocationGuard {
30
+ /** Throws `RelocatedError` when either runtime file is a tombstone. */
31
+ assertNotRelocated(): Promise<void>;
32
+ /** True when either runtime file is a tombstone; never throws for it. */
33
+ isRelocated(): Promise<boolean>;
34
+ }
35
+ /** The first tombstone among `runtimePaths`, with the path that holds it. */
36
+ export declare function findRelocationTombstone(runtimePaths: readonly string[]): Promise<{
37
+ path: string;
38
+ pointer: RelocationPointer;
39
+ } | undefined>;
40
+ /** A guard over the given legacy runtime files. */
41
+ export declare function createRelocationGuard(runtimePaths: readonly string[]): RelocationGuard;
42
+ /**
43
+ * The legacy runtime files of a dataset: its local runtime and its vault
44
+ * runtime. A move replaces both with tombstones before it commits.
45
+ */
46
+ export declare function nativeRelocationRuntimePaths(paths: NativePoolPaths): [string, string];
47
+ /** A guard over a dataset's two legacy runtime files. */
48
+ export declare function nativeRelocationGuard(paths: NativePoolPaths): RelocationGuard;
@@ -0,0 +1,193 @@
1
+ import * as nodePath from 'node:path';
2
+ /**
3
+ * Where a dataset's machine-written files live.
4
+ *
5
+ * - `legacy`: beside the account files in OpenCode's config folder, as in every
6
+ * release so far.
7
+ * - `state-home`: in `dir`, the config folder's own subfolder of the CortexKit
8
+ * state root. `dir` must be absolute and canonical (no symlinked component),
9
+ * because vault paths are derived from it without another realpath pass.
10
+ *
11
+ * The layout decides only where files are. Storage ids never depend on it: they
12
+ * are always computed from where the files would be in the legacy layout, so a
13
+ * file copied between layouts keeps the id it was written with.
14
+ */
15
+ export type StateLayout = {
16
+ readonly kind: 'legacy';
17
+ } | {
18
+ readonly kind: 'state-home';
19
+ readonly dir: string;
20
+ };
21
+ export declare const LEGACY_STATE_LAYOUT: StateLayout;
22
+ /**
23
+ * The layout a resolver uses when its caller passes none. A process decides it
24
+ * once, before it resolves any pool path, and never switches: every
25
+ * re-resolution must use the same layout as the first, or comparisons between
26
+ * them fail. No process can choose the state-home layout yet, so this is
27
+ * always the legacy layout.
28
+ */
29
+ export declare function processStateLayout(): StateLayout;
30
+ /** The `node:path` functions the pure helpers use; tests pass `path.win32`. */
31
+ export type StatePathApi = Pick<typeof nodePath, 'join' | 'isAbsolute'>;
32
+ export interface StateRootInputs {
33
+ /** `XDG_STATE_HOME` exactly as read; undefined or empty means unset. */
34
+ xdgStateHome: string | undefined;
35
+ /** Home directory used when `XDG_STATE_HOME` is unset or not usable. */
36
+ home: string;
37
+ /**
38
+ * Use a relative `XDG_STATE_HOME` as given. The XDG base-directory rules say
39
+ * a relative value is invalid and must be ignored, which is the default and
40
+ * what the CLI diagnostics folder has always done. Host enrollment files and
41
+ * the RPC folder have always accepted a relative value, so they keep doing
42
+ * so: changing it would hide an existing enrollment.
43
+ */
44
+ acceptRelative?: boolean;
45
+ }
46
+ /**
47
+ * The CortexKit state root of anthropic-auth:
48
+ * `<XDG_STATE_HOME or ~/.local/state>/cortexkit/anthropic-auth`. Enrollment
49
+ * files, RPC port files, CLI diagnostics and relocated pool state all live
50
+ * under it.
51
+ */
52
+ export declare function anthropicAuthStateRoot(inputs: StateRootInputs, pathApi?: StatePathApi): string;
53
+ /**
54
+ * The identity of a config folder: `realpathSync.native` of it, compared and
55
+ * hashed exactly as returned, with no case folding on any OS. A folder that
56
+ * doesn't exist has no identity, and its dataset stays in the legacy layout.
57
+ */
58
+ export declare function configFolderIdentity(configDir?: string): string | undefined;
59
+ /** OpenCode's config folder when nothing in the environment overrides it. */
60
+ export declare function homeDefaultConfigDir(home?: string, pathApi?: StatePathApi): string;
61
+ /**
62
+ * The state-root subfolder of a config folder. Only the home directory's
63
+ * default folder gets the plain `opencode` name. That folder is derived from
64
+ * the home directory and never from `XDG_CONFIG_HOME`, so two environments
65
+ * with different `XDG_CONFIG_HOME` values can't both claim `opencode`. Every
66
+ * other folder gets `opencode-<first 16 hex digits of sha256(identity)>`.
67
+ */
68
+ export declare function stateSubfolderName(identity: string, homeDefaultIdentity: string | undefined): string;
69
+ export interface StateHomeTarget {
70
+ /** The config folder's identity (see `configFolderIdentity`). */
71
+ identity: string;
72
+ /** The state root this process uses. */
73
+ stateRoot: string;
74
+ /**
75
+ * The config folder's subfolder of `stateRoot`. It may not exist yet, so it
76
+ * is not canonicalized here.
77
+ */
78
+ dir: string;
79
+ }
80
+ /**
81
+ * Where this process would keep the state of OpenCode's config folder in the
82
+ * state-home layout, or undefined when the config folder has no identity.
83
+ * `XDG_STATE_HOME` must be absolute to count; a relative value is ignored.
84
+ */
85
+ export declare function resolveStateHomeTarget(options?: {
86
+ env?: NodeJS.ProcessEnv;
87
+ home?: string;
88
+ }): StateHomeTarget | undefined;
89
+ /**
90
+ * Names of the files kept in a state-home subfolder. Data files keep their
91
+ * default legacy names so the folder stays readable for manual recovery.
92
+ */
93
+ export declare const STATE_HOME_FILE_NAMES: Readonly<{
94
+ localPoolState: "anthropic-auth-pool-state.json";
95
+ localRuntime: "anthropic-auth-native-state.json";
96
+ journal: "anthropic-auth-migration.json";
97
+ localRoster: "anthropic-auth-custody-roster.json";
98
+ vaultStoreState: "anthropic-auth-vault-store-state.json";
99
+ vaultRuntime: "anthropic-auth-vault-state.json";
100
+ vaultRoster: "anthropic-auth-vault-roster.json";
101
+ vaultRouting: "anthropic-auth-vault-routing-state.json";
102
+ requestGzip: "anthropic-auth-request-gzip.json";
103
+ configDirMarker: "config-dir.json";
104
+ layoutMarker: "layout.json";
105
+ }>;
106
+ export type StateHomeFilePaths = {
107
+ readonly [K in keyof typeof STATE_HOME_FILE_NAMES]: string;
108
+ };
109
+ /**
110
+ * Every file of a state-home subfolder. The account files
111
+ * (`anthropic-auth.json`, `anthropic-auth-state.json`), the pool settings
112
+ * (`anthropic-auth-pool.json`), the vault settings
113
+ * (`anthropic-auth-vault-settings.json`), the local routing file and the TUI
114
+ * preferences stay in the config folder in both layouts and are not listed.
115
+ */
116
+ export declare function stateHomeFilePaths(dir: string, pathApi?: StatePathApi): StateHomeFilePaths;
117
+ /**
118
+ * Files of the state-home layout for a dataset given by its canonical legacy
119
+ * account files. Only the default dataset of a config folder can use that
120
+ * layout: custom file names or a state file away from the config file mean an
121
+ * explicit override, which keeps every file beside the named files.
122
+ */
123
+ export declare function stateHomeDatasetFiles(layout: Extract<StateLayout, {
124
+ kind: 'state-home';
125
+ }>, legacyConfig: string, legacyState: string): StateHomeFilePaths;
126
+ export type StateLayoutFileErrorCode = 'unreadable' | 'invalid';
127
+ /** A state-layout file exists but can't be read or doesn't parse. */
128
+ export declare class StateLayoutFileError extends Error {
129
+ readonly code: StateLayoutFileErrorCode;
130
+ readonly path: string;
131
+ constructor(code: StateLayoutFileErrorCode, path: string, cause?: unknown);
132
+ }
133
+ /** `config-dir.json`: names the config folder a state-home subfolder belongs to. */
134
+ export interface ConfigDirMarker {
135
+ readonly version: 1;
136
+ readonly identity: string;
137
+ }
138
+ /**
139
+ * Read `<dir>/config-dir.json`. Undefined only when the file is absent; any
140
+ * other read error, or content that doesn't parse, throws
141
+ * `StateLayoutFileError`.
142
+ */
143
+ export declare function readConfigDirMarker(dir: string): Promise<ConfigDirMarker | undefined>;
144
+ export declare const STATE_LAYOUT_PHASES: readonly ['preparing', 'committed', 'rolled-back', 'restoring', 'restore-staged', 'restored'];
145
+ export type StateLayoutPhase = (typeof STATE_LAYOUT_PHASES)[number];
146
+ declare const CLEANUP_STATES: readonly ['pending', 'done', 'kept'];
147
+ declare const RESTORE_CLEANUP_STATES: readonly ['pending', 'done'];
148
+ /** The fields of `layout.json` that decide whether a process may use a layout. */
149
+ export interface StateLayoutMarker {
150
+ readonly version: 1;
151
+ readonly phase: StateLayoutPhase;
152
+ readonly attempt: string;
153
+ readonly identity: string;
154
+ readonly stateRoot: string;
155
+ readonly sub: string;
156
+ readonly oldDir: string;
157
+ readonly storageIds: {
158
+ readonly local: string;
159
+ readonly vault: string;
160
+ };
161
+ /** Present once a move has committed. */
162
+ readonly cleanup?: (typeof CLEANUP_STATES)[number];
163
+ /** Present while a restore to the legacy layout is under way or finished. */
164
+ readonly restore?: {
165
+ readonly cleanup?: (typeof RESTORE_CLEANUP_STATES)[number];
166
+ };
167
+ }
168
+ /**
169
+ * Read `<dir>/layout.json`. Undefined only when the file is absent. Any other
170
+ * read error, or content that doesn't parse, throws `StateLayoutFileError`:
171
+ * an unreadable marker must never be taken as "no move" or as a finished one.
172
+ */
173
+ export declare function readStateLayoutMarker(dir: string): Promise<StateLayoutMarker | undefined>;
174
+ /**
175
+ * What a relocation tombstone over an old runtime path says. A move replaces
176
+ * each legacy runtime file with one, so older versions refuse the legacy copy
177
+ * and newer ones can name where the state went.
178
+ */
179
+ export interface RelocationPointer {
180
+ readonly relocatedTo: string;
181
+ readonly stateRoot: string;
182
+ readonly identity: string;
183
+ readonly attempt: string;
184
+ readonly by: string;
185
+ }
186
+ /**
187
+ * Read a legacy runtime path as a relocation tombstone. Undefined when the
188
+ * file is absent, isn't a small regular file, or doesn't parse as a
189
+ * tombstone: such a file is an ordinary runtime, valid or not, and its own
190
+ * reader decides. Read errors other than absence are thrown.
191
+ */
192
+ export declare function readRelocationPointer(runtimePath: string): Promise<RelocationPointer | undefined>;
193
+ export {};
@@ -111,6 +111,14 @@ export declare class StickySessionRouter {
111
111
  vaultSeed?: NativeVaultRoutingSeed;
112
112
  localRecoveryPath?: string;
113
113
  onLockEvent?: (event: NativeLockEvent) => void;
114
+ /**
115
+ * Refuses once a newer version has moved the dataset this routing
116
+ * file belongs to. Every write runs it under the routing file's lock,
117
+ * before any temporary file is created.
118
+ */
119
+ relocationGuard?: {
120
+ assertNotRelocated(): Promise<void>;
121
+ };
114
122
  });
115
123
  private now;
116
124
  private readState;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/anthropic-auth-core",
3
- "version": "2.2.8",
3
+ "version": "2.4.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -30,7 +30,7 @@
30
30
  "prepublishOnly": "bun run build"
31
31
  },
32
32
  "devDependencies": {
33
- "@cortexkit/common-auth": "0.25.0"
33
+ "@cortexkit/common-auth": "0.28.0"
34
34
  },
35
35
  "dependencies": {
36
36
  "@cortexkit/claustrum-client": "0.12.0",