@arcblock/did-connect-service 4.1.10 → 4.1.12

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 (50) hide show
  1. package/dist/_generated/asset-bytes.js +1 -1
  2. package/dist/_generated/asset-manifest.js +2 -2
  3. package/dist/assets/admin-core.cbbdbe6d.js +1465 -0
  4. package/dist/assets/admin-extra.35b91f98.js +2543 -0
  5. package/dist/blocklet-service-rpc.js +5 -5
  6. package/dist/blocklet-service-rpc.js.map +1 -1
  7. package/dist/blocklet-service.js +5 -5
  8. package/dist/blocklet-service.js.map +1 -1
  9. package/dist/env-config.d.ts +6 -3
  10. package/dist/env-config.d.ts.map +1 -1
  11. package/dist/env-config.js +21 -4
  12. package/dist/env-config.js.map +1 -1
  13. package/dist/handlers/avatar-handler.d.ts +9 -1
  14. package/dist/handlers/avatar-handler.d.ts.map +1 -1
  15. package/dist/handlers/avatar-handler.js +22 -6
  16. package/dist/handlers/avatar-handler.js.map +1 -1
  17. package/dist/handlers/did-connect-handler.d.ts.map +1 -1
  18. package/dist/handlers/did-connect-handler.js +9 -0
  19. package/dist/handlers/did-connect-handler.js.map +1 -1
  20. package/dist/handlers/email-login-handler.d.ts.map +1 -1
  21. package/dist/handlers/email-login-handler.js +9 -0
  22. package/dist/handlers/email-login-handler.js.map +1 -1
  23. package/dist/handlers/team-handler.d.ts.map +1 -1
  24. package/dist/handlers/team-handler.js +6 -3
  25. package/dist/handlers/team-handler.js.map +1 -1
  26. package/dist/og/ssrf-guard.d.ts.map +1 -1
  27. package/dist/og/ssrf-guard.js +21 -3
  28. package/dist/og/ssrf-guard.js.map +1 -1
  29. package/dist/pages/admin/scripts/utils.d.ts +1 -1
  30. package/dist/pages/admin/scripts/utils.d.ts.map +1 -1
  31. package/dist/pages/admin/scripts/utils.js +5 -1
  32. package/dist/pages/admin/scripts/utils.js.map +1 -1
  33. package/dist/pages/admin/tab-appearance.js +1 -1
  34. package/dist/pages/admin/tab-members.d.ts +1 -1
  35. package/dist/pages/admin/tab-members.d.ts.map +1 -1
  36. package/dist/pages/admin/tab-members.js +16 -6
  37. package/dist/pages/admin/tab-members.js.map +1 -1
  38. package/dist/pages/admin/tab-settings.d.ts.map +1 -1
  39. package/dist/pages/admin/tab-settings.js +4 -1
  40. package/dist/pages/admin/tab-settings.js.map +1 -1
  41. package/dist/pages/admin-instances-page.d.ts.map +1 -1
  42. package/dist/pages/admin-instances-page.js +13 -3
  43. package/dist/pages/admin-instances-page.js.map +1 -1
  44. package/dist/store/d1-store.d.ts.map +1 -1
  45. package/dist/store/d1-store.js +252 -214
  46. package/dist/store/d1-store.js.map +1 -1
  47. package/dist/store/d1-token-storage.js +7 -7
  48. package/dist/store/d1-token-storage.js.map +1 -1
  49. package/migrations/0010_rename_tables.sql +31 -0
  50. package/package.json +3 -3
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { dbToAccessType, invalidateRegexCache } from "../access/access-policy.js";
8
8
  const SCHEMA_SQL = `
9
- CREATE TABLE IF NOT EXISTS users (
9
+ CREATE TABLE IF NOT EXISTS cs_users (
10
10
  did TEXT PRIMARY KEY,
11
11
  pk TEXT NOT NULL DEFAULT '',
12
12
  fullName TEXT,
@@ -40,10 +40,10 @@ CREATE TABLE IF NOT EXISTS users (
40
40
  updatedBy TEXT
41
41
  );
42
42
 
43
- CREATE TABLE IF NOT EXISTS connected_accounts (
43
+ CREATE TABLE IF NOT EXISTS cs_connected_accounts (
44
44
  did TEXT PRIMARY KEY,
45
45
  pk TEXT,
46
- userDid TEXT REFERENCES users(did),
46
+ userDid TEXT REFERENCES cs_users(did),
47
47
  provider TEXT NOT NULL,
48
48
  id TEXT,
49
49
  firstLoginAt TEXT,
@@ -58,14 +58,14 @@ CREATE TABLE IF NOT EXISTS connected_accounts (
58
58
  updatedBy TEXT
59
59
  );
60
60
 
61
- CREATE TABLE IF NOT EXISTS challenges (
61
+ CREATE TABLE IF NOT EXISTS cs_challenges (
62
62
  id TEXT PRIMARY KEY,
63
63
  challenge TEXT NOT NULL,
64
64
  invitationId TEXT,
65
65
  createdAt TEXT DEFAULT (datetime('now'))
66
66
  );
67
67
 
68
- CREATE TABLE IF NOT EXISTS invitations (
68
+ CREATE TABLE IF NOT EXISTS cs_invitations (
69
69
  id TEXT PRIMARY KEY,
70
70
  teamDid TEXT NOT NULL,
71
71
  role TEXT NOT NULL,
@@ -81,7 +81,7 @@ CREATE TABLE IF NOT EXISTS invitations (
81
81
  updatedBy TEXT
82
82
  );
83
83
 
84
- CREATE TABLE IF NOT EXISTS audit_logs (
84
+ CREATE TABLE IF NOT EXISTS cs_audit_logs (
85
85
  id INTEGER PRIMARY KEY AUTOINCREMENT,
86
86
  action TEXT NOT NULL,
87
87
  operatorDid TEXT NOT NULL,
@@ -91,20 +91,20 @@ CREATE TABLE IF NOT EXISTS audit_logs (
91
91
  createdAt TEXT DEFAULT (datetime('now'))
92
92
  );
93
93
 
94
- CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
95
- CREATE INDEX IF NOT EXISTS idx_users_pk ON users(pk);
96
- CREATE INDEX IF NOT EXISTS idx_users_createdAt ON users(createdAt);
97
- CREATE INDEX IF NOT EXISTS idx_connected_accounts_userDid ON connected_accounts(userDid);
98
- CREATE INDEX IF NOT EXISTS idx_connected_accounts_pk ON connected_accounts(pk);
99
- CREATE INDEX IF NOT EXISTS idx_invitations_status ON invitations(status);
100
- CREATE INDEX IF NOT EXISTS idx_invitations_expireAt ON invitations(expireAt);
101
- CREATE INDEX IF NOT EXISTS idx_audit_logs_action ON audit_logs(action);
102
- CREATE INDEX IF NOT EXISTS idx_audit_logs_operatorDid ON audit_logs(operatorDid);
103
- CREATE INDEX IF NOT EXISTS idx_audit_logs_createdAt ON audit_logs(createdAt);
104
- CREATE INDEX IF NOT EXISTS idx_audit_logs_targetDid ON audit_logs(targetDid);
105
- CREATE INDEX IF NOT EXISTS idx_audit_logs_ip ON audit_logs(ip);
94
+ CREATE INDEX IF NOT EXISTS idx_users_email ON cs_users(email);
95
+ CREATE INDEX IF NOT EXISTS idx_users_pk ON cs_users(pk);
96
+ CREATE INDEX IF NOT EXISTS idx_users_createdAt ON cs_users(createdAt);
97
+ CREATE INDEX IF NOT EXISTS idx_connected_accounts_userDid ON cs_connected_accounts(userDid);
98
+ CREATE INDEX IF NOT EXISTS idx_connected_accounts_pk ON cs_connected_accounts(pk);
99
+ CREATE INDEX IF NOT EXISTS idx_invitations_status ON cs_invitations(status);
100
+ CREATE INDEX IF NOT EXISTS idx_invitations_expireAt ON cs_invitations(expireAt);
101
+ CREATE INDEX IF NOT EXISTS idx_audit_logs_action ON cs_audit_logs(action);
102
+ CREATE INDEX IF NOT EXISTS idx_audit_logs_operatorDid ON cs_audit_logs(operatorDid);
103
+ CREATE INDEX IF NOT EXISTS idx_audit_logs_createdAt ON cs_audit_logs(createdAt);
104
+ CREATE INDEX IF NOT EXISTS idx_audit_logs_targetDid ON cs_audit_logs(targetDid);
105
+ CREATE INDEX IF NOT EXISTS idx_audit_logs_ip ON cs_audit_logs(ip);
106
106
 
107
- CREATE TABLE IF NOT EXISTS access_policies (
107
+ CREATE TABLE IF NOT EXISTS cs_access_policies (
108
108
  id TEXT PRIMARY KEY,
109
109
  name TEXT NOT NULL,
110
110
  description TEXT DEFAULT '',
@@ -117,11 +117,11 @@ CREATE TABLE IF NOT EXISTS access_policies (
117
117
  updatedBy TEXT
118
118
  );
119
119
 
120
- CREATE TABLE IF NOT EXISTS security_rules (
120
+ CREATE TABLE IF NOT EXISTS cs_security_rules (
121
121
  id TEXT PRIMARY KEY,
122
122
  pathPattern TEXT NOT NULL,
123
123
  priority INTEGER DEFAULT 0,
124
- accessPolicyId TEXT NOT NULL REFERENCES access_policies(id),
124
+ accessPolicyId TEXT NOT NULL REFERENCES cs_access_policies(id),
125
125
  enabled INTEGER DEFAULT 1,
126
126
  remark TEXT DEFAULT '',
127
127
  createdAt TEXT DEFAULT (datetime('now')),
@@ -130,10 +130,10 @@ CREATE TABLE IF NOT EXISTS security_rules (
130
130
  updatedBy TEXT
131
131
  );
132
132
 
133
- CREATE INDEX IF NOT EXISTS idx_security_rules_priority ON security_rules(priority);
134
- CREATE INDEX IF NOT EXISTS idx_security_rules_accessPolicyId ON security_rules(accessPolicyId);
133
+ CREATE INDEX IF NOT EXISTS idx_security_rules_priority ON cs_security_rules(priority);
134
+ CREATE INDEX IF NOT EXISTS idx_security_rules_accessPolicyId ON cs_security_rules(accessPolicyId);
135
135
 
136
- CREATE TABLE IF NOT EXISTS access_keys (
136
+ CREATE TABLE IF NOT EXISTS cs_access_keys (
137
137
  accessKeyId TEXT PRIMARY KEY,
138
138
  accessKeyPublic TEXT NOT NULL,
139
139
  role TEXT NOT NULL,
@@ -146,22 +146,43 @@ CREATE TABLE IF NOT EXISTS access_keys (
146
146
  updatedBy TEXT
147
147
  );
148
148
 
149
- CREATE INDEX IF NOT EXISTS idx_access_keys_createdBy ON access_keys(createdBy);
150
- CREATE INDEX IF NOT EXISTS idx_access_keys_expireAt ON access_keys(expireAt);
151
- CREATE INDEX IF NOT EXISTS idx_access_keys_lastUsedAt ON access_keys(lastUsedAt);
149
+ CREATE INDEX IF NOT EXISTS idx_access_keys_createdBy ON cs_access_keys(createdBy);
150
+ CREATE INDEX IF NOT EXISTS idx_access_keys_expireAt ON cs_access_keys(expireAt);
151
+ CREATE INDEX IF NOT EXISTS idx_access_keys_lastUsedAt ON cs_access_keys(lastUsedAt);
152
152
 
153
- CREATE TABLE IF NOT EXISTS connect_tokens (
153
+ CREATE TABLE IF NOT EXISTS cs_connect_tokens (
154
154
  token TEXT PRIMARY KEY,
155
155
  data TEXT NOT NULL,
156
156
  expiresAt INTEGER NOT NULL
157
157
  );
158
158
 
159
- CREATE TABLE IF NOT EXISTS kv_cache (
159
+ CREATE TABLE IF NOT EXISTS cs_kv_cache (
160
160
  key TEXT PRIMARY KEY,
161
161
  value TEXT NOT NULL,
162
162
  expires_at INTEGER NOT NULL
163
163
  );
164
164
  `;
165
+ // Upgrade map (cs_ table prefix): pre-cs_ unprefixed name → cs_ name.
166
+ // Consumed by the runtime rename guard in migrate() (the non-assumeMigrated
167
+ // path), mirroring migrations/0010_rename_tables.sql for deploy-time DBs.
168
+ const TABLE_RENAMES = [
169
+ ["users", "cs_users"],
170
+ ["connected_accounts", "cs_connected_accounts"],
171
+ ["challenges", "cs_challenges"],
172
+ ["invitations", "cs_invitations"],
173
+ ["audit_logs", "cs_audit_logs"],
174
+ ["access_policies", "cs_access_policies"],
175
+ ["security_rules", "cs_security_rules"],
176
+ ["access_keys", "cs_access_keys"],
177
+ ["access_key_sessions", "cs_access_key_sessions"],
178
+ ["connect_tokens", "cs_connect_tokens"],
179
+ ["kv_cache", "cs_kv_cache"],
180
+ ["memberships", "cs_memberships"],
181
+ ["settings", "cs_settings"],
182
+ ["instance_hosts", "cs_instance_hosts"],
183
+ ["login_tickets", "cs_login_tickets"],
184
+ ["verify_codes", "cs_verify_codes"],
185
+ ];
165
186
  // Module-level flag: schema migration runs once per isolate lifetime.
166
187
  // Safe because CREATE TABLE IF NOT EXISTS is idempotent — if the isolate
167
188
  // is recycled the flag resets and the migration re-runs harmlessly.
@@ -247,6 +268,23 @@ export class D1Store {
247
268
  schemaMigrated = true;
248
269
  return;
249
270
  }
271
+ // Upgrade guard (cs_ table prefix): rename any pre-cs_ unprefixed tables
272
+ // to their cs_* names BEFORE the CREATE TABLE IF NOT EXISTS batch below.
273
+ // Without this, CREATE IF NOT EXISTS would create a new empty cs_* table
274
+ // alongside the old one, silently losing all existing rows. Runtime analogue
275
+ // of migrations/0010_rename_tables.sql for the non-assumeMigrated path.
276
+ // "no such table" = fresh install / already migrated; "already … table named"
277
+ // = concurrent-open race — both are safe to ignore.
278
+ for (const [oldName, newName] of TABLE_RENAMES) {
279
+ try {
280
+ await this.db.prepare(`ALTER TABLE ${oldName} RENAME TO ${newName}`).run();
281
+ }
282
+ catch (err) {
283
+ const msg = String(err?.message ?? err);
284
+ if (!/no such table|already .*table|already exists/i.test(msg))
285
+ throw err;
286
+ }
287
+ }
250
288
  // Batch 1: core tables + indexes from SCHEMA_SQL
251
289
  const statements = SCHEMA_SQL.split(";")
252
290
  .map((s) => s.trim())
@@ -254,43 +292,43 @@ export class D1Store {
254
292
  await this.db.batch(statements.map((sql) => this.db.prepare(sql)));
255
293
  // ALTER TABLE — run in parallel (each is independent; failure = column already exists)
256
294
  await Promise.allSettled([
257
- this.db.prepare("ALTER TABLE challenges ADD COLUMN invitationId TEXT").run(),
258
- this.db.prepare("ALTER TABLE users ADD COLUMN sourceDomain TEXT").run(),
259
- this.db.prepare("ALTER TABLE users ADD COLUMN lastLoginDomain TEXT").run(),
260
- this.db.prepare("ALTER TABLE security_rules ADD COLUMN instance_did TEXT DEFAULT NULL").run(),
261
- this.db.prepare("ALTER TABLE access_keys ADD COLUMN instance_did TEXT DEFAULT NULL").run(),
262
- this.db.prepare("ALTER TABLE audit_logs ADD COLUMN instance_did TEXT DEFAULT NULL").run(),
263
- this.db.prepare("ALTER TABLE access_policies ADD COLUMN instance_did TEXT DEFAULT NULL").run(),
264
- this.db.prepare("ALTER TABLE invitations ADD COLUMN instance_did TEXT DEFAULT NULL").run(),
265
- this.db.prepare("ALTER TABLE connected_accounts ADD COLUMN createdAt TEXT").run(),
266
- this.db.prepare("ALTER TABLE connected_accounts ADD COLUMN updatedAt TEXT").run(),
267
- this.db.prepare("ALTER TABLE memberships ADD COLUMN created_at TEXT").run(),
268
- this.db.prepare("ALTER TABLE memberships ADD COLUMN updated_at TEXT").run(),
269
- this.db.prepare("ALTER TABLE settings ADD COLUMN created_at TEXT").run(),
270
- this.db.prepare("ALTER TABLE instance_hosts ADD COLUMN updated_at TEXT").run(),
295
+ this.db.prepare("ALTER TABLE cs_challenges ADD COLUMN invitationId TEXT").run(),
296
+ this.db.prepare("ALTER TABLE cs_users ADD COLUMN sourceDomain TEXT").run(),
297
+ this.db.prepare("ALTER TABLE cs_users ADD COLUMN lastLoginDomain TEXT").run(),
298
+ this.db.prepare("ALTER TABLE cs_security_rules ADD COLUMN instance_did TEXT DEFAULT NULL").run(),
299
+ this.db.prepare("ALTER TABLE cs_access_keys ADD COLUMN instance_did TEXT DEFAULT NULL").run(),
300
+ this.db.prepare("ALTER TABLE cs_audit_logs ADD COLUMN instance_did TEXT DEFAULT NULL").run(),
301
+ this.db.prepare("ALTER TABLE cs_access_policies ADD COLUMN instance_did TEXT DEFAULT NULL").run(),
302
+ this.db.prepare("ALTER TABLE cs_invitations ADD COLUMN instance_did TEXT DEFAULT NULL").run(),
303
+ this.db.prepare("ALTER TABLE cs_connected_accounts ADD COLUMN createdAt TEXT").run(),
304
+ this.db.prepare("ALTER TABLE cs_connected_accounts ADD COLUMN updatedAt TEXT").run(),
305
+ this.db.prepare("ALTER TABLE cs_memberships ADD COLUMN created_at TEXT").run(),
306
+ this.db.prepare("ALTER TABLE cs_memberships ADD COLUMN updated_at TEXT").run(),
307
+ this.db.prepare("ALTER TABLE cs_settings ADD COLUMN created_at TEXT").run(),
308
+ this.db.prepare("ALTER TABLE cs_instance_hosts ADD COLUMN updated_at TEXT").run(),
271
309
  // Phase 3: createdBy/updatedBy audit columns
272
- this.db.prepare("ALTER TABLE users ADD COLUMN createdBy TEXT").run(),
273
- this.db.prepare("ALTER TABLE users ADD COLUMN updatedBy TEXT").run(),
274
- this.db.prepare("ALTER TABLE connected_accounts ADD COLUMN createdBy TEXT").run(),
275
- this.db.prepare("ALTER TABLE connected_accounts ADD COLUMN updatedBy TEXT").run(),
276
- this.db.prepare("ALTER TABLE invitations ADD COLUMN createdBy TEXT").run(),
277
- this.db.prepare("ALTER TABLE invitations ADD COLUMN updatedBy TEXT").run(),
278
- this.db.prepare("ALTER TABLE access_policies ADD COLUMN createdBy TEXT").run(),
279
- this.db.prepare("ALTER TABLE access_policies ADD COLUMN updatedBy TEXT").run(),
280
- this.db.prepare("ALTER TABLE security_rules ADD COLUMN createdBy TEXT").run(),
281
- this.db.prepare("ALTER TABLE security_rules ADD COLUMN updatedBy TEXT").run(),
282
- this.db.prepare("ALTER TABLE access_keys ADD COLUMN updatedBy TEXT").run(),
283
- this.db.prepare("ALTER TABLE memberships ADD COLUMN created_by TEXT").run(),
284
- this.db.prepare("ALTER TABLE memberships ADD COLUMN updated_by TEXT").run(),
285
- this.db.prepare("ALTER TABLE settings ADD COLUMN created_by TEXT").run(),
286
- this.db.prepare("ALTER TABLE settings ADD COLUMN updated_by TEXT").run(),
287
- this.db.prepare("ALTER TABLE instance_hosts ADD COLUMN created_by TEXT").run(),
288
- this.db.prepare("ALTER TABLE instance_hosts ADD COLUMN updated_by TEXT").run(),
310
+ this.db.prepare("ALTER TABLE cs_users ADD COLUMN createdBy TEXT").run(),
311
+ this.db.prepare("ALTER TABLE cs_users ADD COLUMN updatedBy TEXT").run(),
312
+ this.db.prepare("ALTER TABLE cs_connected_accounts ADD COLUMN createdBy TEXT").run(),
313
+ this.db.prepare("ALTER TABLE cs_connected_accounts ADD COLUMN updatedBy TEXT").run(),
314
+ this.db.prepare("ALTER TABLE cs_invitations ADD COLUMN createdBy TEXT").run(),
315
+ this.db.prepare("ALTER TABLE cs_invitations ADD COLUMN updatedBy TEXT").run(),
316
+ this.db.prepare("ALTER TABLE cs_access_policies ADD COLUMN createdBy TEXT").run(),
317
+ this.db.prepare("ALTER TABLE cs_access_policies ADD COLUMN updatedBy TEXT").run(),
318
+ this.db.prepare("ALTER TABLE cs_security_rules ADD COLUMN createdBy TEXT").run(),
319
+ this.db.prepare("ALTER TABLE cs_security_rules ADD COLUMN updatedBy TEXT").run(),
320
+ this.db.prepare("ALTER TABLE cs_access_keys ADD COLUMN updatedBy TEXT").run(),
321
+ this.db.prepare("ALTER TABLE cs_memberships ADD COLUMN created_by TEXT").run(),
322
+ this.db.prepare("ALTER TABLE cs_memberships ADD COLUMN updated_by TEXT").run(),
323
+ this.db.prepare("ALTER TABLE cs_settings ADD COLUMN created_by TEXT").run(),
324
+ this.db.prepare("ALTER TABLE cs_settings ADD COLUMN updated_by TEXT").run(),
325
+ this.db.prepare("ALTER TABLE cs_instance_hosts ADD COLUMN created_by TEXT").run(),
326
+ this.db.prepare("ALTER TABLE cs_instance_hosts ADD COLUMN updated_by TEXT").run(),
289
327
  ]);
290
328
  // Batch 2: additional tables + indexes (all CREATE IF NOT EXISTS, safe in one batch)
291
329
  await this.db.batch([
292
330
  this.db.prepare(`
293
- CREATE TABLE IF NOT EXISTS memberships (
331
+ CREATE TABLE IF NOT EXISTS cs_memberships (
294
332
  user_did TEXT NOT NULL,
295
333
  instance_did TEXT NOT NULL,
296
334
  role TEXT NOT NULL DEFAULT 'guest',
@@ -303,8 +341,8 @@ export class D1Store {
303
341
  PRIMARY KEY (user_did, instance_did)
304
342
  )
305
343
  `),
306
- this.db.prepare(`CREATE INDEX IF NOT EXISTS idx_memberships_instance ON memberships(instance_did)`),
307
- this.db.prepare(`CREATE TABLE IF NOT EXISTS settings (
344
+ this.db.prepare(`CREATE INDEX IF NOT EXISTS idx_memberships_instance ON cs_memberships(instance_did)`),
345
+ this.db.prepare(`CREATE TABLE IF NOT EXISTS cs_settings (
308
346
  instance_did TEXT NOT NULL,
309
347
  key TEXT NOT NULL,
310
348
  value TEXT,
@@ -314,7 +352,7 @@ export class D1Store {
314
352
  updated_by TEXT,
315
353
  PRIMARY KEY (instance_did, key)
316
354
  )`),
317
- this.db.prepare(`CREATE TABLE IF NOT EXISTS verify_codes (
355
+ this.db.prepare(`CREATE TABLE IF NOT EXISTS cs_verify_codes (
318
356
  id INTEGER PRIMARY KEY AUTOINCREMENT,
319
357
  code TEXT NOT NULL UNIQUE,
320
358
  subject TEXT NOT NULL,
@@ -325,15 +363,15 @@ export class D1Store {
325
363
  sent_at TEXT,
326
364
  created_at TEXT DEFAULT (datetime('now'))
327
365
  )`),
328
- this.db.prepare("CREATE INDEX IF NOT EXISTS idx_vc_subject ON verify_codes(subject)"),
329
- this.db.prepare(`CREATE TABLE IF NOT EXISTS login_tickets (
366
+ this.db.prepare("CREATE INDEX IF NOT EXISTS idx_vc_subject ON cs_verify_codes(subject)"),
367
+ this.db.prepare(`CREATE TABLE IF NOT EXISTS cs_login_tickets (
330
368
  ticket TEXT PRIMARY KEY,
331
369
  did TEXT NOT NULL,
332
370
  target_origin TEXT,
333
371
  created_at TEXT DEFAULT (datetime('now')),
334
372
  expires_at TEXT NOT NULL
335
373
  )`),
336
- this.db.prepare(`CREATE TABLE IF NOT EXISTS access_key_sessions (
374
+ this.db.prepare(`CREATE TABLE IF NOT EXISTS cs_access_key_sessions (
337
375
  id TEXT PRIMARY KEY,
338
376
  challenge TEXT NOT NULL,
339
377
  status TEXT DEFAULT 'pending',
@@ -343,7 +381,7 @@ export class D1Store {
343
381
  created_at TEXT DEFAULT (datetime('now')),
344
382
  expires_at TEXT NOT NULL
345
383
  )`),
346
- this.db.prepare(`CREATE TABLE IF NOT EXISTS instance_hosts (
384
+ this.db.prepare(`CREATE TABLE IF NOT EXISTS cs_instance_hosts (
347
385
  host TEXT PRIMARY KEY,
348
386
  instance_did TEXT NOT NULL,
349
387
  created_at TEXT DEFAULT (datetime('now')),
@@ -351,7 +389,7 @@ export class D1Store {
351
389
  created_by TEXT,
352
390
  updated_by TEXT
353
391
  )`),
354
- this.db.prepare("CREATE INDEX IF NOT EXISTS idx_instance_hosts_instance ON instance_hosts(instance_did)"),
392
+ this.db.prepare("CREATE INDEX IF NOT EXISTS idx_instance_hosts_instance ON cs_instance_hosts(instance_did)"),
355
393
  ]);
356
394
  // Seed built-in access policies + default rule (idempotent via INSERT OR IGNORE)
357
395
  await this.ensureBuiltinPolicies();
@@ -365,13 +403,13 @@ export class D1Store {
365
403
  // ─── Challenge operations ──────────────────────────────────────────────
366
404
  async saveChallenge(id, challenge, invitationId) {
367
405
  await this.db
368
- .prepare("INSERT OR REPLACE INTO challenges (id, challenge, invitationId) VALUES (?, ?, ?)")
406
+ .prepare("INSERT OR REPLACE INTO cs_challenges (id, challenge, invitationId) VALUES (?, ?, ?)")
369
407
  .bind(id, challenge, invitationId ?? null)
370
408
  .run();
371
409
  }
372
410
  async getChallenge(id) {
373
411
  const row = await this.db
374
- .prepare("SELECT challenge, invitationId FROM challenges WHERE id = ?")
412
+ .prepare("SELECT challenge, invitationId FROM cs_challenges WHERE id = ?")
375
413
  .bind(id)
376
414
  .first();
377
415
  return row ?? null;
@@ -379,25 +417,25 @@ export class D1Store {
379
417
  /** Find challenge by its value (not by ID). Returns id + challenge + invitationId. */
380
418
  async getChallengeByValue(challenge) {
381
419
  const row = await this.db
382
- .prepare("SELECT id, challenge, invitationId FROM challenges WHERE challenge = ?")
420
+ .prepare("SELECT id, challenge, invitationId FROM cs_challenges WHERE challenge = ?")
383
421
  .bind(challenge)
384
422
  .first();
385
423
  return row ?? null;
386
424
  }
387
425
  async deleteChallenge(id) {
388
- await this.db.prepare("DELETE FROM challenges WHERE id = ?").bind(id).run();
426
+ await this.db.prepare("DELETE FROM cs_challenges WHERE id = ?").bind(id).run();
389
427
  }
390
428
  async purgeExpiredChallenges() {
391
429
  // Purge challenges older than 5 minutes
392
430
  await this.db
393
- .prepare("DELETE FROM challenges WHERE createdAt < datetime('now', '-5 minutes')")
431
+ .prepare("DELETE FROM cs_challenges WHERE createdAt < datetime('now', '-5 minutes')")
394
432
  .run();
395
433
  }
396
434
  async isRegistrationOpen(instanceDid) {
397
435
  // Check instance-specific default rule first, fall back to global
398
436
  if (instanceDid) {
399
437
  const instanceRule = await this.db
400
- .prepare("SELECT accessPolicyId FROM security_rules WHERE id = ?")
438
+ .prepare("SELECT accessPolicyId FROM cs_security_rules WHERE id = ?")
401
439
  .bind(`default-${instanceDid}`)
402
440
  .first();
403
441
  if (instanceRule) {
@@ -408,7 +446,7 @@ export class D1Store {
408
446
  }
409
447
  // Global fallback
410
448
  const row = await this.db
411
- .prepare("SELECT accessPolicyId FROM security_rules WHERE id = 'default'")
449
+ .prepare("SELECT accessPolicyId FROM cs_security_rules WHERE id = 'default'")
412
450
  .first();
413
451
  return row?.accessPolicyId === "public";
414
452
  }
@@ -419,34 +457,34 @@ export class D1Store {
419
457
  // admin代建 passes createdBy = caller.did explicitly.
420
458
  const actor = params.createdBy ?? params.did;
421
459
  await this.db
422
- .prepare(`INSERT INTO users (did, pk, fullName, email, avatar, sourceProvider, emailVerified, firstLoginAt, lastLoginAt, lastLoginIp, sourceDomain, lastLoginDomain, createdAt, updatedAt, createdBy, updatedBy)
460
+ .prepare(`INSERT INTO cs_users (did, pk, fullName, email, avatar, sourceProvider, emailVerified, firstLoginAt, lastLoginAt, lastLoginIp, sourceDomain, lastLoginDomain, createdAt, updatedAt, createdBy, updatedBy)
423
461
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
424
462
  .bind(params.did, params.pk, params.fullName ?? null, params.email ?? null, params.avatar ?? null, params.sourceProvider, params.emailVerified ?? 0, now, now, params.ip ?? null, params.domain ?? null, params.domain ?? null, now, now, actor, actor)
425
463
  .run();
426
464
  }
427
465
  async getUserByDid(did) {
428
- return this.db.prepare("SELECT * FROM users WHERE did = ?").bind(did).first();
466
+ return this.db.prepare("SELECT * FROM cs_users WHERE did = ?").bind(did).first();
429
467
  }
430
468
  async getUserByEmail(email) {
431
- return this.db.prepare("SELECT * FROM users WHERE email = ? LIMIT 1").bind(email).first();
469
+ return this.db.prepare("SELECT * FROM cs_users WHERE email = ? LIMIT 1").bind(email).first();
432
470
  }
433
471
  async updateLastLogin(did, ip, domain) {
434
472
  const now = new Date().toISOString();
435
473
  await this.db
436
- .prepare("UPDATE users SET lastLoginAt = ?, lastLoginIp = ?, lastLoginDomain = ?, updatedAt = ? WHERE did = ?")
474
+ .prepare("UPDATE cs_users SET lastLoginAt = ?, lastLoginIp = ?, lastLoginDomain = ?, updatedAt = ? WHERE did = ?")
437
475
  .bind(now, ip ?? null, domain ?? null, now, did)
438
476
  .run();
439
477
  }
440
478
  async incrementPasskeyCount(did) {
441
479
  await this.db
442
- .prepare("UPDATE users SET passkeyCount = passkeyCount + 1, updatedAt = ? WHERE did = ?")
480
+ .prepare("UPDATE cs_users SET passkeyCount = passkeyCount + 1, updatedAt = ? WHERE did = ?")
443
481
  .bind(new Date().toISOString(), did)
444
482
  .run();
445
483
  }
446
484
  // ─── Team: User queries ────────────────────────────────────────────────
447
485
  async getUserCount() {
448
486
  const row = await this.db
449
- .prepare("SELECT COUNT(*) as count FROM users")
487
+ .prepare("SELECT COUNT(*) as count FROM cs_users")
450
488
  .first();
451
489
  return Number(row?.count ?? 0);
452
490
  }
@@ -487,14 +525,14 @@ export class D1Store {
487
525
  const orderBy = `ORDER BY ${sortExpr} ${direction}, u.did ASC`;
488
526
  // Batch COUNT + SELECT into one D1 roundtrip
489
527
  const [countResult, dataResult] = await this.db.batch([
490
- this.db.prepare(`SELECT COUNT(*) as count FROM users u ${where}`).bind(...params),
528
+ this.db.prepare(`SELECT COUNT(*) as count FROM cs_users u ${where}`).bind(...params),
491
529
  this.db
492
530
  .prepare(`SELECT u.did, u.fullName, u.email, u.avatar, u.role, u.approved,
493
531
  COALESCE(u.createdAt, u.firstLoginAt) as createdAt,
494
532
  u.lastLoginAt, u.passkeyCount, u.sourceDomain, u.lastLoginDomain, u.sourceProvider, u.inviter,
495
533
  inv.fullName as inviterName
496
- FROM users u
497
- LEFT JOIN users inv ON u.inviter = inv.did
534
+ FROM cs_users u
535
+ LEFT JOIN cs_users inv ON u.inviter = inv.did
498
536
  ${where}
499
537
  ${orderBy}
500
538
  LIMIT ? OFFSET ?`)
@@ -508,8 +546,8 @@ export class D1Store {
508
546
  const row = await this.db
509
547
  .prepare(`SELECT u.did, u.fullName, u.email, u.avatar, u.role, u.approved, u.createdAt, u.lastLoginAt, u.passkeyCount, u.sourceDomain, u.lastLoginDomain, u.sourceProvider, u.inviter, u.emailVerified,
510
548
  inv.fullName as inviterName
511
- FROM users u
512
- LEFT JOIN users inv ON u.inviter = inv.did
549
+ FROM cs_users u
550
+ LEFT JOIN cs_users inv ON u.inviter = inv.did
513
551
  WHERE u.did = ?`)
514
552
  .bind(did)
515
553
  .first();
@@ -517,13 +555,13 @@ export class D1Store {
517
555
  }
518
556
  async updateUserRole(did, role, actor) {
519
557
  await this.db
520
- .prepare("UPDATE users SET role = ?, updatedAt = ?, updatedBy = ? WHERE did = ?")
558
+ .prepare("UPDATE cs_users SET role = ?, updatedAt = ?, updatedBy = ? WHERE did = ?")
521
559
  .bind(role, new Date().toISOString(), actor, did)
522
560
  .run();
523
561
  }
524
562
  async updateUserApproval(did, approved, actor) {
525
563
  await this.db
526
- .prepare("UPDATE users SET approved = ?, updatedAt = ?, updatedBy = ? WHERE did = ?")
564
+ .prepare("UPDATE cs_users SET approved = ?, updatedAt = ?, updatedBy = ? WHERE did = ?")
527
565
  .bind(approved ? 1 : 0, new Date().toISOString(), actor, did)
528
566
  .run();
529
567
  }
@@ -554,20 +592,20 @@ export class D1Store {
554
592
  params.push(actor);
555
593
  params.push(did);
556
594
  await this.db
557
- .prepare(`UPDATE users SET ${sets.join(", ")} WHERE did = ?`)
595
+ .prepare(`UPDATE cs_users SET ${sets.join(", ")} WHERE did = ?`)
558
596
  .bind(...params)
559
597
  .run();
560
598
  }
561
599
  async removeUser(did) {
562
600
  // Delete connected accounts first, then user
563
601
  await this.db.batch([
564
- this.db.prepare("DELETE FROM connected_accounts WHERE userDid = ?").bind(did),
565
- this.db.prepare("DELETE FROM users WHERE did = ?").bind(did),
602
+ this.db.prepare("DELETE FROM cs_connected_accounts WHERE userDid = ?").bind(did),
603
+ this.db.prepare("DELETE FROM cs_users WHERE did = ?").bind(did),
566
604
  ]);
567
605
  }
568
606
  async setUserInviter(did, inviterDid, actor) {
569
607
  await this.db
570
- .prepare("UPDATE users SET inviter = ?, updatedAt = ?, updatedBy = ? WHERE did = ? AND inviter IS NULL")
608
+ .prepare("UPDATE cs_users SET inviter = ?, updatedAt = ?, updatedBy = ? WHERE did = ? AND inviter IS NULL")
571
609
  .bind(inviterDid, new Date().toISOString(), actor, did)
572
610
  .run();
573
611
  }
@@ -579,10 +617,10 @@ export class D1Store {
579
617
  const now = new Date().toISOString();
580
618
  await this.db.batch([
581
619
  this.db
582
- .prepare("UPDATE users SET role = 'owner', updatedAt = ?, updatedBy = ? WHERE did = ?")
620
+ .prepare("UPDATE cs_users SET role = 'owner', updatedAt = ?, updatedBy = ? WHERE did = ?")
583
621
  .bind(now, actor, newOwnerDid),
584
622
  this.db
585
- .prepare("UPDATE users SET role = 'admin', updatedAt = ?, updatedBy = ? WHERE did = ?")
623
+ .prepare("UPDATE cs_users SET role = 'admin', updatedAt = ?, updatedBy = ? WHERE did = ?")
586
624
  .bind(now, actor, currentOwnerDid),
587
625
  ]);
588
626
  }
@@ -596,7 +634,7 @@ export class D1Store {
596
634
  // Default actor = inviter (the invitation's creator) per plan §五A.
597
635
  const actor = input.actor ?? input.inviterDid;
598
636
  await this.db
599
- .prepare(`INSERT INTO invitations (id, teamDid, role, remark, inviterDid, expireAt, maxUses, useCount, status, instance_did, createdAt, updatedAt, createdBy, updatedBy)
637
+ .prepare(`INSERT INTO cs_invitations (id, teamDid, role, remark, inviterDid, expireAt, maxUses, useCount, status, instance_did, createdAt, updatedAt, createdBy, updatedBy)
600
638
  VALUES (?, ?, ?, ?, ?, ?, ?, 0, 'active', ?, ?, ?, ?, ?)`)
601
639
  .bind(id, input.teamDid, input.role, input.remark ?? "", input.inviterDid, expireAt, maxUses, input.instanceDid ?? null, now, now, actor, actor)
602
640
  .run();
@@ -619,7 +657,7 @@ export class D1Store {
619
657
  }
620
658
  async getInvitation(id) {
621
659
  return this.db
622
- .prepare("SELECT * FROM invitations WHERE id = ?")
660
+ .prepare("SELECT * FROM cs_invitations WHERE id = ?")
623
661
  .bind(id)
624
662
  .first();
625
663
  }
@@ -637,11 +675,11 @@ export class D1Store {
637
675
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
638
676
  // Batch COUNT + SELECT into one D1 roundtrip
639
677
  const [countResult, dataResult] = await this.db.batch([
640
- this.db.prepare(`SELECT COUNT(*) as count FROM invitations i ${where}`).bind(...params),
678
+ this.db.prepare(`SELECT COUNT(*) as count FROM cs_invitations i ${where}`).bind(...params),
641
679
  this.db
642
680
  .prepare(`SELECT i.*, u.fullName as inviterName
643
- FROM invitations i
644
- LEFT JOIN users u ON i.inviterDid = u.did
681
+ FROM cs_invitations i
682
+ LEFT JOIN cs_users u ON i.inviterDid = u.did
645
683
  ${where}
646
684
  ORDER BY i.createdAt DESC
647
685
  LIMIT ? OFFSET ?`)
@@ -656,7 +694,7 @@ export class D1Store {
656
694
  */
657
695
  async incrementInvitationUseCount(id) {
658
696
  const result = await this.db
659
- .prepare(`UPDATE invitations SET useCount = useCount + 1, updatedAt = ?
697
+ .prepare(`UPDATE cs_invitations SET useCount = useCount + 1, updatedAt = ?
660
698
  WHERE id = ? AND useCount < maxUses AND status = 'active'`)
661
699
  .bind(new Date().toISOString(), id)
662
700
  .run();
@@ -664,23 +702,23 @@ export class D1Store {
664
702
  }
665
703
  async updateInvitationStatus(id, status, actor) {
666
704
  await this.db
667
- .prepare("UPDATE invitations SET status = ?, updatedAt = ?, updatedBy = ? WHERE id = ?")
705
+ .prepare("UPDATE cs_invitations SET status = ?, updatedAt = ?, updatedBy = ? WHERE id = ?")
668
706
  .bind(status, new Date().toISOString(), actor, id)
669
707
  .run();
670
708
  }
671
709
  async deleteInvitation(id) {
672
- await this.db.prepare("DELETE FROM invitations WHERE id = ?").bind(id).run();
710
+ await this.db.prepare("DELETE FROM cs_invitations WHERE id = ?").bind(id).run();
673
711
  }
674
712
  async purgeExpiredInvitations() {
675
713
  await this.db
676
- .prepare("UPDATE invitations SET status = 'expired', updatedAt = ? WHERE status = 'active' AND expireAt < datetime('now')")
714
+ .prepare("UPDATE cs_invitations SET status = 'expired', updatedAt = ? WHERE status = 'active' AND expireAt < datetime('now')")
677
715
  .bind(new Date().toISOString())
678
716
  .run();
679
717
  }
680
718
  // ─── Team: Audit logs ─────────────────────────────────────────────────
681
719
  async createAuditLog(input) {
682
720
  await this.db
683
- .prepare(`INSERT INTO audit_logs (action, operatorDid, targetDid, metadata, ip, instance_did, createdAt)
721
+ .prepare(`INSERT INTO cs_audit_logs (action, operatorDid, targetDid, metadata, ip, instance_did, createdAt)
684
722
  VALUES (?, ?, ?, ?, ?, ?, ?)`)
685
723
  .bind(input.action, input.operatorDid, input.targetDid ?? null, JSON.stringify(input.metadata ?? {}), input.ip ?? null, input.instanceDid ?? null, new Date().toISOString())
686
724
  .run();
@@ -731,12 +769,12 @@ export class D1Store {
731
769
  const offset = (opts.page - 1) * opts.pageSize;
732
770
  // Batch COUNT + SELECT into one D1 roundtrip
733
771
  const [countResult, dataResult] = await this.db.batch([
734
- this.db.prepare(`SELECT COUNT(*) as count FROM audit_logs a ${where}`).bind(...params),
772
+ this.db.prepare(`SELECT COUNT(*) as count FROM cs_audit_logs a ${where}`).bind(...params),
735
773
  this.db
736
774
  .prepare(`SELECT a.*, op.fullName as operatorName, op.role as operatorRole, tgt.fullName as targetName
737
- FROM audit_logs a
738
- LEFT JOIN users op ON a.operatorDid = op.did
739
- LEFT JOIN users tgt ON a.targetDid = tgt.did
775
+ FROM cs_audit_logs a
776
+ LEFT JOIN cs_users op ON a.operatorDid = op.did
777
+ LEFT JOIN cs_users tgt ON a.targetDid = tgt.did
740
778
  ${where}
741
779
  ORDER BY a.createdAt DESC
742
780
  LIMIT ? OFFSET ?`)
@@ -749,9 +787,9 @@ export class D1Store {
749
787
  async getAuditLogById(id, instanceDid) {
750
788
  return this.db
751
789
  .prepare(`SELECT a.*, op.fullName as operatorName, op.role as operatorRole, tgt.fullName as targetName
752
- FROM audit_logs a
753
- LEFT JOIN users op ON a.operatorDid = op.did
754
- LEFT JOIN users tgt ON a.targetDid = tgt.did
790
+ FROM cs_audit_logs a
791
+ LEFT JOIN cs_users op ON a.operatorDid = op.did
792
+ LEFT JOIN cs_users tgt ON a.targetDid = tgt.did
755
793
  WHERE a.id = ? AND a.instance_did = ?`)
756
794
  .bind(id, instanceDid)
757
795
  .first();
@@ -762,7 +800,7 @@ export class D1Store {
762
800
  // Self-serve account link: default actor = the user's own DID (plan §二).
763
801
  const actor = params.actor ?? params.userDid;
764
802
  await this.db
765
- .prepare(`INSERT INTO connected_accounts (did, pk, userDid, provider, id, extra, userInfo, firstLoginAt, lastLoginAt, lastLoginIp, createdAt, updatedAt, createdBy, updatedBy)
803
+ .prepare(`INSERT INTO cs_connected_accounts (did, pk, userDid, provider, id, extra, userInfo, firstLoginAt, lastLoginAt, lastLoginIp, createdAt, updatedAt, createdBy, updatedBy)
766
804
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
767
805
  .bind(params.did, params.pk, params.userDid, params.provider, params.id, params.extra, params.userInfo, now, now, params.ip ?? null, now, now, actor, actor)
768
806
  .run();
@@ -775,49 +813,49 @@ export class D1Store {
775
813
  .prepare(
776
814
  // Bind all timestamps as ISO `?` params (consistent with createConnectedAccount;
777
815
  // avoids mixing `datetime('now')` literals with `?` placeholders).
778
- `INSERT INTO connected_accounts (did, pk, userDid, provider, id, userInfo, firstLoginAt, lastLoginAt, createdAt, updatedAt, createdBy, updatedBy)
816
+ `INSERT INTO cs_connected_accounts (did, pk, userDid, provider, id, userInfo, firstLoginAt, lastLoginAt, createdAt, updatedAt, createdBy, updatedBy)
779
817
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
780
818
  ON CONFLICT (did) DO UPDATE SET
781
819
  pk = excluded.pk, lastLoginAt = excluded.lastLoginAt, updatedAt = excluded.updatedAt,
782
- userInfo = COALESCE(excluded.userInfo, connected_accounts.userInfo)`)
820
+ userInfo = COALESCE(excluded.userInfo, cs_connected_accounts.userInfo)`)
783
821
  .bind(account.did, account.pk, account.userDid, account.provider, account.id, account.userInfo || null, now, now, now, now, actor, actor)
784
822
  .run();
785
823
  }
786
824
  async getConnectedAccountById(credentialId) {
787
825
  return this.db
788
- .prepare("SELECT * FROM connected_accounts WHERE id = ?")
826
+ .prepare("SELECT * FROM cs_connected_accounts WHERE id = ?")
789
827
  .bind(credentialId)
790
828
  .first();
791
829
  }
792
830
  async getConnectedAccountByDid(did) {
793
831
  return this.db
794
- .prepare("SELECT * FROM connected_accounts WHERE did = ?")
832
+ .prepare("SELECT * FROM cs_connected_accounts WHERE did = ?")
795
833
  .bind(did)
796
834
  .first();
797
835
  }
798
836
  async updateCounter(did, counter) {
799
837
  const now = new Date().toISOString();
800
838
  await this.db
801
- .prepare("UPDATE connected_accounts SET counter = ?, lastLoginAt = ?, updatedAt = ? WHERE did = ?")
839
+ .prepare("UPDATE cs_connected_accounts SET counter = ?, lastLoginAt = ?, updatedAt = ? WHERE did = ?")
802
840
  .bind(counter, now, now, did)
803
841
  .run();
804
842
  }
805
843
  async getConnectedAccountsByUserDid(userDid) {
806
844
  const rows = await this.db
807
- .prepare("SELECT * FROM connected_accounts WHERE userDid = ?")
845
+ .prepare("SELECT * FROM cs_connected_accounts WHERE userDid = ?")
808
846
  .bind(userDid)
809
847
  .all();
810
848
  return rows.results ?? [];
811
849
  }
812
850
  async getConnectedAccountByProviderAndUser(provider, userDid) {
813
851
  return this.db
814
- .prepare("SELECT * FROM connected_accounts WHERE provider = ? AND userDid = ?")
852
+ .prepare("SELECT * FROM cs_connected_accounts WHERE provider = ? AND userDid = ?")
815
853
  .bind(provider, userDid)
816
854
  .first();
817
855
  }
818
856
  async getConnectedAccountsByProviderAndUser(provider, userDid) {
819
857
  const rows = await this.db
820
- .prepare("SELECT * FROM connected_accounts WHERE provider = ? AND userDid = ?")
858
+ .prepare("SELECT * FROM cs_connected_accounts WHERE provider = ? AND userDid = ?")
821
859
  .bind(provider, userDid)
822
860
  .all();
823
861
  return rows.results ?? [];
@@ -826,33 +864,33 @@ export class D1Store {
826
864
  // Single query: direct DID match OR indirect via connected_accounts.
827
865
  // UNION ALL + LIMIT 1 ensures direct match is preferred.
828
866
  return this.db
829
- .prepare(`SELECT u.* FROM users u WHERE u.did = ?
867
+ .prepare(`SELECT u.* FROM cs_users u WHERE u.did = ?
830
868
  UNION ALL
831
- SELECT u.* FROM connected_accounts ca JOIN users u ON ca.userDid = u.did WHERE ca.did = ?
869
+ SELECT u.* FROM cs_connected_accounts ca JOIN cs_users u ON ca.userDid = u.did WHERE ca.did = ?
832
870
  LIMIT 1`)
833
871
  .bind(did, did)
834
872
  .first();
835
873
  }
836
874
  async decrementPasskeyCount(did) {
837
875
  await this.db
838
- .prepare("UPDATE users SET passkeyCount = MAX(passkeyCount - 1, 0), updatedAt = ? WHERE did = ?")
876
+ .prepare("UPDATE cs_users SET passkeyCount = MAX(passkeyCount - 1, 0), updatedAt = ? WHERE did = ?")
839
877
  .bind(new Date().toISOString(), did)
840
878
  .run();
841
879
  }
842
880
  async updateConnectedAccountName(did, name, actor) {
843
881
  await this.db
844
- .prepare("UPDATE connected_accounts SET userInfo = ?, updatedAt = ?, updatedBy = ? WHERE did = ?")
882
+ .prepare("UPDATE cs_connected_accounts SET userInfo = ?, updatedAt = ?, updatedBy = ? WHERE did = ?")
845
883
  .bind(JSON.stringify({ name }), new Date().toISOString(), actor, did)
846
884
  .run();
847
885
  }
848
886
  async deleteConnectedAccount(did) {
849
- await this.db.prepare("DELETE FROM connected_accounts WHERE did = ?").bind(did).run();
887
+ await this.db.prepare("DELETE FROM cs_connected_accounts WHERE did = ?").bind(did).run();
850
888
  }
851
889
  // ─── Access keys ────────────────────────────────────────────────────────
852
890
  async createAccessKey(input) {
853
891
  const now = new Date().toISOString();
854
892
  await this.db
855
- .prepare(`INSERT INTO access_keys (accessKeyId, accessKeyPublic, role, remark, createdBy, expireAt, instance_did, createdAt, updatedAt, updatedBy)
893
+ .prepare(`INSERT INTO cs_access_keys (accessKeyId, accessKeyPublic, role, remark, createdBy, expireAt, instance_did, createdAt, updatedAt, updatedBy)
856
894
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
857
895
  .bind(input.accessKeyId, input.accessKeyPublic, input.role, input.remark ?? "", input.createdBy, input.expireAt ?? null, input.instanceDid ?? null, now, now, input.createdBy)
858
896
  .run();
@@ -873,8 +911,8 @@ export class D1Store {
873
911
  async getAccessKeyById(accessKeyId) {
874
912
  const row = await this.db
875
913
  .prepare(`SELECT k.*, u.fullName as createdByName
876
- FROM access_keys k
877
- LEFT JOIN users u ON k.createdBy = u.did
914
+ FROM cs_access_keys k
915
+ LEFT JOIN cs_users u ON k.createdBy = u.did
878
916
  WHERE k.accessKeyId = ?`)
879
917
  .bind(accessKeyId)
880
918
  .first();
@@ -906,11 +944,11 @@ export class D1Store {
906
944
  const offset = (opts.page - 1) * opts.pageSize;
907
945
  // Batch COUNT + SELECT into one D1 roundtrip
908
946
  const [countResult, dataResult] = await this.db.batch([
909
- this.db.prepare(`SELECT COUNT(*) as count FROM access_keys k ${where}`).bind(...params),
947
+ this.db.prepare(`SELECT COUNT(*) as count FROM cs_access_keys k ${where}`).bind(...params),
910
948
  this.db
911
949
  .prepare(`SELECT k.*, u.fullName as createdByName
912
- FROM access_keys k
913
- LEFT JOIN users u ON k.createdBy = u.did
950
+ FROM cs_access_keys k
951
+ LEFT JOIN cs_users u ON k.createdBy = u.did
914
952
  ${where}
915
953
  ORDER BY k.createdAt DESC
916
954
  LIMIT ? OFFSET ?`)
@@ -948,18 +986,18 @@ export class D1Store {
948
986
  params.push(actor);
949
987
  params.push(accessKeyId);
950
988
  await this.db
951
- .prepare(`UPDATE access_keys SET ${sets.join(", ")} WHERE accessKeyId = ?`)
989
+ .prepare(`UPDATE cs_access_keys SET ${sets.join(", ")} WHERE accessKeyId = ?`)
952
990
  .bind(...params)
953
991
  .run();
954
992
  }
955
993
  return this.getAccessKeyById(accessKeyId);
956
994
  }
957
995
  async deleteAccessKey(accessKeyId) {
958
- await this.db.prepare("DELETE FROM access_keys WHERE accessKeyId = ?").bind(accessKeyId).run();
996
+ await this.db.prepare("DELETE FROM cs_access_keys WHERE accessKeyId = ?").bind(accessKeyId).run();
959
997
  }
960
998
  async refreshAccessKeyLastUsed(accessKeyId) {
961
999
  await this.db
962
- .prepare("UPDATE access_keys SET lastUsedAt = ? WHERE accessKeyId = ?")
1000
+ .prepare("UPDATE cs_access_keys SET lastUsedAt = ? WHERE accessKeyId = ?")
963
1001
  .bind(new Date().toISOString(), accessKeyId)
964
1002
  .run();
965
1003
  }
@@ -997,7 +1035,7 @@ export class D1Store {
997
1035
  ];
998
1036
  const now = new Date().toISOString();
999
1037
  await this.db.batch(policies.map((p) => this.db
1000
- .prepare(`INSERT OR IGNORE INTO access_policies (id, name, description, roles, reverse, isProtected, createdAt, updatedAt, createdBy, updatedBy)
1038
+ .prepare(`INSERT OR IGNORE INTO cs_access_policies (id, name, description, roles, reverse, isProtected, createdAt, updatedAt, createdBy, updatedBy)
1001
1039
  VALUES (?, ?, ?, ?, ?, 1, ?, ?, 'system', 'system')`)
1002
1040
  .bind(p.id, p.name, p.description, p.roles, p.reverse, now, now)));
1003
1041
  invalidateRulesCache();
@@ -1005,7 +1043,7 @@ export class D1Store {
1005
1043
  async ensureDefaultRule() {
1006
1044
  const now = new Date().toISOString();
1007
1045
  await this.db
1008
- .prepare(`INSERT OR IGNORE INTO security_rules (id, pathPattern, priority, accessPolicyId, enabled, remark, createdAt, updatedAt, createdBy, updatedBy)
1046
+ .prepare(`INSERT OR IGNORE INTO cs_security_rules (id, pathPattern, priority, accessPolicyId, enabled, remark, createdAt, updatedAt, createdBy, updatedBy)
1009
1047
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'system', 'system')`)
1010
1048
  .bind("default", "*", -1, "public", 1, "Default fallback rule", now, now)
1011
1049
  .run();
@@ -1013,7 +1051,7 @@ export class D1Store {
1013
1051
  }
1014
1052
  // ─── Access policies: CRUD ─────────────────────────────────────────────
1015
1053
  async getAccessPolicies(instanceDid) {
1016
- let sql = "SELECT * FROM access_policies";
1054
+ let sql = "SELECT * FROM cs_access_policies";
1017
1055
  const params = [];
1018
1056
  if (instanceDid !== undefined) {
1019
1057
  sql += " WHERE instance_did = ?";
@@ -1032,7 +1070,7 @@ export class D1Store {
1032
1070
  return [];
1033
1071
  // Batch-fetch all rule counts in one D1 roundtrip (instead of N+1 individual queries)
1034
1072
  const countResults = await this.db.batch(policies.map((p) => this.db
1035
- .prepare("SELECT COUNT(*) as count FROM security_rules WHERE accessPolicyId = ?")
1073
+ .prepare("SELECT COUNT(*) as count FROM cs_security_rules WHERE accessPolicyId = ?")
1036
1074
  .bind(p.id)));
1037
1075
  return policies.map((p, i) => {
1038
1076
  const ruleCount = countResults[i]?.results?.[0]?.count ?? 0;
@@ -1055,9 +1093,9 @@ export class D1Store {
1055
1093
  async getAccessPolicy(id) {
1056
1094
  // Batch policy + rule count into one D1 roundtrip
1057
1095
  const [policyResult, countResult] = await this.db.batch([
1058
- this.db.prepare("SELECT * FROM access_policies WHERE id = ?").bind(id),
1096
+ this.db.prepare("SELECT * FROM cs_access_policies WHERE id = ?").bind(id),
1059
1097
  this.db
1060
- .prepare("SELECT COUNT(*) as count FROM security_rules WHERE accessPolicyId = ?")
1098
+ .prepare("SELECT COUNT(*) as count FROM cs_security_rules WHERE accessPolicyId = ?")
1061
1099
  .bind(id),
1062
1100
  ]);
1063
1101
  const p = policyResult.results?.[0];
@@ -1084,7 +1122,7 @@ export class D1Store {
1084
1122
  const now = new Date().toISOString();
1085
1123
  const { roles: dbRoles, reverse } = await import("../access/access-policy.js").then((m) => m.accessTypeToDb(input.accessType, input.roles));
1086
1124
  await this.db
1087
- .prepare(`INSERT INTO access_policies (id, name, description, roles, reverse, isProtected, instance_did, createdAt, updatedAt, createdBy, updatedBy)
1125
+ .prepare(`INSERT INTO cs_access_policies (id, name, description, roles, reverse, isProtected, instance_did, createdAt, updatedAt, createdBy, updatedBy)
1088
1126
  VALUES (?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?)`)
1089
1127
  .bind(id, input.name, input.description ?? "", dbRoles, reverse, input.instanceDid ?? null, now, now, actor, actor)
1090
1128
  .run();
@@ -1117,7 +1155,7 @@ export class D1Store {
1117
1155
  params.push(actor);
1118
1156
  params.push(id);
1119
1157
  await this.db
1120
- .prepare(`UPDATE access_policies SET ${sets.join(", ")} WHERE id = ?`)
1158
+ .prepare(`UPDATE cs_access_policies SET ${sets.join(", ")} WHERE id = ?`)
1121
1159
  .bind(...params)
1122
1160
  .run();
1123
1161
  }
@@ -1125,12 +1163,12 @@ export class D1Store {
1125
1163
  return (await this.getAccessPolicy(id));
1126
1164
  }
1127
1165
  async deleteAccessPolicy(id) {
1128
- await this.db.prepare("DELETE FROM access_policies WHERE id = ?").bind(id).run();
1166
+ await this.db.prepare("DELETE FROM cs_access_policies WHERE id = ?").bind(id).run();
1129
1167
  invalidateRulesCache();
1130
1168
  }
1131
1169
  async getAccessPolicyRuleCount(id) {
1132
1170
  const row = await this.db
1133
- .prepare("SELECT COUNT(*) as count FROM security_rules WHERE accessPolicyId = ?")
1171
+ .prepare("SELECT COUNT(*) as count FROM cs_security_rules WHERE accessPolicyId = ?")
1134
1172
  .bind(id)
1135
1173
  .first();
1136
1174
  return Number(row?.count ?? 0);
@@ -1138,8 +1176,8 @@ export class D1Store {
1138
1176
  // ─── Security rules: CRUD ─────────────────────────────────────────────
1139
1177
  async getSecurityRules(instanceDid) {
1140
1178
  let sql = `SELECT r.*, p.name as accessPolicyName
1141
- FROM security_rules r
1142
- LEFT JOIN access_policies p ON r.accessPolicyId = p.id`;
1179
+ FROM cs_security_rules r
1180
+ LEFT JOIN cs_access_policies p ON r.accessPolicyId = p.id`;
1143
1181
  const params = [];
1144
1182
  if (instanceDid !== undefined) {
1145
1183
  sql += ` WHERE r.instance_did = ?`;
@@ -1169,8 +1207,8 @@ export class D1Store {
1169
1207
  async getSecurityRule(id) {
1170
1208
  const r = await this.db
1171
1209
  .prepare(`SELECT r.*, p.name as accessPolicyName
1172
- FROM security_rules r
1173
- LEFT JOIN access_policies p ON r.accessPolicyId = p.id
1210
+ FROM cs_security_rules r
1211
+ LEFT JOIN cs_access_policies p ON r.accessPolicyId = p.id
1174
1212
  WHERE r.id = ?`)
1175
1213
  .bind(id)
1176
1214
  .first();
@@ -1193,7 +1231,7 @@ export class D1Store {
1193
1231
  const id = crypto.randomUUID();
1194
1232
  const now = new Date().toISOString();
1195
1233
  await this.db
1196
- .prepare(`INSERT INTO security_rules (id, pathPattern, priority, accessPolicyId, enabled, remark, instance_did, createdAt, updatedAt, createdBy, updatedBy)
1234
+ .prepare(`INSERT INTO cs_security_rules (id, pathPattern, priority, accessPolicyId, enabled, remark, instance_did, createdAt, updatedAt, createdBy, updatedBy)
1197
1235
  VALUES (?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?)`)
1198
1236
  .bind(id, input.pathPattern, input.priority ?? 0, input.accessPolicyId, input.remark ?? "", input.instanceDid ?? null, now, now, actor, actor)
1199
1237
  .run();
@@ -1231,7 +1269,7 @@ export class D1Store {
1231
1269
  params.push(actor);
1232
1270
  params.push(id);
1233
1271
  await this.db
1234
- .prepare(`UPDATE security_rules SET ${sets.join(", ")} WHERE id = ?`)
1272
+ .prepare(`UPDATE cs_security_rules SET ${sets.join(", ")} WHERE id = ?`)
1235
1273
  .bind(...params)
1236
1274
  .run();
1237
1275
  }
@@ -1239,14 +1277,14 @@ export class D1Store {
1239
1277
  return (await this.getSecurityRule(id));
1240
1278
  }
1241
1279
  async deleteSecurityRule(id) {
1242
- await this.db.prepare("DELETE FROM security_rules WHERE id = ?").bind(id).run();
1280
+ await this.db.prepare("DELETE FROM cs_security_rules WHERE id = ?").bind(id).run();
1243
1281
  invalidateRulesCache();
1244
1282
  }
1245
1283
  // ─── Membership operations ──────────────────────────────────────────────
1246
1284
  async createMembership(userDid, instanceDid, role, invitedBy, actor) {
1247
1285
  const now = new Date().toISOString();
1248
1286
  await this.db
1249
- .prepare(`INSERT OR IGNORE INTO memberships (user_did, instance_did, role, invited_by, created_at, updated_at, created_by, updated_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
1287
+ .prepare(`INSERT OR IGNORE INTO cs_memberships (user_did, instance_did, role, invited_by, created_at, updated_at, created_by, updated_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
1250
1288
  .bind(userDid, instanceDid, role, invitedBy ?? null, now, now, actor, actor)
1251
1289
  .run();
1252
1290
  invalidateMembership(userDid, instanceDid);
@@ -1258,7 +1296,7 @@ export class D1Store {
1258
1296
  return cached.result;
1259
1297
  }
1260
1298
  const result = await this.db
1261
- .prepare("SELECT * FROM memberships WHERE user_did = ? AND instance_did = ?")
1299
+ .prepare("SELECT * FROM cs_memberships WHERE user_did = ? AND instance_did = ?")
1262
1300
  .bind(userDid, instanceDid)
1263
1301
  .first();
1264
1302
  _membershipCache.set(cacheKey, { result: result ?? null, at: Date.now() });
@@ -1267,14 +1305,14 @@ export class D1Store {
1267
1305
  /** Get all instance DIDs where user has owner role (single query). */
1268
1306
  async getOwnerInstanceDids(userDid) {
1269
1307
  const { results } = await this.db
1270
- .prepare("SELECT instance_did FROM memberships WHERE user_did = ? AND role = 'owner'")
1308
+ .prepare("SELECT instance_did FROM cs_memberships WHERE user_did = ? AND role = 'owner'")
1271
1309
  .bind(userDid)
1272
1310
  .all();
1273
1311
  return new Set((results ?? []).map((r) => r.instance_did));
1274
1312
  }
1275
1313
  async listMemberships(instanceDid) {
1276
1314
  const rows = await this.db
1277
- .prepare("SELECT * FROM memberships WHERE instance_did = ? ORDER BY joined_at ASC")
1315
+ .prepare("SELECT * FROM cs_memberships WHERE instance_did = ? ORDER BY joined_at ASC")
1278
1316
  .bind(instanceDid)
1279
1317
  .all();
1280
1318
  return rows.results ?? [];
@@ -1284,8 +1322,8 @@ export class D1Store {
1284
1322
  .prepare(`SELECT m.user_did, m.instance_did, m.role, m.invited_by, m.joined_at,
1285
1323
  u.fullName, u.email, u.avatar, COALESCE(u.approved, 1) as approved,
1286
1324
  u.sourceProvider, u.sourceDomain, u.lastLoginDomain, u.createdAt
1287
- FROM memberships m
1288
- LEFT JOIN users u ON m.user_did = u.did
1325
+ FROM cs_memberships m
1326
+ LEFT JOIN cs_users u ON m.user_did = u.did
1289
1327
  WHERE m.instance_did = ?
1290
1328
  ORDER BY
1291
1329
  CASE m.role WHEN 'owner' THEN 0 WHEN 'admin' THEN 1 WHEN 'member' THEN 2 ELSE 3 END,
@@ -1298,8 +1336,8 @@ export class D1Store {
1298
1336
  const rows = await this.db
1299
1337
  .prepare(`SELECT m.user_did, m.instance_did, m.role, m.joined_at,
1300
1338
  u.fullName, u.email, u.sourceProvider, COALESCE(u.approved, 1) as approved
1301
- FROM memberships m
1302
- LEFT JOIN users u ON m.user_did = u.did
1339
+ FROM cs_memberships m
1340
+ LEFT JOIN cs_users u ON m.user_did = u.did
1303
1341
  ORDER BY m.instance_did, m.role, m.joined_at ASC`)
1304
1342
  .all();
1305
1343
  return rows.results ?? [];
@@ -1314,8 +1352,8 @@ export class D1Store {
1314
1352
  CASE MIN(CASE m.role WHEN 'owner' THEN 0 WHEN 'admin' THEN 1 WHEN 'member' THEN 2 ELSE 3 END)
1315
1353
  WHEN 0 THEN 'owner' WHEN 1 THEN 'admin' WHEN 2 THEN 'member' ELSE 'guest' END as role,
1316
1354
  json_group_array(json_object('instance_did', m.instance_did, 'role', m.role, 'joined_at', m.joined_at)) as instances_json
1317
- FROM memberships m
1318
- LEFT JOIN users u ON m.user_did = u.did
1355
+ FROM cs_memberships m
1356
+ LEFT JOIN cs_users u ON m.user_did = u.did
1319
1357
  GROUP BY m.user_did
1320
1358
  ORDER BY MIN(CASE m.role WHEN 'owner' THEN 0 WHEN 'admin' THEN 1 WHEN 'member' THEN 2 ELSE 3 END) ASC,
1321
1359
  MIN(m.joined_at) ASC`)
@@ -1324,26 +1362,26 @@ export class D1Store {
1324
1362
  }
1325
1363
  async updateMembershipRole(userDid, instanceDid, role, actor) {
1326
1364
  await this.db
1327
- .prepare("UPDATE memberships SET role = ?, updated_at = ?, updated_by = ? WHERE user_did = ? AND instance_did = ?")
1365
+ .prepare("UPDATE cs_memberships SET role = ?, updated_at = ?, updated_by = ? WHERE user_did = ? AND instance_did = ?")
1328
1366
  .bind(role, new Date().toISOString(), actor, userDid, instanceDid)
1329
1367
  .run();
1330
1368
  invalidateMembership(userDid, instanceDid);
1331
1369
  }
1332
1370
  async deleteMembership(userDid, instanceDid) {
1333
1371
  await this.db
1334
- .prepare("DELETE FROM memberships WHERE user_did = ? AND instance_did = ?")
1372
+ .prepare("DELETE FROM cs_memberships WHERE user_did = ? AND instance_did = ?")
1335
1373
  .bind(userDid, instanceDid)
1336
1374
  .run();
1337
1375
  invalidateMembership(userDid, instanceDid);
1338
1376
  }
1339
1377
  async deleteMembershipsByInstance(instanceDid) {
1340
- await this.db.prepare("DELETE FROM memberships WHERE instance_did = ?").bind(instanceDid).run();
1378
+ await this.db.prepare("DELETE FROM cs_memberships WHERE instance_did = ?").bind(instanceDid).run();
1341
1379
  invalidateMembershipsByInstance(instanceDid);
1342
1380
  }
1343
1381
  // ─── Settings CRUD ─────────────────────────────────────────────────────
1344
1382
  async getSetting(instanceDid, key) {
1345
1383
  const row = await this.db
1346
- .prepare("SELECT value FROM settings WHERE instance_did = ? AND key = ?")
1384
+ .prepare("SELECT value FROM cs_settings WHERE instance_did = ? AND key = ?")
1347
1385
  .bind(instanceDid, key)
1348
1386
  .first();
1349
1387
  return row?.value ?? null;
@@ -1351,7 +1389,7 @@ export class D1Store {
1351
1389
  async setSetting(instanceDid, key, value, actor) {
1352
1390
  try {
1353
1391
  await this.db
1354
- .prepare(`INSERT INTO settings (instance_did, key, value, updated_at, created_at, created_by, updated_by)
1392
+ .prepare(`INSERT INTO cs_settings (instance_did, key, value, updated_at, created_at, created_by, updated_by)
1355
1393
  VALUES (?, ?, ?, datetime('now'), datetime('now'), ?, ?)
1356
1394
  ON CONFLICT(instance_did, key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at, updated_by = excluded.updated_by`)
1357
1395
  .bind(instanceDid, key, value, actor, actor)
@@ -1362,7 +1400,7 @@ export class D1Store {
1362
1400
  const msg = err instanceof Error ? err.message : String(err);
1363
1401
  if (msg.includes("UNIQUE constraint")) {
1364
1402
  await this.db
1365
- .prepare(`UPDATE settings SET value = ?, updated_at = datetime('now'), updated_by = ? WHERE instance_did = ? AND key = ?`)
1403
+ .prepare(`UPDATE cs_settings SET value = ?, updated_at = datetime('now'), updated_by = ? WHERE instance_did = ? AND key = ?`)
1366
1404
  .bind(value, actor, instanceDid, key)
1367
1405
  .run();
1368
1406
  }
@@ -1373,14 +1411,14 @@ export class D1Store {
1373
1411
  }
1374
1412
  async listSettings(instanceDid) {
1375
1413
  const rows = await this.db
1376
- .prepare("SELECT key, value, updated_at FROM settings WHERE instance_did = ? ORDER BY key")
1414
+ .prepare("SELECT key, value, updated_at FROM cs_settings WHERE instance_did = ? ORDER BY key")
1377
1415
  .bind(instanceDid)
1378
1416
  .all();
1379
1417
  return rows.results ?? [];
1380
1418
  }
1381
1419
  async deleteSetting(instanceDid, key) {
1382
1420
  await this.db
1383
- .prepare("DELETE FROM settings WHERE instance_did = ? AND key = ?")
1421
+ .prepare("DELETE FROM cs_settings WHERE instance_did = ? AND key = ?")
1384
1422
  .bind(instanceDid, key)
1385
1423
  .run();
1386
1424
  }
@@ -1388,13 +1426,13 @@ export class D1Store {
1388
1426
  async batchDeleteSettings(entries) {
1389
1427
  if (entries.length === 0)
1390
1428
  return;
1391
- const stmts = entries.map(({ instanceDid, key }) => this.db.prepare("DELETE FROM settings WHERE instance_did = ? AND key = ?").bind(instanceDid, key));
1429
+ const stmts = entries.map(({ instanceDid, key }) => this.db.prepare("DELETE FROM cs_settings WHERE instance_did = ? AND key = ?").bind(instanceDid, key));
1392
1430
  await this.db.batch(stmts);
1393
1431
  }
1394
1432
  async listSettingsByPrefix(instanceDid, keyPrefix) {
1395
1433
  await this.ensureSchema();
1396
1434
  const rows = await this.db
1397
- .prepare("SELECT key, value, updated_at FROM settings WHERE instance_did = ? AND key LIKE ? ORDER BY key")
1435
+ .prepare("SELECT key, value, updated_at FROM cs_settings WHERE instance_did = ? AND key LIKE ? ORDER BY key")
1398
1436
  .bind(instanceDid, `${keyPrefix}%`)
1399
1437
  .all();
1400
1438
  return rows.results ?? [];
@@ -1403,7 +1441,7 @@ export class D1Store {
1403
1441
  async findSettingByKey(key) {
1404
1442
  await this.ensureSchema();
1405
1443
  const rows = await this.db
1406
- .prepare("SELECT instance_did, value FROM settings WHERE key = ? ORDER BY instance_did")
1444
+ .prepare("SELECT instance_did, value FROM cs_settings WHERE key = ? ORDER BY instance_did")
1407
1445
  .bind(key)
1408
1446
  .all();
1409
1447
  return (rows.results ?? []).map((r) => ({ instanceDid: r.instance_did, value: r.value }));
@@ -1434,7 +1472,7 @@ export class D1Store {
1434
1472
  if (cached && Date.now() - cached.at < HOST_CACHE_TTL)
1435
1473
  return cached.instanceDid;
1436
1474
  const row = await this.db
1437
- .prepare("SELECT instance_did FROM instance_hosts WHERE host = ?")
1475
+ .prepare("SELECT instance_did FROM cs_instance_hosts WHERE host = ?")
1438
1476
  .bind(h)
1439
1477
  .first();
1440
1478
  if (row)
@@ -1449,7 +1487,7 @@ export class D1Store {
1449
1487
  if (!h)
1450
1488
  return { ok: false, reason: "invalid" };
1451
1489
  const res = await this.db
1452
- .prepare("INSERT INTO instance_hosts (host, instance_did, updated_at, created_by, updated_by) VALUES (?, ?, datetime('now'), ?, ?) ON CONFLICT(host) DO NOTHING")
1490
+ .prepare("INSERT INTO cs_instance_hosts (host, instance_did, updated_at, created_by, updated_by) VALUES (?, ?, datetime('now'), ?, ?) ON CONFLICT(host) DO NOTHING")
1453
1491
  .bind(h, instanceDid, actor, actor)
1454
1492
  .run();
1455
1493
  if ((res.meta?.changes ?? 0) > 0) {
@@ -1458,7 +1496,7 @@ export class D1Store {
1458
1496
  }
1459
1497
  // Row already existed — read committed value from D1 (not cache) to decide.
1460
1498
  const owner = await this.db
1461
- .prepare("SELECT instance_did FROM instance_hosts WHERE host = ?")
1499
+ .prepare("SELECT instance_did FROM cs_instance_hosts WHERE host = ?")
1462
1500
  .bind(h)
1463
1501
  .first();
1464
1502
  if (owner?.instance_did === instanceDid)
@@ -1470,26 +1508,26 @@ export class D1Store {
1470
1508
  const h = this.normalizeHost(host);
1471
1509
  if (!h)
1472
1510
  return;
1473
- await this.db.prepare("DELETE FROM instance_hosts WHERE host = ?").bind(h).run();
1511
+ await this.db.prepare("DELETE FROM cs_instance_hosts WHERE host = ?").bind(h).run();
1474
1512
  invalidateHostCache();
1475
1513
  }
1476
1514
  /** List all hosts bound to an instance (normalized form). */
1477
1515
  async listInstanceHosts(instanceDid) {
1478
1516
  const rows = await this.db
1479
- .prepare("SELECT host FROM instance_hosts WHERE instance_did = ? ORDER BY host")
1517
+ .prepare("SELECT host FROM cs_instance_hosts WHERE instance_did = ? ORDER BY host")
1480
1518
  .bind(instanceDid)
1481
1519
  .all();
1482
1520
  return (rows.results ?? []).map((r) => r.host);
1483
1521
  }
1484
1522
  /** Delete all host bindings for an instance (used during instance removal). */
1485
1523
  async deleteInstanceHosts(instanceDid) {
1486
- await this.db.prepare("DELETE FROM instance_hosts WHERE instance_did = ?").bind(instanceDid).run();
1524
+ await this.db.prepare("DELETE FROM cs_instance_hosts WHERE instance_did = ?").bind(instanceDid).run();
1487
1525
  invalidateHostCache();
1488
1526
  }
1489
1527
  // ─── Verify codes (Email Login) ────────────────────────────────────────
1490
1528
  async createVerifyCode(code, subject, purpose) {
1491
1529
  const result = await this.db
1492
- .prepare("INSERT INTO verify_codes (code, subject, purpose) VALUES (?, ?, ?)")
1530
+ .prepare("INSERT INTO cs_verify_codes (code, subject, purpose) VALUES (?, ?, ?)")
1493
1531
  .bind(code, subject, purpose)
1494
1532
  .run();
1495
1533
  // D1 returns last_row_id in meta
@@ -1500,11 +1538,11 @@ export class D1Store {
1500
1538
  // then SELECT to retrieve data. batch() is transactional in D1.
1501
1539
  const [updateResult, selectResult] = await this.db.batch([
1502
1540
  this.db
1503
- .prepare(`UPDATE verify_codes SET verified = 1, verified_at = datetime('now')
1541
+ .prepare(`UPDATE cs_verify_codes SET verified = 1, verified_at = datetime('now')
1504
1542
  WHERE code = ? AND verified = 0
1505
1543
  AND created_at > datetime('now', '-30 minutes')`)
1506
1544
  .bind(code),
1507
- this.db.prepare("SELECT id, subject FROM verify_codes WHERE code = ?").bind(code),
1545
+ this.db.prepare("SELECT id, subject FROM cs_verify_codes WHERE code = ?").bind(code),
1508
1546
  ]);
1509
1547
  if (!updateResult.meta?.changes)
1510
1548
  return null;
@@ -1512,7 +1550,7 @@ export class D1Store {
1512
1550
  }
1513
1551
  async isVerifyCodeSent(subject) {
1514
1552
  const row = await this.db
1515
- .prepare(`SELECT 1 FROM verify_codes
1553
+ .prepare(`SELECT 1 FROM cs_verify_codes
1516
1554
  WHERE subject = ? AND sent = 1
1517
1555
  AND sent_at > datetime('now', '-1 minute')`)
1518
1556
  .bind(subject)
@@ -1521,46 +1559,46 @@ export class D1Store {
1521
1559
  }
1522
1560
  async markVerifyCodeSent(code) {
1523
1561
  await this.db
1524
- .prepare("UPDATE verify_codes SET sent = 1, sent_at = datetime('now') WHERE code = ?")
1562
+ .prepare("UPDATE cs_verify_codes SET sent = 1, sent_at = datetime('now') WHERE code = ?")
1525
1563
  .bind(code)
1526
1564
  .run();
1527
1565
  }
1528
1566
  async purgeExpiredVerifyCodes() {
1529
1567
  await this.db
1530
- .prepare("DELETE FROM verify_codes WHERE created_at < datetime('now', '-1 hour')")
1568
+ .prepare("DELETE FROM cs_verify_codes WHERE created_at < datetime('now', '-1 hour')")
1531
1569
  .run();
1532
1570
  }
1533
1571
  // ─── Login tickets (Federation) ────────────────────────────────────────
1534
1572
  async createLoginTicket(ticket, did, targetOrigin, ttlSeconds = 300) {
1535
1573
  await this.db
1536
- .prepare(`INSERT INTO login_tickets (ticket, did, target_origin, expires_at)
1574
+ .prepare(`INSERT INTO cs_login_tickets (ticket, did, target_origin, expires_at)
1537
1575
  VALUES (?, ?, ?, datetime('now', '+' || ? || ' seconds'))`)
1538
1576
  .bind(ticket, did, targetOrigin || null, ttlSeconds)
1539
1577
  .run();
1540
1578
  }
1541
1579
  async getLoginTicket(ticket) {
1542
1580
  return this.db
1543
- .prepare(`SELECT ticket, did, target_origin FROM login_tickets
1581
+ .prepare(`SELECT ticket, did, target_origin FROM cs_login_tickets
1544
1582
  WHERE ticket = ? AND expires_at > datetime('now')`)
1545
1583
  .bind(ticket)
1546
1584
  .first();
1547
1585
  }
1548
1586
  async deleteLoginTicket(ticket) {
1549
- await this.db.prepare("DELETE FROM login_tickets WHERE ticket = ?").bind(ticket).run();
1587
+ await this.db.prepare("DELETE FROM cs_login_tickets WHERE ticket = ?").bind(ticket).run();
1550
1588
  }
1551
1589
  async purgeExpiredLoginTickets() {
1552
- await this.db.prepare("DELETE FROM login_tickets WHERE expires_at < datetime('now')").run();
1590
+ await this.db.prepare("DELETE FROM cs_login_tickets WHERE expires_at < datetime('now')").run();
1553
1591
  }
1554
1592
  async deleteLoginTicketsByOrigin(origin) {
1555
1593
  await this.ensureSchema();
1556
1594
  await this.db
1557
- .prepare("DELETE FROM login_tickets WHERE target_origin = ?")
1595
+ .prepare("DELETE FROM cs_login_tickets WHERE target_origin = ?")
1558
1596
  .bind(origin)
1559
1597
  .run();
1560
1598
  }
1561
1599
  async deleteAllLoginTickets() {
1562
1600
  await this.ensureSchema();
1563
- await this.db.prepare("DELETE FROM login_tickets").run();
1601
+ await this.db.prepare("DELETE FROM cs_login_tickets").run();
1564
1602
  }
1565
1603
  // ─── Instance default rule seeding ──────────────────────────────────────
1566
1604
  async seedInstanceDefaults(instanceDid) {
@@ -1597,13 +1635,13 @@ export class D1Store {
1597
1635
  },
1598
1636
  ];
1599
1637
  await this.db.batch(policies.map((p) => this.db
1600
- .prepare(`INSERT OR IGNORE INTO access_policies (id, name, description, roles, reverse, isProtected, instance_did, createdAt, updatedAt, createdBy, updatedBy)
1638
+ .prepare(`INSERT OR IGNORE INTO cs_access_policies (id, name, description, roles, reverse, isProtected, instance_did, createdAt, updatedAt, createdBy, updatedBy)
1601
1639
  VALUES (?, ?, ?, ?, ?, 1, ?, ?, ?, 'system', 'system')`)
1602
1640
  .bind(p.id, p.name, p.description, p.roles, p.reverse, instanceDid, now, now)));
1603
1641
  // Seed instance default rule referencing the instance-scoped public policy
1604
1642
  const ruleId = `default-${instanceDid}`;
1605
1643
  await this.db
1606
- .prepare(`INSERT OR IGNORE INTO security_rules
1644
+ .prepare(`INSERT OR IGNORE INTO cs_security_rules
1607
1645
  (id, pathPattern, priority, accessPolicyId, enabled, remark, instance_did, createdAt, updatedAt, createdBy, updatedBy)
1608
1646
  VALUES (?, '*', 0, ?, 1, 'Instance default: public access', ?, ?, ?, 'system', 'system')`)
1609
1647
  .bind(ruleId, `public-${instanceDid}`, instanceDid, now, now)
@@ -1618,8 +1656,8 @@ export class D1Store {
1618
1656
  }
1619
1657
  const rows = await this.db
1620
1658
  .prepare(`SELECT r.id, r.pathPattern, r.priority, p.roles, p.reverse, r.enabled
1621
- FROM security_rules r
1622
- JOIN access_policies p ON r.accessPolicyId = p.id
1659
+ FROM cs_security_rules r
1660
+ JOIN cs_access_policies p ON r.accessPolicyId = p.id
1623
1661
  WHERE r.enabled = 1
1624
1662
  AND (r.instance_did = ?1 OR r.instance_did IS NULL)
1625
1663
  AND (p.instance_did = ?1 OR p.instance_did IS NULL)
@@ -1642,8 +1680,8 @@ export class D1Store {
1642
1680
  }
1643
1681
  const rows = await this.db
1644
1682
  .prepare(`SELECT r.id, r.pathPattern, r.priority, p.roles, p.reverse, r.enabled
1645
- FROM security_rules r
1646
- JOIN access_policies p ON r.accessPolicyId = p.id
1683
+ FROM cs_security_rules r
1684
+ JOIN cs_access_policies p ON r.accessPolicyId = p.id
1647
1685
  WHERE r.enabled = 1
1648
1686
  ORDER BY CASE WHEN r.id = 'default' THEN 1 ELSE 0 END, r.priority ASC`)
1649
1687
  .all();
@@ -1655,46 +1693,46 @@ export class D1Store {
1655
1693
  async createAccessKeySession(params) {
1656
1694
  const now = new Date().toISOString();
1657
1695
  await this.db
1658
- .prepare(`INSERT INTO access_key_sessions (id, challenge, status, access_key_id, access_key_secret_encrypted, source, created_at, expires_at)
1696
+ .prepare(`INSERT INTO cs_access_key_sessions (id, challenge, status, access_key_id, access_key_secret_encrypted, source, created_at, expires_at)
1659
1697
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
1660
1698
  .bind(params.id, params.challenge, "pending", null, null, params.source, now, params.expiresAt)
1661
1699
  .run();
1662
1700
  }
1663
1701
  async getAccessKeySession(id) {
1664
1702
  const row = await this.db
1665
- .prepare(`SELECT * FROM access_key_sessions WHERE id = ? AND expires_at > datetime('now')`)
1703
+ .prepare(`SELECT * FROM cs_access_key_sessions WHERE id = ? AND expires_at > datetime('now')`)
1666
1704
  .bind(id)
1667
1705
  .first();
1668
1706
  return row ?? null;
1669
1707
  }
1670
1708
  async updateAccessKeySession(id, updates) {
1671
1709
  await this.db
1672
- .prepare(`UPDATE access_key_sessions SET status = ?, access_key_id = ?, access_key_secret_encrypted = ? WHERE id = ?`)
1710
+ .prepare(`UPDATE cs_access_key_sessions SET status = ?, access_key_id = ?, access_key_secret_encrypted = ? WHERE id = ?`)
1673
1711
  .bind(updates.status, updates.accessKeyId, updates.accessKeySecretEncrypted, id)
1674
1712
  .run();
1675
1713
  }
1676
1714
  async deleteAccessKeySession(id) {
1677
1715
  await this.db
1678
- .prepare(`DELETE FROM access_key_sessions WHERE id = ?`)
1716
+ .prepare(`DELETE FROM cs_access_key_sessions WHERE id = ?`)
1679
1717
  .bind(id)
1680
1718
  .run();
1681
1719
  }
1682
1720
  async purgeExpiredAccessKeySessions() {
1683
1721
  await this.db
1684
- .prepare(`DELETE FROM access_key_sessions WHERE expires_at <= datetime('now')`)
1722
+ .prepare(`DELETE FROM cs_access_key_sessions WHERE expires_at <= datetime('now')`)
1685
1723
  .run();
1686
1724
  }
1687
1725
  // ── Generic KV cache (kv_cache table) ─────────────────────────────────
1688
1726
  /** Read a cached value. Returns null if missing or expired (lazy-deletes expired rows). */
1689
1727
  async cacheGet(key) {
1690
1728
  const row = await this.db
1691
- .prepare("SELECT value, expires_at FROM kv_cache WHERE key = ?")
1729
+ .prepare("SELECT value, expires_at FROM cs_kv_cache WHERE key = ?")
1692
1730
  .bind(key)
1693
1731
  .first();
1694
1732
  if (!row)
1695
1733
  return null;
1696
1734
  if (row.expires_at < Math.floor(Date.now() / 1000)) {
1697
- this.db.prepare("DELETE FROM kv_cache WHERE key = ?").bind(key).run().catch(() => { });
1735
+ this.db.prepare("DELETE FROM cs_kv_cache WHERE key = ?").bind(key).run().catch(() => { });
1698
1736
  return null;
1699
1737
  }
1700
1738
  return row.value;
@@ -1703,7 +1741,7 @@ export class D1Store {
1703
1741
  async cachePut(key, value, ttlSeconds) {
1704
1742
  const expiresAt = Math.floor(Date.now() / 1000) + ttlSeconds;
1705
1743
  await this.db
1706
- .prepare("INSERT OR REPLACE INTO kv_cache (key, value, expires_at) VALUES (?, ?, ?)")
1744
+ .prepare("INSERT OR REPLACE INTO cs_kv_cache (key, value, expires_at) VALUES (?, ?, ?)")
1707
1745
  .bind(key, value, expiresAt)
1708
1746
  .run();
1709
1747
  if (Math.random() < 0.05) {
@@ -1712,12 +1750,12 @@ export class D1Store {
1712
1750
  }
1713
1751
  /** Delete a cached value. */
1714
1752
  async cacheDelete(key) {
1715
- await this.db.prepare("DELETE FROM kv_cache WHERE key = ?").bind(key).run();
1753
+ await this.db.prepare("DELETE FROM cs_kv_cache WHERE key = ?").bind(key).run();
1716
1754
  }
1717
1755
  /** Purge all expired cache rows. */
1718
1756
  async purgeExpiredCache() {
1719
1757
  const now = Math.floor(Date.now() / 1000);
1720
- await this.db.prepare("DELETE FROM kv_cache WHERE expires_at < ?").bind(now).run();
1758
+ await this.db.prepare("DELETE FROM cs_kv_cache WHERE expires_at < ?").bind(now).run();
1721
1759
  }
1722
1760
  // ─── Instance registration queries ──────────────────────────────────────
1723
1761
  /** List all registered instances (those with an app:sk setting). */
@@ -1727,10 +1765,10 @@ export class D1Store {
1727
1765
  COALESCE(s2.value, json_extract(s4.value, '$.name')) as app_name,
1728
1766
  CASE WHEN s3.value IS NOT NULL THEN 1 ELSE 0 END as has_psk,
1729
1767
  s1.updated_at as registered_at
1730
- FROM settings s1
1731
- LEFT JOIN settings s2 ON s1.instance_did = s2.instance_did AND s2.key = 'app:name'
1732
- LEFT JOIN settings s3 ON s1.instance_did = s3.instance_did AND s3.key = 'app:psk'
1733
- LEFT JOIN settings s4 ON s1.instance_did = s4.instance_did AND s4.key = 'app:branding'
1768
+ FROM cs_settings s1
1769
+ LEFT JOIN cs_settings s2 ON s1.instance_did = s2.instance_did AND s2.key = 'app:name'
1770
+ LEFT JOIN cs_settings s3 ON s1.instance_did = s3.instance_did AND s3.key = 'app:psk'
1771
+ LEFT JOIN cs_settings s4 ON s1.instance_did = s4.instance_did AND s4.key = 'app:branding'
1734
1772
  WHERE s1.key = 'app:sk'
1735
1773
  ORDER BY s1.updated_at DESC`)
1736
1774
  .all();
@@ -1749,7 +1787,7 @@ export class D1Store {
1749
1787
  const withPrefix = appSk.startsWith("0x") ? appSk : `0x${appSk}`;
1750
1788
  const withoutPrefix = appSk.startsWith("0x") ? appSk.slice(2) : appSk;
1751
1789
  const { results } = await this.db
1752
- .prepare(`SELECT DISTINCT instance_did FROM settings
1790
+ .prepare(`SELECT DISTINCT instance_did FROM cs_settings
1753
1791
  WHERE key = 'app:sk' AND value IN (?, ?)`)
1754
1792
  .bind(withPrefix, withoutPrefix)
1755
1793
  .all();
@@ -1758,7 +1796,7 @@ export class D1Store {
1758
1796
  /** Delete all security rules for a specific instance. */
1759
1797
  async deleteSecurityRulesByInstance(instanceDid) {
1760
1798
  await this.db
1761
- .prepare("DELETE FROM security_rules WHERE instance_did = ?")
1799
+ .prepare("DELETE FROM cs_security_rules WHERE instance_did = ?")
1762
1800
  .bind(instanceDid)
1763
1801
  .run();
1764
1802
  invalidateRulesCache();
@@ -1766,7 +1804,7 @@ export class D1Store {
1766
1804
  /** Delete all access policies for a specific instance. */
1767
1805
  async deleteAccessPoliciesByInstance(instanceDid) {
1768
1806
  await this.db
1769
- .prepare("DELETE FROM access_policies WHERE instance_did = ?")
1807
+ .prepare("DELETE FROM cs_access_policies WHERE instance_did = ?")
1770
1808
  .bind(instanceDid)
1771
1809
  .run();
1772
1810
  invalidateRulesCache();