@fadhilp/stateql 0.10.1 → 0.11.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.
@@ -5,7 +5,7 @@ import { writeFileSync } from "node:fs";
5
5
  import { basename, resolve } from "node:path";
6
6
  import { env } from "node:process";
7
7
  import { AdapterExecutionError, AdapterWriteError, BatchWriteError, createAdapter, createAdapterContext, } from "./adapters.js";
8
- import { confidence, credentialSource, databaseIdentity, databaseUrlHasSecret, detectDriver, isEnvironmentName, mongoDatabaseName, redisDatabaseName, normalizeSqliteSource, validateCredentialRef, validateProfileName, version, } from "./connection.js";
8
+ import { confidence, credentialSource, databaseIdentity, databaseUrlHasSecret, detectDriver, isEnvironmentName, injectPassword, mongoDatabaseName, redisDatabaseName, normalizeSqliteSource, validateCredentialRef, validatePasswordReferenceTarget, validateProfileName, version, } from "./connection.js";
9
9
  import { asStateQLError, CredentialResolutionError, StateQLError, } from "./errors.js";
10
10
  import { analyzeMongoWriteSafety, deserializeMongoWriteCommand, serializeMongoCommand, validateMongoReadCommand, validateMongoWriteCommand, MongoAdapter, } from "./mongodb.js";
11
11
  import { deserializeRedisCommand, RedisAdapter, serializeRedisCommand, validateRedisReadCommand, validateRedisWriteCommand, } from "./redis.js";
@@ -18,6 +18,8 @@ const DEFAULT_SNAPSHOT_HISTORY_LIMIT = 50;
18
18
  const MAX_SNAPSHOT_HISTORY_LIMIT = 100;
19
19
  const DEFAULT_CREDENTIAL_RESOLUTION_TIMEOUT_MS = 120_000;
20
20
  export class StateQL {
21
+ /** Runtime contract marker for passwordRef/password_ref support. */
22
+ static passwordReferenceVersion = 1;
21
23
  static forActor(options) {
22
24
  if (!options.actor.trim()) {
23
25
  throw new StateQLError("INVALID_COMMAND", "Actor ID is required.");
@@ -112,7 +114,13 @@ export class StateQL {
112
114
  if (sourceCount !== 1) {
113
115
  throw new StateQLError("INVALID_COMMAND", "Use exactly one connection target, profile, secret environment variable, or credential reference.");
114
116
  }
115
- const implicitProfile = !options.profile && !options.secretEnv && !options.credentialRef && target
117
+ if (options.passwordRef !== undefined &&
118
+ (target === undefined || options.profile !== undefined ||
119
+ options.secretEnv !== undefined || options.credentialRef !== undefined)) {
120
+ throw new StateQLError("INVALID_COMMAND", "A password reference requires a literal remote connection target.");
121
+ }
122
+ const implicitProfile = !options.profile && !options.secretEnv && !options.credentialRef &&
123
+ options.passwordRef === undefined && target
116
124
  ? this.store.getProfile(target)
117
125
  : undefined;
118
126
  const profile = options.profile
@@ -122,18 +130,27 @@ export class StateQL {
122
130
  throw new StateQLError("CONNECTION_NOT_FOUND", `Profile "${options.profile}" was not found.`, { suggestedAction: "Run stql profile list." });
123
131
  }
124
132
  if (profile &&
125
- [profile.target, profile.secret_env, profile.credential_ref]
126
- .filter((value) => value !== null).length !== 1) {
127
- throw new StateQLError("STATE_CORRUPTED", `Profile "${profile.name}" does not have exactly one connection source.`);
133
+ ([profile.target, profile.secret_env, profile.credential_ref]
134
+ .filter((value) => value !== null).length !== 1 ||
135
+ (profile.password_ref !== null && profile.target === null))) {
136
+ throw new StateQLError("STATE_CORRUPTED", `Profile "${profile.name}" has an invalid connection source.`);
128
137
  }
129
138
  const resolvedTarget = profile?.target ?? target;
130
139
  const secretEnv = options.secretEnv ?? profile?.secret_env ?? undefined;
131
140
  const credentialRef = options.credentialRef ?? profile?.credential_ref ?? undefined;
141
+ const passwordRef = options.passwordRef ?? profile?.password_ref ?? undefined;
132
142
  if (secretEnv !== undefined && !isEnvironmentName(secretEnv)) {
133
143
  throw new StateQLError("INVALID_COMMAND", "Secret environment variable name is invalid.");
134
144
  }
135
145
  if (credentialRef !== undefined)
136
146
  validateCredentialRef(credentialRef);
147
+ if (passwordRef !== undefined) {
148
+ validateCredentialRef(passwordRef);
149
+ if (!resolvedTarget) {
150
+ throw new StateQLError("INVALID_COMMAND", "A password reference requires a literal remote connection target.");
151
+ }
152
+ validatePasswordReferenceTarget(resolvedTarget);
153
+ }
137
154
  const credentialReference = secretEnv ?? credentialRef;
138
155
  const credentialReferenceSource = secretEnv !== undefined
139
156
  ? "secret_env"
@@ -141,50 +158,65 @@ export class StateQL {
141
158
  const readOnly = options.readOnly ??
142
159
  (profile ? Boolean(profile.read_only) : true);
143
160
  const context = this.executionContext(options);
144
- const secret = credentialReference && credentialReferenceSource
145
- ? await this.resolveCredential(credentialReference, credentialReferenceSource, session, "connect", readOnly ? "read" : "write", context, {
161
+ let adapterSource;
162
+ let driver;
163
+ if (passwordRef !== undefined) {
164
+ const password = await this.resolveCredential(passwordRef, "password_ref", session, "connect", readOnly ? "read" : "write", context, {
146
165
  ...(profile ? { profile: { name: profile.name } } : {}),
147
166
  requestedReadOnly: readOnly,
148
- })
149
- : resolvedTarget;
150
- if (!secret) {
151
- throw new StateQLError("INVALID_COMMAND", "Connection target is required.");
152
- }
153
- const resolvedSource = credentialReferenceSource
154
- ? credentialSource(secret, undefined, credentialReferenceSource)
155
- : { driver: detectDriver(secret), source: secret };
156
- const { driver } = resolvedSource;
157
- if (driver !== "sqlite" &&
158
- !credentialReference &&
159
- databaseUrlHasSecret(secret)) {
160
- throw new StateQLError("PERMISSION_DENIED", `Credential-bearing ${databaseDisplayName(driver)} URLs must use --env or --credential-ref.`, {
161
- suggestedAction: "Use an environment variable or trusted host credential reference.",
162
- });
167
+ }, resolvedTarget);
168
+ ({ driver, source: adapterSource } = injectPassword(resolvedTarget, password));
163
169
  }
164
- const adapterSource = credentialReferenceSource
165
- ? resolvedSource.source
166
- : driver === "sqlite" ? normalizeSqliteSource(secret) : secret;
167
- const source = driver === "sqlite"
168
- ? adapterSource
169
- : credentialReferenceSource
170
- ? redact(secret)
171
- : adapterSource;
170
+ else {
171
+ const secret = credentialReference && credentialReferenceSource
172
+ ? await this.resolveCredential(credentialReference, credentialReferenceSource, session, "connect", readOnly ? "read" : "write", context, {
173
+ ...(profile ? { profile: { name: profile.name } } : {}),
174
+ requestedReadOnly: readOnly,
175
+ })
176
+ : resolvedTarget;
177
+ if (!secret) {
178
+ throw new StateQLError("INVALID_COMMAND", "Connection target is required.");
179
+ }
180
+ const resolvedSource = credentialReferenceSource
181
+ ? credentialSource(secret, undefined, credentialReferenceSource)
182
+ : { driver: detectDriver(secret), source: secret };
183
+ driver = resolvedSource.driver;
184
+ if (driver !== "sqlite" &&
185
+ !credentialReference &&
186
+ databaseUrlHasSecret(secret)) {
187
+ throw new StateQLError("PERMISSION_DENIED", `Credential-bearing ${databaseDisplayName(driver)} URLs must use --env or --credential-ref.`, {
188
+ suggestedAction: "Use an environment variable or trusted host credential reference.",
189
+ });
190
+ }
191
+ adapterSource = credentialReferenceSource
192
+ ? resolvedSource.source
193
+ : driver === "sqlite" ? normalizeSqliteSource(secret) : secret;
194
+ }
195
+ const persistedSource = passwordRef !== undefined
196
+ ? resolvedTarget
197
+ : driver === "sqlite"
198
+ ? adapterSource
199
+ : credentialReferenceSource
200
+ ? redact(adapterSource)
201
+ : adapterSource;
202
+ const identitySource = passwordRef !== undefined ? resolvedTarget : adapterSource;
172
203
  const databaseName = driver === "sqlite"
173
204
  ? basename(adapterSource)
174
205
  : driver === "mongodb"
175
- ? mongoDatabaseName(adapterSource)
206
+ ? mongoDatabaseName(identitySource)
176
207
  : driver === "redis"
177
- ? redisDatabaseName(adapterSource)
178
- : new URL(secret).pathname.replace(/^\//, "") || driver;
208
+ ? redisDatabaseName(identitySource)
209
+ : new URL(identitySource).pathname.replace(/^\//, "") || driver;
179
210
  const draft = {
180
211
  id: "pending",
181
212
  session_id: session.id,
182
213
  name: options.name ?? profile?.name ?? databaseName,
183
214
  driver,
184
215
  database_name: databaseName,
185
- source,
216
+ source: persistedSource,
186
217
  secret_env: secretEnv ?? null,
187
218
  credential_ref: credentialRef ?? null,
219
+ password_ref: passwordRef ?? null,
188
220
  read_only: readOnly ? 1 : 0,
189
221
  version: 0,
190
222
  created_at: this.now().toISOString(),
@@ -212,9 +244,10 @@ export class StateQL {
212
244
  name: draft.name,
213
245
  driver,
214
246
  databaseName,
215
- source,
247
+ source: persistedSource,
216
248
  ...(secretEnv ? { secretEnv } : {}),
217
249
  ...(credentialRef ? { credentialRef } : {}),
250
+ ...(passwordRef !== undefined ? { passwordRef } : {}),
218
251
  readOnly,
219
252
  });
220
253
  if (!connection) {
@@ -250,12 +283,14 @@ export class StateQL {
250
283
  target,
251
284
  secretEnv: options.secretEnv,
252
285
  credentialRef: options.credentialRef,
286
+ passwordRef: options.passwordRef,
253
287
  });
254
288
  const profile = this.store.addProfile({
255
289
  name,
256
290
  target: source.target ?? undefined,
257
291
  secretEnv: source.secretEnv ?? undefined,
258
292
  credentialRef: source.credentialRef ?? undefined,
293
+ passwordRef: source.passwordRef ?? undefined,
259
294
  readOnly: options.readOnly ?? true,
260
295
  });
261
296
  return {
@@ -272,22 +307,32 @@ export class StateQL {
272
307
  if (!existing)
273
308
  throw new StateQLError("CONNECTION_NOT_FOUND", `Profile "${name}" was not found.`);
274
309
  if (!changes || typeof changes !== "object" || Array.isArray(changes) ||
275
- Object.keys(changes).some((key) => !["target", "secretEnv", "credentialRef", "readOnly"].includes(key))) {
310
+ Object.keys(changes).some((key) => !["target", "secretEnv", "credentialRef", "passwordRef", "readOnly"].includes(key))) {
276
311
  throw new StateQLError("INVALID_COMMAND", "Profile update contains unknown fields.");
277
312
  }
278
313
  if (changes.readOnly !== undefined && typeof changes.readOnly !== "boolean")
279
314
  throw new StateQLError("INVALID_COMMAND", "Profile readOnly must be boolean.");
280
315
  const changesSource = Object.hasOwn(changes, "target") || Object.hasOwn(changes, "secretEnv") || Object.hasOwn(changes, "credentialRef");
281
- if (!changesSource && changes.readOnly === undefined)
316
+ const changesPassword = Object.hasOwn(changes, "passwordRef");
317
+ if (!changesSource && !changesPassword && changes.readOnly === undefined)
282
318
  throw new StateQLError("INVALID_COMMAND", "Profile update has no changes.");
283
- const source = changesSource
284
- ? validatedProfileSource({ target: changes.target ?? undefined, secretEnv: changes.secretEnv ?? undefined, credentialRef: changes.credentialRef ?? undefined })
285
- : { target: existing.target, secretEnv: existing.secret_env, credentialRef: existing.credential_ref };
319
+ const targetSource = changesSource ? changes.target ?? undefined : existing.target ?? undefined;
320
+ const source = validatedProfileSource({
321
+ target: targetSource,
322
+ secretEnv: changesSource ? changes.secretEnv ?? undefined : existing.secret_env ?? undefined,
323
+ credentialRef: changesSource ? changes.credentialRef ?? undefined : existing.credential_ref ?? undefined,
324
+ passwordRef: changesPassword
325
+ ? changes.passwordRef ?? undefined
326
+ : !changesSource || targetSource === existing.target
327
+ ? existing.password_ref ?? undefined
328
+ : undefined,
329
+ });
286
330
  const profile = this.store.updateProfile({
287
331
  name,
288
332
  target: source.target,
289
333
  secretEnv: source.secretEnv,
290
334
  credentialRef: source.credentialRef,
335
+ passwordRef: source.passwordRef,
291
336
  readOnly: changes.readOnly ?? Boolean(existing.read_only),
292
337
  });
293
338
  if (!profile)
@@ -1711,7 +1756,7 @@ export class StateQL {
1711
1756
  const planParameters = compiled?.params ?? (nativePlan || tableUpdates
1712
1757
  ? undefined
1713
1758
  : parseJson(plan.parameters, `plan "${plan.id}" parameters`, isSqlParameters));
1714
- const claimToken = this.store.nextId("claim");
1759
+ const claimToken = this.store.randomId("claim");
1715
1760
  const claimed = this.store.claimPlan(plan.id, session.id, this.actorId, claimToken);
1716
1761
  if (!claimed) {
1717
1762
  throw new StateQLError("STALE_PLAN", "Plan is already being applied.");
@@ -1900,6 +1945,7 @@ export class StateQL {
1900
1945
  readOnly: command.read_only,
1901
1946
  secretEnv: command.secret_env,
1902
1947
  credentialRef: command.credential_ref,
1948
+ passwordRef: command.password_ref ?? undefined,
1903
1949
  profile: command.profile,
1904
1950
  timeoutMs: command.timeout_ms,
1905
1951
  });
@@ -1912,12 +1958,14 @@ export class StateQL {
1912
1958
  readOnly: command.read_only ?? true,
1913
1959
  secretEnv: command.secret_env,
1914
1960
  credentialRef: command.credential_ref,
1961
+ passwordRef: command.password_ref ?? undefined,
1915
1962
  });
1916
1963
  case "profile.update":
1917
1964
  return this.updateProfile(batchString(command.name, "name"), {
1918
1965
  ...(command.target !== undefined ? { target: command.target } : {}),
1919
1966
  ...(command.secret_env !== undefined ? { secretEnv: command.secret_env } : {}),
1920
1967
  ...(command.credential_ref !== undefined ? { credentialRef: command.credential_ref } : {}),
1968
+ ...(command.password_ref !== undefined ? { passwordRef: command.password_ref } : {}),
1921
1969
  ...(command.read_only !== undefined ? { readOnly: command.read_only } : {}),
1922
1970
  });
1923
1971
  case "profile.list":
@@ -2718,6 +2766,28 @@ export class StateQL {
2718
2766
  throw new StateQLError("PERMISSION_DENIED", `Actor "${this.actorId}" is not attached to session "${session.name}".`);
2719
2767
  }
2720
2768
  async resolveConnectionSource(connection, session, operation, access, context) {
2769
+ const references = [connection.secret_env, connection.credential_ref, connection.password_ref]
2770
+ .filter((value) => value !== null);
2771
+ if (references.length > 1) {
2772
+ throw new StateQLError("STATE_CORRUPTED", "Connection has ambiguous credential references.");
2773
+ }
2774
+ if (connection.password_ref !== null) {
2775
+ validateCredentialRef(connection.password_ref);
2776
+ const driver = validatePasswordReferenceTarget(connection.source);
2777
+ if (driver !== connection.driver) {
2778
+ throw new StateQLError("STATE_CORRUPTED", "Password-reference target driver does not match the stored connection.");
2779
+ }
2780
+ const password = await this.resolveCredential(connection.password_ref, "password_ref", session, operation, access, context, {
2781
+ connection: {
2782
+ id: connection.id,
2783
+ name: connection.name,
2784
+ driver: connection.driver,
2785
+ database: connection.database_name,
2786
+ readOnly: Boolean(connection.read_only),
2787
+ },
2788
+ }, connection.source);
2789
+ return injectPassword(connection.source, password).source;
2790
+ }
2721
2791
  const reference = connection.secret_env ?? connection.credential_ref;
2722
2792
  if (!reference)
2723
2793
  return connection.source;
@@ -2735,7 +2805,7 @@ export class StateQL {
2735
2805
  });
2736
2806
  return credentialSource(value, connection.driver, source).source;
2737
2807
  }
2738
- async resolveCredential(reference, source, session, operation, access, context, details = {}) {
2808
+ async resolveCredential(reference, source, session, operation, access, context, details = {}, passwordTarget) {
2739
2809
  const resolver = this.credentialResolver;
2740
2810
  const credentialContext = createAdapterContext(this.credentialTimeoutMs, context.signal);
2741
2811
  let value;
@@ -2750,9 +2820,8 @@ export class StateQL {
2750
2820
  value = env[reference];
2751
2821
  }
2752
2822
  else {
2753
- const request = {
2823
+ const baseRequest = {
2754
2824
  reference,
2755
- source,
2756
2825
  actorId: this.actorId,
2757
2826
  session: { id: session.id, name: session.name },
2758
2827
  operation,
@@ -2760,6 +2829,9 @@ export class StateQL {
2760
2829
  ...(context.signal ? { signal: context.signal } : {}),
2761
2830
  ...details,
2762
2831
  };
2832
+ const request = source === "password_ref"
2833
+ ? { ...baseRequest, source, target: passwordTarget }
2834
+ : { ...baseRequest, source };
2763
2835
  try {
2764
2836
  value = await resolveCredentialBeforeDeadline(resolver, request, credentialContext);
2765
2837
  }
@@ -2767,7 +2839,7 @@ export class StateQL {
2767
2839
  throw credentialStateQLError(reference, error);
2768
2840
  }
2769
2841
  }
2770
- if (!value) {
2842
+ if (value === undefined || (source !== "password_ref" && value === "")) {
2771
2843
  throw credentialStateQLError(reference, new CredentialResolutionError("unavailable"));
2772
2844
  }
2773
2845
  context.deadline = Date.now() + (context.timeoutMs ?? this.timeoutMs);
@@ -2844,8 +2916,8 @@ export class StateQL {
2844
2916
  const category = historyCategory(command);
2845
2917
  const internal = commandContext?.internal ?? false;
2846
2918
  let session = this.store.ensureSession(this.sessionName);
2847
- const commandId = this.store.nextId("cmd");
2848
2919
  if (!this.store.isSessionMember(session.id, this.actorId)) {
2920
+ const commandId = this.store.randomId("cmd");
2849
2921
  const error = new StateQLError("PERMISSION_DENIED", `Actor "${this.actorId}" is not attached to session "${session.name}".`);
2850
2922
  return {
2851
2923
  ok: false,
@@ -2861,8 +2933,7 @@ export class StateQL {
2861
2933
  const result = await action(session);
2862
2934
  const responseSession = result.session ?? session;
2863
2935
  const sqlText = resolveHistorySql(historySql);
2864
- this.store.addHistory({
2865
- id: commandId,
2936
+ const history = this.store.addHistory({
2866
2937
  sessionId: session.id,
2867
2938
  actorId: this.actorId,
2868
2939
  origin,
@@ -2878,7 +2949,7 @@ export class StateQL {
2878
2949
  });
2879
2950
  return {
2880
2951
  ok: true,
2881
- command_id: commandId,
2952
+ command_id: history.id,
2882
2953
  session_id: responseSession.id,
2883
2954
  data: result.data,
2884
2955
  warnings: result.warnings ?? [],
@@ -2896,8 +2967,7 @@ export class StateQL {
2896
2967
  catch (error) {
2897
2968
  const stateqlError = asStateQLError(error);
2898
2969
  const sqlText = resolveHistorySql(historySql);
2899
- this.store.addHistory({
2900
- id: commandId,
2970
+ const history = this.store.addHistory({
2901
2971
  sessionId: session.id,
2902
2972
  actorId: this.actorId,
2903
2973
  origin,
@@ -2913,7 +2983,7 @@ export class StateQL {
2913
2983
  });
2914
2984
  return {
2915
2985
  ok: false,
2916
- command_id: commandId,
2986
+ command_id: history.id,
2917
2987
  session_id: session.id,
2918
2988
  error: stateqlError.details,
2919
2989
  meta: {
@@ -3214,7 +3284,23 @@ function credentialStateQLError(reference, error) {
3214
3284
  return new StateQLError("CREDENTIAL_RESOLUTION_FAILED", `Credential reference "${reference}" could not be resolved.`, { retryable: true });
3215
3285
  }
3216
3286
  function safeCredentialErrorMessage(error, source) {
3217
- return redact(errorMessage(error).split(source).join("[credential redacted]"))
3287
+ let message = errorMessage(error).split(source).join("[credential redacted]");
3288
+ const authority = /^[a-z][a-z\d+.-]*:\/\/([^/?#]*)/i.exec(source)?.[1];
3289
+ if (authority) {
3290
+ const at = authority.lastIndexOf("@");
3291
+ const colon = at < 0 ? -1 : authority.slice(0, at).indexOf(":");
3292
+ const password = colon < 0 ? "" : authority.slice(colon + 1, at);
3293
+ const secrets = new Set([password]);
3294
+ try {
3295
+ secrets.add(decodeURIComponent(password));
3296
+ }
3297
+ catch { /* malformed values stay encoded */ }
3298
+ for (const secret of secrets) {
3299
+ if (secret)
3300
+ message = message.split(secret).join("[credential redacted]");
3301
+ }
3302
+ }
3303
+ return redact(message)
3218
3304
  .replace(/\b([a-z][a-z0-9+.-]*:\/\/)[^\s\/@]+(?::[^\s\/@]*)?@/giu, "$1***@");
3219
3305
  }
3220
3306
  function executionTimeout(value, name = "timeoutMs") {
@@ -3236,15 +3322,27 @@ function validatedProfileSource(input) {
3236
3322
  throw new StateQLError("INVALID_COMMAND", "Secret environment variable name is invalid.");
3237
3323
  if (input.credentialRef !== undefined)
3238
3324
  validateCredentialRef(input.credentialRef);
3325
+ if (input.passwordRef !== undefined)
3326
+ validateCredentialRef(input.passwordRef);
3239
3327
  let target = input.target ?? null;
3328
+ if (input.passwordRef !== undefined && target === null) {
3329
+ throw new StateQLError("INVALID_COMMAND", "A password reference requires a literal remote profile target.");
3330
+ }
3240
3331
  if (target) {
3241
- const driver = detectDriver(target);
3242
- if (driver !== "sqlite" && databaseUrlHasSecret(target))
3332
+ const driver = input.passwordRef !== undefined
3333
+ ? validatePasswordReferenceTarget(target)
3334
+ : detectDriver(target);
3335
+ if (input.passwordRef === undefined && driver !== "sqlite" && databaseUrlHasSecret(target))
3243
3336
  throw new StateQLError("PERMISSION_DENIED", `Credential-bearing ${databaseDisplayName(driver)} URLs must use --env or --credential-ref.`);
3244
3337
  if (driver === "sqlite")
3245
3338
  target = normalizeSqliteSource(target);
3246
3339
  }
3247
- return { target, secretEnv: input.secretEnv ?? null, credentialRef: input.credentialRef ?? null };
3340
+ return {
3341
+ target,
3342
+ secretEnv: input.secretEnv ?? null,
3343
+ credentialRef: input.credentialRef ?? null,
3344
+ passwordRef: input.passwordRef ?? null,
3345
+ };
3248
3346
  }
3249
3347
  function historyCategory(command) {
3250
3348
  if (["query", "exec", "plan", "apply", "mongo.query", "mongo.exec", "mongo.plan", "redis.query", "redis.exec", "redis.plan", "filter"].includes(command))
@@ -19,6 +19,7 @@ export interface ConnectionRecord {
19
19
  source: string;
20
20
  secret_env: string | null;
21
21
  credential_ref: string | null;
22
+ password_ref: string | null;
22
23
  read_only: number;
23
24
  version: number;
24
25
  created_at: string;
@@ -28,6 +29,7 @@ export interface ProfileRecord {
28
29
  target: string | null;
29
30
  secret_env: string | null;
30
31
  credential_ref: string | null;
32
+ password_ref: string | null;
31
33
  read_only: number;
32
34
  created_at: string;
33
35
  updated_at: string;
@@ -126,7 +128,8 @@ export declare class StateStore {
126
128
  private closed;
127
129
  constructor(home: string, now: () => Date, maxStateBytes?: number);
128
130
  close(): void;
129
- nextId(prefix: string): string;
131
+ randomId(prefix: string): string;
132
+ private insertWithRandomId;
130
133
  ensureSession(name?: string): SessionRecord;
131
134
  bootstrapSession(name: string, actorId: string, ensureLegacyMembership: boolean): SessionRecord;
132
135
  createSession(name: string): SessionRecord;
@@ -144,6 +147,7 @@ export declare class StateStore {
144
147
  target?: string;
145
148
  secretEnv?: string;
146
149
  credentialRef?: string;
150
+ passwordRef?: string;
147
151
  readOnly: boolean;
148
152
  }): ProfileRecord;
149
153
  updateProfile(input: {
@@ -151,6 +155,7 @@ export declare class StateStore {
151
155
  target: string | null;
152
156
  secretEnv: string | null;
153
157
  credentialRef: string | null;
158
+ passwordRef: string | null;
154
159
  readOnly: boolean;
155
160
  }): ProfileRecord | undefined;
156
161
  getProfile(name: string): ProfileRecord | undefined;
@@ -165,6 +170,7 @@ export declare class StateStore {
165
170
  source: string;
166
171
  secretEnv?: string;
167
172
  credentialRef?: string;
173
+ passwordRef?: string;
168
174
  readOnly: boolean;
169
175
  }): ConnectionRecord | undefined;
170
176
  private allocateConnectionAlias;