@fadhilp/stateql 0.10.0 → 0.10.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.
- package/README.md +9 -0
- package/dist/src/migrations.js +11 -0
- package/dist/src/stateql.js +4 -0
- package/dist/src/store.d.ts +3 -0
- package/dist/src/store.js +24 -0
- package/dist/src/types.d.ts +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -555,6 +555,15 @@ session-scoped, allocated atomically with the result, stable on cache reuse, and
|
|
|
555
555
|
cannot be reassigned by `setAlias`; explicit aliases and all old handles continue
|
|
556
556
|
to resolve.
|
|
557
557
|
|
|
558
|
+
Connections likewise retain canonical `conn_*` IDs and receive persistent random
|
|
559
|
+
10-character lowercase base32 aliases, exposed as `alias` and `display_alias` by
|
|
560
|
+
`connect()` and `snapshot().connection` (optional in snapshot types for older
|
|
561
|
+
producers). Connection aliases are unique within the state store, allocated
|
|
562
|
+
atomically with the connection, and backfilled for existing records on startup.
|
|
563
|
+
They survive reopening; reconnecting creates a new ID and alias. They are display
|
|
564
|
+
identities only, separate from result aliases; internal references and lookups
|
|
565
|
+
continue to use canonical connection IDs.
|
|
566
|
+
|
|
558
567
|
### Safe profile updates
|
|
559
568
|
|
|
560
569
|
```ts
|
package/dist/src/migrations.js
CHANGED
|
@@ -115,6 +115,17 @@ const MIGRATIONS = [
|
|
|
115
115
|
requireIndexes(db, ["history_session_category"]);
|
|
116
116
|
},
|
|
117
117
|
},
|
|
118
|
+
{
|
|
119
|
+
name: "connection_aliases_v1",
|
|
120
|
+
apply(db) {
|
|
121
|
+
addColumn(db, "connections", "alias", "TEXT");
|
|
122
|
+
db.exec("CREATE UNIQUE INDEX IF NOT EXISTS connections_alias ON connections(alias)");
|
|
123
|
+
},
|
|
124
|
+
validate(db) {
|
|
125
|
+
requireColumns(db, "connections", ["alias"]);
|
|
126
|
+
requireIndexes(db, ["connections_alias"]);
|
|
127
|
+
},
|
|
128
|
+
},
|
|
118
129
|
];
|
|
119
130
|
export function runMigrations(db, now) {
|
|
120
131
|
db.exec(`
|
package/dist/src/stateql.js
CHANGED
|
@@ -223,6 +223,8 @@ export class StateQL {
|
|
|
223
223
|
return {
|
|
224
224
|
data: {
|
|
225
225
|
connection_id: connection.id,
|
|
226
|
+
alias: connection.alias,
|
|
227
|
+
display_alias: connection.alias,
|
|
226
228
|
driver,
|
|
227
229
|
database: databaseName,
|
|
228
230
|
name: connection.name,
|
|
@@ -368,6 +370,8 @@ export class StateQL {
|
|
|
368
370
|
connection: connection
|
|
369
371
|
? {
|
|
370
372
|
connection_id: connection.id,
|
|
373
|
+
alias: connection.alias,
|
|
374
|
+
display_alias: connection.alias,
|
|
371
375
|
name: connection.name,
|
|
372
376
|
status: "connected",
|
|
373
377
|
driver: connection.driver,
|
package/dist/src/store.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export interface SessionRecord {
|
|
|
11
11
|
}
|
|
12
12
|
export interface ConnectionRecord {
|
|
13
13
|
id: string;
|
|
14
|
+
alias?: string;
|
|
14
15
|
session_id: string;
|
|
15
16
|
name: string;
|
|
16
17
|
driver: Driver;
|
|
@@ -166,6 +167,8 @@ export declare class StateStore {
|
|
|
166
167
|
credentialRef?: string;
|
|
167
168
|
readOnly: boolean;
|
|
168
169
|
}): ConnectionRecord | undefined;
|
|
170
|
+
private allocateConnectionAlias;
|
|
171
|
+
private backfillConnectionAliases;
|
|
169
172
|
getConnection(id: string): ConnectionRecord | undefined;
|
|
170
173
|
activeConnection(session: SessionRecord): ConnectionRecord | undefined;
|
|
171
174
|
disconnect(sessionId: string, actorId: string): boolean;
|
package/dist/src/store.js
CHANGED
|
@@ -36,6 +36,7 @@ export class StateStore {
|
|
|
36
36
|
this.db.exec("PRAGMA busy_timeout = 5000");
|
|
37
37
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
38
38
|
runMigrations(this.db, this.now);
|
|
39
|
+
this.backfillConnectionAliases();
|
|
39
40
|
this.backfillGeneratedAliases();
|
|
40
41
|
this.recoverStaleCommittingTransactions();
|
|
41
42
|
this.deleteExpiredData();
|
|
@@ -285,6 +286,7 @@ export class StateStore {
|
|
|
285
286
|
credential_ref, read_only, version, created_at)
|
|
286
287
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?)`)
|
|
287
288
|
.run(id, input.sessionId, input.name, input.driver, input.databaseName, input.source, input.secretEnv ?? null, input.credentialRef ?? null, input.readOnly ? 1 : 0, timestamp);
|
|
289
|
+
this.allocateConnectionAlias(id);
|
|
288
290
|
this.db
|
|
289
291
|
.prepare(`UPDATE sessions
|
|
290
292
|
SET active_connection_id = ?, updated_at = ?
|
|
@@ -298,6 +300,28 @@ export class StateStore {
|
|
|
298
300
|
throw error;
|
|
299
301
|
}
|
|
300
302
|
}
|
|
303
|
+
allocateConnectionAlias(connectionId) {
|
|
304
|
+
for (let attempt = 0; attempt < 64; attempt++) {
|
|
305
|
+
this.db.prepare("UPDATE OR IGNORE connections SET alias = ? WHERE id = ? AND alias IS NULL").run(randomBase32Alias(), connectionId);
|
|
306
|
+
const connection = this.getConnection(connectionId);
|
|
307
|
+
if (connection?.alias)
|
|
308
|
+
return connection.alias;
|
|
309
|
+
}
|
|
310
|
+
throw new Error("Could not allocate a unique connection alias.");
|
|
311
|
+
}
|
|
312
|
+
backfillConnectionAliases() {
|
|
313
|
+
this.db.exec("BEGIN IMMEDIATE");
|
|
314
|
+
try {
|
|
315
|
+
const connections = this.db.prepare("SELECT id FROM connections WHERE alias IS NULL").all();
|
|
316
|
+
for (const connection of connections)
|
|
317
|
+
this.allocateConnectionAlias(connection.id);
|
|
318
|
+
this.db.exec("COMMIT");
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
this.db.exec("ROLLBACK");
|
|
322
|
+
throw error;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
301
325
|
getConnection(id) {
|
|
302
326
|
return this.db
|
|
303
327
|
.prepare("SELECT * FROM connections WHERE id = ?")
|
package/dist/src/types.d.ts
CHANGED
|
@@ -106,6 +106,9 @@ export interface StateQLSnapshot {
|
|
|
106
106
|
actor_id: string;
|
|
107
107
|
connection: {
|
|
108
108
|
connection_id: string;
|
|
109
|
+
/** Generated display identity; optional for older snapshot producers. */
|
|
110
|
+
alias?: string;
|
|
111
|
+
display_alias?: string;
|
|
109
112
|
name: string;
|
|
110
113
|
status: "connected";
|
|
111
114
|
driver: Driver;
|
|
@@ -379,6 +382,9 @@ export type Row = Record<string, unknown>;
|
|
|
379
382
|
/** Data returned by the stable, non-dynamic StateQL public methods. */
|
|
380
383
|
export interface ConnectionData {
|
|
381
384
|
connection_id: string;
|
|
385
|
+
/** Persistent generated display identity; connection_id remains canonical. */
|
|
386
|
+
alias: string;
|
|
387
|
+
display_alias: string;
|
|
382
388
|
driver: Driver;
|
|
383
389
|
database: string;
|
|
384
390
|
name: string;
|