@hatk/hatk 0.0.1-alpha.69 → 0.0.1-alpha.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/database/db.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/database/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAkB,MAAM,aAAa,CAAA;AAC9D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAA;AAI1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAM1D,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AACD,wBAAgB,aAAa,IAAI,UAAU,CAE1C;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAMD,wBAAsB,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAcnG;AAMD,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,WAAW,EAAE,EAC3B,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,IAAI,CAAC,CAqIf;AAED,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAA;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAoED,wBAAsB,aAAa,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CA6F3F;AA0CD,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGnE;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEzE;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGvE;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC1E,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAED,0DAA0D;AAC1D,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjF;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGpE;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAO9G;AAED,wBAAsB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAOlF;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAG1D;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAG5D;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3D;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGvE;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAE3F;AAED,wBAAsB,kBAAkB,CACtC,IAAI,GAAE;IACJ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,CAAC,CAAC,EAAE,MAAM,CAAA;CACN,GACL,OAAO,CAAC;IAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA8B1C;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAmB3E;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAO3E;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAcvE;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKhE;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI/D;AAED,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAQxF;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAiCrD;AAED,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC1B;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,GAAG,EAAE,CAAA;CAAE,CA+BhC;AAED,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC,CAqGf;AAWD,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBjF;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAClG,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CACR,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAAC,CAC7G,CAqBA;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAC5B;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqN9E;AAuCD,UAAU,SAAS;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;CACvB;AAED,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,SAAc,GACnB,OAAO,CAAC;IAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAoF9C;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAgCrE;AAED,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAqCzF;AAED,qEAAqE;AACrE,wBAAsB,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CASjH;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9D,OAAO,CAAC;IAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA2H9C;AAGD,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAEtF;AAED,wBAAsB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/E;AAED,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAClE,OAAO,CAAC,OAAO,YAAY,EAAE,YAAY,CAAC,CAE5C;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAErE;AAED,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOpG;AAED,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EAAE,GACf,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAc9B;AAED,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAKvG;AAED,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EAAE,GACf,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CA6B7B;AAED,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EAAE,GACf,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CASpC;AAED,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,GAC7C,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxB;AAKD,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,GAAG,GAAG,CAI1C;AAED,wBAAsB,YAAY,CAAC,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAc5G;AAED,wBAAgB,UAAU,CACxB,GAAG,EAAE,GAAG,EACR,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAC3C,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,GACvD,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,CAiGrB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGhE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CASpF;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAIlE;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAKtF;AAED,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOxE;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAO3E;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGlE;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAW9E;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAOvF;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAI/E;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAQ9E;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE;IACzC,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;CACnB,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAO1B;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA8B7C;AAED,wBAAsB,aAAa,CACjC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,UAAU,GAAG,WAAW,EAChC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAevD;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAK1D"}
@@ -65,6 +65,17 @@ export async function initDatabase(adapter, dbPath, tableSchemas, ddlStatements)
65
65
  catch { }
66
66
  // Re-queue repos with missing handles so backfill populates them
67
67
  await run(`UPDATE _repos SET status = 'pending' WHERE handle IS NULL`);
68
+ // Covering index for the status rollups the admin overview and backfill queue
69
+ // read. Skipped on DuckDB, which scans the column just as fast and would only
70
+ // pay the ART index's insert cost.
71
+ if (port.dialect !== 'duckdb') {
72
+ await run(`CREATE INDEX IF NOT EXISTS idx_repos_status ON _repos(status)`);
73
+ }
74
+ // resolveHandleToDid runs on every feed request that takes an `actor` handle,
75
+ // and without this it scans all of _repos. Not UNIQUE: during a handle change
76
+ // two rows can briefly claim the same handle, and a constraint violation there
77
+ // would fail the indexer write.
78
+ await run(`CREATE INDEX IF NOT EXISTS idx_repos_handle ON _repos(handle)`);
68
79
  await run(`CREATE TABLE IF NOT EXISTS _cursor (
69
80
  key TEXT PRIMARY KEY,
70
81
  value TEXT NOT NULL
@@ -422,11 +433,21 @@ export async function listReposPaginated(opts = {}) {
422
433
  return { repos: rows, total };
423
434
  }
424
435
  export async function getCollectionCounts() {
436
+ const entries = [...schemas];
425
437
  const counts = {};
426
- for (const [collection, schema] of schemas) {
427
- const rows = await all(`SELECT ${dialect.countAsInteger} as count FROM ${schema.tableName}`);
428
- counts[collection] = Number(rows[0]?.count || 0);
429
- }
438
+ for (const [collection] of entries)
439
+ counts[collection] = 0;
440
+ if (entries.length === 0)
441
+ return counts;
442
+ // One round trip instead of one per collection — reads are serialized on a
443
+ // single connection, so N queries means N waits behind whatever else is
444
+ // reading.
445
+ const sql = entries
446
+ .map(([collection, schema]) => `SELECT '${collection.replace(/'/g, "''")}' as collection, ${dialect.countAsInteger} as count FROM ${schema.tableName}`)
447
+ .join(' UNION ALL ');
448
+ const rows = await all(sql);
449
+ for (const row of rows)
450
+ counts[row.collection] = Number(row.count || 0);
430
451
  return counts;
431
452
  }
432
453
  export async function getRepoStatusCounts() {
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AA0DA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AA4B9C;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAqM3F;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;IACzB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxF,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAk3B5F;AAGD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EAAE,EACrB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,KAAK,EAAE,WAAW,GAAG,IAAI,EACzB,MAAM,GAAE,MAAM,EAAO,EACrB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,GACpB,OAAO,WAAW,EAAE,MAAM,CAG5B"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AA4DA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AA4B9C;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAqM3F;AAgDD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;IACzB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxF,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAy5B5F;AAGD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EAAE,EACrB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,KAAK,EAAE,WAAW,GAAG,IAAI,EACzB,MAAM,GAAE,MAAM,EAAO,EACrB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,GACpB,OAAO,WAAW,EAAE,MAAM,CAG5B"}
package/dist/server.js CHANGED
@@ -1,6 +1,8 @@
1
+ import { createHash } from 'node:crypto';
1
2
  import { existsSync } from 'node:fs';
2
3
  import { readFile } from 'node:fs/promises';
3
4
  import { join, extname } from 'node:path';
5
+ import { gzipSync } from 'node:zlib';
4
6
  import { queryRecords, getRecordByUri, searchRecords, getSchema, reshapeRow, setRepoStatus, getRepoStatus, getRepoRetryInfo, queryLabelsForUris, insertLabels, searchAccounts, listReposPaginated, getCollectionCounts, getRepoStatusCounts, getDatabaseSize, deleteLabels, getRecentRecords, listActiveRepoDids, removeRepo, getRepoHandle, getPreferences, putPreference, insertReport, queryReports, resolveReport, getOpenReportCount, } from "./database/db.js";
5
7
  import { executeFeed, listFeeds } from "./feeds.js";
6
8
  import { executeXrpc, InvalidRequestError, NotFoundError, registerCoreXrpcHandler } from "./xrpc.js";
@@ -240,6 +242,37 @@ export function registerCoreHandlers(collections, oauth) {
240
242
  });
241
243
  }
242
244
  }
245
+ /**
246
+ * Assets we ship inside the package never change while the process is alive, so
247
+ * read, gzip and hash them once. Repeat visits then cost a 304 instead of the
248
+ * full (uncompressed) payload.
249
+ */
250
+ const bundledAssets = new Map();
251
+ async function serveBundledAsset(path, contentType, request, devMode) {
252
+ let asset = devMode ? undefined : bundledAssets.get(path);
253
+ if (!asset) {
254
+ const raw = await readFile(path);
255
+ asset = {
256
+ raw,
257
+ gzip: gzipSync(raw),
258
+ etag: `"${createHash('sha256').update(raw).digest('base64url').slice(0, 16)}"`,
259
+ };
260
+ if (!devMode)
261
+ bundledAssets.set(path, asset);
262
+ }
263
+ const headers = { ETag: asset.etag, 'Cache-Control': 'no-cache' };
264
+ if (request.headers.get('if-none-match') === asset.etag) {
265
+ return new Response(null, { status: 304, headers });
266
+ }
267
+ const acceptEncoding = request.headers.get('accept-encoding');
268
+ const useGzip = !!acceptEncoding && /\bgzip\b/.test(acceptEncoding);
269
+ if (useGzip) {
270
+ headers['Content-Encoding'] = 'gzip';
271
+ headers.Vary = 'Accept-Encoding';
272
+ }
273
+ headers['Content-Type'] = contentType;
274
+ return new Response(Buffer.from(useGzip ? asset.gzip : asset.raw), { status: 200, headers });
275
+ }
243
276
  /**
244
277
  * Create a Web Standard request handler for all hatk routes.
245
278
  * Returns a pure function: (Request) → Promise<Response>
@@ -255,6 +288,37 @@ export function createHandler(config) {
255
288
  return withCors(jsonError(403, 'Admin access required', acceptEncoding));
256
289
  return null; // auth OK
257
290
  }
291
+ // The /admin/info rollups count every row in every collection table, so they get
292
+ // slower as the index grows. Cache them for a few seconds — that collapses the
293
+ // overview's repeat loads and any concurrent requests into one scan — and drop
294
+ // the cache whenever an admin action changes what they report.
295
+ const ADMIN_STATS_TTL_MS = 10_000;
296
+ let adminStats = null;
297
+ function getAdminStats() {
298
+ if (adminStats && Date.now() - adminStats.at < ADMIN_STATS_TTL_MS)
299
+ return adminStats.data;
300
+ const data = (async () => {
301
+ const [repos, duckdb, collections, openReports] = await Promise.all([
302
+ getRepoStatusCounts(),
303
+ getDatabaseSize(),
304
+ getCollectionCounts(),
305
+ getOpenReportCount(),
306
+ ]);
307
+ return { repos, duckdb, collections, openReports };
308
+ })();
309
+ const entry = { at: Date.now(), data };
310
+ adminStats = entry;
311
+ // Don't cache a failure — and keep the rejection handled so it surfaces only
312
+ // at the awaiting request.
313
+ data.catch(() => {
314
+ if (adminStats === entry)
315
+ adminStats = null;
316
+ });
317
+ return data;
318
+ }
319
+ function invalidateAdminStats() {
320
+ adminStats = null;
321
+ }
258
322
  return async (request) => {
259
323
  const url = new URL(request.url);
260
324
  const acceptEncoding = request.headers.get('accept-encoding');
@@ -425,6 +489,7 @@ export function createHandler(config) {
425
489
  await setRepoStatus(did, 'pending');
426
490
  triggerAutoBackfill(did);
427
491
  }
492
+ invalidateAdminStats();
428
493
  return withCors(json({ added: dids.length }, 200, acceptEncoding));
429
494
  }
430
495
  // POST /admin/labels/rescan — retroactively apply label rules
@@ -492,6 +557,7 @@ export function createHandler(config) {
492
557
  if (!did)
493
558
  return withCors(jsonError(400, 'Missing did', acceptEncoding));
494
559
  await setRepoStatus(did, 'takendown');
560
+ invalidateAdminStats();
495
561
  return withCors(json({ ok: true }, 200, acceptEncoding));
496
562
  }
497
563
  // POST /admin/reverse-takedown — reverse a takedown
@@ -503,6 +569,7 @@ export function createHandler(config) {
503
569
  if (!did)
504
570
  return withCors(jsonError(400, 'Missing did', acceptEncoding));
505
571
  await setRepoStatus(did, 'active');
572
+ invalidateAdminStats();
506
573
  return withCors(json({ ok: true }, 200, acceptEncoding));
507
574
  }
508
575
  // GET /admin/search — search records or accounts
@@ -623,6 +690,7 @@ export function createHandler(config) {
623
690
  triggerAutoBackfill(did);
624
691
  }
625
692
  }
693
+ invalidateAdminStats();
626
694
  return withCors(json({ resyncing: repoList.length }, 200, acceptEncoding));
627
695
  }
628
696
  // POST /admin/repos/remove — remove DIDs from tracking
@@ -636,6 +704,7 @@ export function createHandler(config) {
636
704
  for (const did of dids) {
637
705
  await removeRepo(did);
638
706
  }
707
+ invalidateAdminStats();
639
708
  return withCors(json({ removed: dids.length }, 200, acceptEncoding));
640
709
  }
641
710
  // GET /admin/info — aggregate status + db size + collection counts
@@ -643,9 +712,7 @@ export function createHandler(config) {
643
712
  const denied = requireAdmin(viewer, acceptEncoding);
644
713
  if (denied)
645
714
  return denied;
646
- const counts = await getRepoStatusCounts();
647
- const dbInfo = await getDatabaseSize();
648
- const collectionCounts = await getCollectionCounts();
715
+ const stats = await getAdminStats();
649
716
  const mem = process.memoryUsage();
650
717
  const node = {
651
718
  rss: `${(mem.rss / 1024 / 1024).toFixed(1)} MiB`,
@@ -653,8 +720,13 @@ export function createHandler(config) {
653
720
  heapTotal: `${(mem.heapTotal / 1024 / 1024).toFixed(1)} MiB`,
654
721
  external: `${(mem.external / 1024 / 1024).toFixed(1)} MiB`,
655
722
  };
656
- const openReports = await getOpenReportCount();
657
- return withCors(json({ repos: counts, duckdb: dbInfo, node, collections: collectionCounts, openReports }, 200, acceptEncoding));
723
+ return withCors(json({
724
+ repos: stats.repos,
725
+ duckdb: stats.duckdb,
726
+ node,
727
+ collections: stats.collections,
728
+ openReports: stats.openReports,
729
+ }, 200, acceptEncoding));
658
730
  }
659
731
  // GET /admin/reports — list reports
660
732
  if (url.pathname === '/admin/reports' && request.method === 'GET') {
@@ -684,6 +756,7 @@ export function createHandler(config) {
684
756
  if (action === 'resolve') {
685
757
  await insertLabels([{ src: 'admin', uri: report.subjectUri, val: report.label }]);
686
758
  }
759
+ invalidateAdminStats();
687
760
  return withCors(json({ ok: true }, 200, acceptEncoding));
688
761
  }
689
762
  // GET /admin/info/:did — repo status info
@@ -953,8 +1026,7 @@ export function createHandler(config) {
953
1026
  if (url.pathname === '/admin' || url.pathname === '/admin/') {
954
1027
  const adminPath = join(import.meta.dirname, '../public/admin.html');
955
1028
  try {
956
- const content = await readFile(adminPath);
957
- return withCors(file(content, 'text/html'));
1029
+ return withCors(await serveBundledAsset(adminPath, 'text/html', request, devMode));
958
1030
  }
959
1031
  catch {
960
1032
  return withCors(new Response('Admin page not found', { status: 404 }));
@@ -964,8 +1036,7 @@ export function createHandler(config) {
964
1036
  if (url.pathname === '/admin/admin-auth.js') {
965
1037
  const authPath = join(import.meta.dirname, '../public/admin-auth.js');
966
1038
  try {
967
- const content = await readFile(authPath);
968
- return withCors(file(content, 'application/javascript'));
1039
+ return withCors(await serveBundledAsset(authPath, 'application/javascript', request, devMode));
969
1040
  }
970
1041
  catch {
971
1042
  return notFound();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hatk/hatk",
3
- "version": "0.0.1-alpha.69",
3
+ "version": "0.0.1-alpha.70",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "hatk": "dist/cli.js"
@@ -1,320 +1,285 @@
1
- function g(s) {
2
- const t = s instanceof Uint8Array ? s : new Uint8Array(s)
3
- let o = ''
4
- for (let e = 0; e < t.length; e++) o += String.fromCharCode(t[e])
5
- return btoa(o).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
1
+ //#region ../oauth-client/src/crypto.js
2
+ function e(e) {
3
+ let t = e instanceof Uint8Array ? e : new Uint8Array(e), n = "";
4
+ for (let e = 0; e < t.length; e++) n += String.fromCharCode(t[e]);
5
+ return btoa(n).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
6
6
  }
7
- function f(s = 32) {
8
- return g(crypto.getRandomValues(new Uint8Array(s)))
7
+ function t(t = 32) {
8
+ return e(crypto.getRandomValues(new Uint8Array(t)));
9
9
  }
10
- async function D(s) {
11
- return new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(s)))
10
+ async function n(e) {
11
+ return new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(e)));
12
12
  }
13
- async function k(s) {
14
- return g(await D(s))
13
+ async function r(t) {
14
+ return e(await n(t));
15
15
  }
16
- async function E(s, t, o) {
17
- const e = new TextEncoder(),
18
- n = g(e.encode(JSON.stringify(s))),
19
- r = g(e.encode(JSON.stringify(t))),
20
- a = `${n}.${r}`,
21
- i = await crypto.subtle.sign({ name: 'ECDSA', hash: 'SHA-256' }, o, e.encode(a))
22
- return `${a}.${g(i)}`
16
+ async function i(t, n, r) {
17
+ let i = new TextEncoder(), a = `${e(i.encode(JSON.stringify(t)))}.${e(i.encode(JSON.stringify(n)))}`;
18
+ return `${a}.${e(await crypto.subtle.sign({
19
+ name: "ECDSA",
20
+ hash: "SHA-256"
21
+ }, r, i.encode(a)))}`;
23
22
  }
24
- const x = 1,
25
- d = 'dpop-keys',
26
- p = 'dpop-key',
27
- y = /* @__PURE__ */ new Map()
28
- function m(s) {
29
- const t = y.get(s)
30
- if (t) return t
31
- const o = new Promise((e, n) => {
32
- const r = indexedDB.open(`appview-oauth-${s}`, x)
33
- ;((r.onerror = () => n(r.error)),
34
- (r.onsuccess = () => e(r.result)),
35
- (r.onupgradeneeded = (a) => {
36
- const i = a.target.result
37
- i.objectStoreNames.contains(d) || i.createObjectStore(d, { keyPath: 'id' })
38
- }))
39
- })
40
- return (y.set(s, o), o)
23
+ //#endregion
24
+ //#region ../oauth-client/src/dpop.js
25
+ var a = "dpop-keys", o = "dpop-key", s = /* @__PURE__ */ new Map();
26
+ function c(e) {
27
+ let t = s.get(e);
28
+ if (t) return t;
29
+ let n = new Promise((t, n) => {
30
+ let r = indexedDB.open(`appview-oauth-${e}`, 1);
31
+ r.onerror = () => n(r.error), r.onsuccess = () => t(r.result), r.onupgradeneeded = (e) => {
32
+ let t = e.target.result;
33
+ t.objectStoreNames.contains(a) || t.createObjectStore(a, { keyPath: "id" });
34
+ };
35
+ });
36
+ return s.set(e, n), n;
41
37
  }
42
- async function $(s) {
43
- const t = await m(s)
44
- return new Promise((o, e) => {
45
- const r = t.transaction(d, 'readonly').objectStore(d).get(p)
46
- ;((r.onsuccess = () => o(r.result || null)), (r.onerror = () => e(r.error)))
47
- })
38
+ async function l(e) {
39
+ let t = await c(e);
40
+ return new Promise((e, n) => {
41
+ let r = t.transaction(a, "readonly").objectStore(a).get(o);
42
+ r.onsuccess = () => e(r.result || null), r.onerror = () => n(r.error);
43
+ });
48
44
  }
49
- async function b(s, t, o) {
50
- const e = await m(s)
51
- return new Promise((n, r) => {
52
- const i = e.transaction(d, 'readwrite').objectStore(d).put({
53
- id: p,
54
- privateKey: t,
55
- publicJwk: o,
56
- createdAt: Date.now(),
57
- })
58
- ;((i.onsuccess = () => n()), (i.onerror = () => r(i.error)))
59
- })
45
+ async function u(e, t, n) {
46
+ let r = await c(e);
47
+ return new Promise((e, i) => {
48
+ let s = r.transaction(a, "readwrite").objectStore(a).put({
49
+ id: o,
50
+ privateKey: t,
51
+ publicJwk: n,
52
+ createdAt: Date.now()
53
+ });
54
+ s.onsuccess = () => e(), s.onerror = () => i(s.error);
55
+ });
60
56
  }
61
- async function P(s) {
62
- const t = await $(s)
63
- if (t) return t
64
- const o = await crypto.subtle.generateKey(
65
- { name: 'ECDSA', namedCurve: 'P-256' },
66
- !1,
67
- // non-extractable private key
68
- ['sign'],
69
- ),
70
- e = await crypto.subtle.exportKey('jwk', o.publicKey)
71
- return (await b(s, o.privateKey, e), { id: p, privateKey: o.privateKey, publicJwk: e, createdAt: Date.now() })
57
+ async function d(e) {
58
+ let t = await l(e);
59
+ if (t) return t;
60
+ let n = await crypto.subtle.generateKey({
61
+ name: "ECDSA",
62
+ namedCurve: "P-256"
63
+ }, !1, ["sign"]), r = await crypto.subtle.exportKey("jwk", n.publicKey);
64
+ return await u(e, n.privateKey, r), {
65
+ id: o,
66
+ privateKey: n.privateKey,
67
+ publicJwk: r,
68
+ createdAt: Date.now()
69
+ };
72
70
  }
73
- async function v(s) {
74
- const t = await m(s)
75
- return new Promise((o, e) => {
76
- const r = t.transaction(d, 'readwrite').objectStore(d).delete(p)
77
- ;((r.onsuccess = () => o()), (r.onerror = () => e(r.error)))
78
- })
71
+ async function f(e) {
72
+ let t = await c(e);
73
+ return new Promise((e, n) => {
74
+ let r = t.transaction(a, "readwrite").objectStore(a).delete(o);
75
+ r.onsuccess = () => e(), r.onerror = () => n(r.error);
76
+ });
79
77
  }
80
- async function w(s, t, o, e) {
81
- const n = await P(s),
82
- { kty: r, crv: a, x: i, y: c } = n.publicJwk,
83
- h = { alg: 'ES256', typ: 'dpop+jwt', jwk: { kty: r, crv: a, x: i, y: c } },
84
- l = {
85
- jti: f(16),
86
- htm: t,
87
- htu: o.split('?')[0],
88
- iat: Math.floor(Date.now() / 1e3),
89
- }
90
- return (e && (l.ath = await k(e)), E(h, l, n.privateKey))
78
+ async function p(e, n, a, o) {
79
+ let s = await d(e), { kty: c, crv: l, x: u, y: f } = s.publicJwk, p = {
80
+ alg: "ES256",
81
+ typ: "dpop+jwt",
82
+ jwk: {
83
+ kty: c,
84
+ crv: l,
85
+ x: u,
86
+ y: f
87
+ }
88
+ }, m = {
89
+ jti: t(16),
90
+ htm: n,
91
+ htu: a.split("?")[0],
92
+ iat: Math.floor(Date.now() / 1e3)
93
+ };
94
+ return o && (m.ath = await r(o)), i(p, m, s.privateKey);
91
95
  }
92
- function U(s) {
93
- const t = (e) => `appview_${s}_${e}`,
94
- o = /* @__PURE__ */ new Set(['codeVerifier', 'oauthState', 'redirectUri'])
95
- return {
96
- get(e) {
97
- return (o.has(e) ? sessionStorage : localStorage).getItem(t(e))
98
- },
99
- set(e, n) {
100
- ;(o.has(e) ? sessionStorage : localStorage).setItem(t(e), n)
101
- },
102
- remove(e) {
103
- ;(o.has(e) ? sessionStorage : localStorage).removeItem(t(e))
104
- },
105
- clear() {
106
- for (const e of o) sessionStorage.removeItem(t(e))
107
- for (const e of ['accessToken', 'refreshToken', 'tokenExpiresAt', 'userDid', 'clientId'])
108
- localStorage.removeItem(t(e))
109
- },
110
- }
96
+ //#endregion
97
+ //#region ../oauth-client/src/storage.js
98
+ function m(e) {
99
+ let t = (t) => `appview_${e}_${t}`, n = /* @__PURE__ */ new Set([
100
+ "codeVerifier",
101
+ "oauthState",
102
+ "redirectUri"
103
+ ]);
104
+ return {
105
+ get(e) {
106
+ return (n.has(e) ? sessionStorage : localStorage).getItem(t(e));
107
+ },
108
+ set(e, r) {
109
+ (n.has(e) ? sessionStorage : localStorage).setItem(t(e), r);
110
+ },
111
+ remove(e) {
112
+ (n.has(e) ? sessionStorage : localStorage).removeItem(t(e));
113
+ },
114
+ clear() {
115
+ for (let e of n) sessionStorage.removeItem(t(e));
116
+ for (let e of [
117
+ "accessToken",
118
+ "refreshToken",
119
+ "tokenExpiresAt",
120
+ "userDid",
121
+ "clientId"
122
+ ]) localStorage.removeItem(t(e));
123
+ }
124
+ };
111
125
  }
112
- const S = 5e3
113
- async function A(s, t) {
114
- const o = `appview_${s}_lock_${t}`,
115
- e = `${Date.now()}_${Math.random()}`,
116
- n = Date.now() + S
117
- for (; Date.now() < n; ) {
118
- const r = localStorage.getItem(o)
119
- if (r) {
120
- const a = parseInt(r.split('_')[0])
121
- if (Date.now() - a > S) localStorage.removeItem(o)
122
- else {
123
- await new Promise((i) => setTimeout(i, 50))
124
- continue
125
- }
126
- }
127
- if ((localStorage.setItem(o, e), await new Promise((a) => setTimeout(a, 10)), localStorage.getItem(o) === e))
128
- return e
129
- }
130
- return null
126
+ var h = 5e3;
127
+ async function g(e, t) {
128
+ let n = `appview_${e}_lock_${t}`, r = `${Date.now()}_${Math.random()}`, i = Date.now() + h;
129
+ for (; Date.now() < i;) {
130
+ let e = localStorage.getItem(n);
131
+ if (e) {
132
+ let t = parseInt(e.split("_")[0]);
133
+ if (Date.now() - t > h) localStorage.removeItem(n);
134
+ else {
135
+ await new Promise((e) => setTimeout(e, 50));
136
+ continue;
137
+ }
138
+ }
139
+ if (localStorage.setItem(n, r), await new Promise((e) => setTimeout(e, 10)), localStorage.getItem(n) === r) return r;
140
+ }
141
+ return null;
131
142
  }
132
- function O(s, t, o) {
133
- const e = `appview_${s}_lock_${t}`
134
- localStorage.getItem(e) === o && localStorage.removeItem(e)
143
+ function _(e, t, n) {
144
+ let r = `appview_${e}_lock_${t}`;
145
+ localStorage.getItem(r) === n && localStorage.removeItem(r);
135
146
  }
136
- const _ = 6e4
137
- class K {
138
- /**
139
- * @param {object} opts
140
- * @param {string} opts.server - Appview server URL (e.g. 'https://my-appview.example.com')
141
- * @param {string} [opts.clientId] - OAuth client_id (defaults to current origin)
142
- * @param {string} [opts.redirectUri] - Callback URL (defaults to current page)
143
- * @param {string} [opts.scope] - OAuth scope (defaults to 'atproto')
144
- */
145
- constructor({ server: t, clientId: o, redirectUri: e, scope: n }) {
146
- ;((this.server = t.replace(/\/$/, '')),
147
- (this.clientId = o || window.location.origin),
148
- (this.redirectUri = e || window.location.origin + window.location.pathname),
149
- (this.scope = n || 'atproto'),
150
- (this.namespace = this.clientId.replace(/[^a-z0-9]/gi, '_').slice(0, 32)),
151
- (this.storage = U(this.namespace)),
152
- (this._initPromise = null))
153
- }
154
- /** Ensure DPoP key exists in IndexedDB. */
155
- async init() {
156
- return (this._initPromise || (this._initPromise = P(this.namespace)), this._initPromise)
157
- }
158
- /** Start the OAuth login flow (redirects the browser). */
159
- async login(t) {
160
- await this.init()
161
- const o = f(32),
162
- e = await k(o),
163
- n = f(16)
164
- ;(this.storage.set('codeVerifier', o),
165
- this.storage.set('oauthState', n),
166
- this.storage.set('clientId', this.clientId),
167
- this.storage.set('redirectUri', this.redirectUri))
168
- const r = `${this.server}/oauth/par`,
169
- a = await w(this.namespace, 'POST', r),
170
- i = new URLSearchParams({
171
- client_id: this.clientId,
172
- redirect_uri: this.redirectUri,
173
- response_type: 'code',
174
- code_challenge: e,
175
- code_challenge_method: 'S256',
176
- scope: this.scope,
177
- state: n,
178
- })
179
- t && i.set('login_hint', t)
180
- const c = await fetch(r, {
181
- method: 'POST',
182
- headers: {
183
- 'Content-Type': 'application/x-www-form-urlencoded',
184
- DPoP: a,
185
- },
186
- body: i.toString(),
187
- })
188
- if (!c.ok) {
189
- const u = await c.json().catch(() => ({}))
190
- throw new Error(`PAR failed: ${u.error || c.status}`)
191
- }
192
- const { request_uri: h } = await c.json(),
193
- l = new URLSearchParams({
194
- request_uri: h,
195
- client_id: this.clientId,
196
- })
197
- window.location.href = `${this.server}/oauth/authorize?${l}`
198
- }
199
- /**
200
- * Handle the OAuth callback after the redirect.
201
- * Call this on page load — returns true if a callback was processed.
202
- */
203
- async handleCallback() {
204
- const t = new URLSearchParams(window.location.search),
205
- o = t.get('code'),
206
- e = t.get('state'),
207
- n = t.get('error')
208
- if (n) throw new Error(`OAuth error: ${n} - ${t.get('error_description') || ''}`)
209
- if (!o || !e) return !1
210
- const r = this.storage.get('oauthState')
211
- if (e !== r) throw new Error('OAuth state mismatch')
212
- const a = this.storage.get('codeVerifier'),
213
- i = this.storage.get('clientId'),
214
- c = this.storage.get('redirectUri')
215
- if (!a || !i || !c) throw new Error('Missing OAuth session data')
216
- await this.init()
217
- const h = `${this.server}/oauth/token`,
218
- l = await w(this.namespace, 'POST', h),
219
- u = await fetch(h, {
220
- method: 'POST',
221
- headers: {
222
- 'Content-Type': 'application/x-www-form-urlencoded',
223
- DPoP: l,
224
- },
225
- body: new URLSearchParams({
226
- grant_type: 'authorization_code',
227
- code: o,
228
- redirect_uri: c,
229
- client_id: i,
230
- code_verifier: a,
231
- }),
232
- })
233
- if (!u.ok) {
234
- const I = await u.json().catch(() => ({}))
235
- throw new Error(`Token exchange failed: ${I.error_description || u.statusText}`)
236
- }
237
- const T = await u.json()
238
- return (
239
- this._storeTokens(T),
240
- this.storage.remove('codeVerifier'),
241
- this.storage.remove('oauthState'),
242
- this.storage.remove('redirectUri'),
243
- window.history.replaceState({}, document.title, window.location.pathname),
244
- !0
245
- )
246
- }
247
- /** Whether the user is currently logged in (has a non-expired token). */
248
- get isLoggedIn() {
249
- return !!this.storage.get('accessToken') && !!this.storage.get('userDid')
250
- }
251
- /** The logged-in user's DID, or null. */
252
- get did() {
253
- return this.storage.get('userDid')
254
- }
255
- /**
256
- * Make an authenticated fetch request.
257
- * Automatically adds DPoP proof and Authorization header.
258
- * Auto-refreshes expired tokens.
259
- */
260
- async fetch(t, o = {}) {
261
- await this.init()
262
- const e = t.startsWith('http') ? t : `${this.server}${t}`,
263
- n = (o.method || 'GET').toUpperCase(),
264
- r = await this._getValidToken()
265
- if (!r) throw new Error('Not authenticated')
266
- const a = await w(this.namespace, n, e, r),
267
- i = {
268
- ...o.headers,
269
- Authorization: `DPoP ${r}`,
270
- DPoP: a,
271
- }
272
- return fetch(e, { ...o, method: n, headers: i })
273
- }
274
- /** Log out — clear all stored tokens and DPoP keys. */
275
- async logout() {
276
- ;(this.storage.clear(), await v(this.namespace), (this._initPromise = null))
277
- }
278
- // --- Private ---
279
- _storeTokens(t) {
280
- ;(this.storage.set('accessToken', t.access_token),
281
- t.refresh_token && this.storage.set('refreshToken', t.refresh_token),
282
- t.sub && this.storage.set('userDid', t.sub))
283
- const o = Date.now() + (t.expires_in || 3600) * 1e3
284
- this.storage.set('tokenExpiresAt', o.toString())
285
- }
286
- async _getValidToken() {
287
- const t = this.storage.get('accessToken'),
288
- o = parseInt(this.storage.get('tokenExpiresAt') || '0')
289
- if (t && Date.now() < o - _) return t
290
- const e = this.storage.get('refreshToken')
291
- if (!e) return null
292
- const n = await A(this.namespace, 'refresh')
293
- if (!n) return (await new Promise((r) => setTimeout(r, 150)), this.storage.get('accessToken'))
294
- try {
295
- const r = this.storage.get('accessToken'),
296
- a = parseInt(this.storage.get('tokenExpiresAt') || '0')
297
- if (r && Date.now() < a - _) return r
298
- const i = `${this.server}/oauth/token`,
299
- c = await w(this.namespace, 'POST', i),
300
- h = await fetch(i, {
301
- method: 'POST',
302
- headers: {
303
- 'Content-Type': 'application/x-www-form-urlencoded',
304
- DPoP: c,
305
- },
306
- body: new URLSearchParams({
307
- grant_type: 'refresh_token',
308
- refresh_token: e,
309
- client_id: this.storage.get('clientId') || this.clientId,
310
- }),
311
- })
312
- if (!h.ok) return (this.storage.clear(), null)
313
- const l = await h.json()
314
- return (this._storeTokens(l), l.access_token)
315
- } finally {
316
- O(this.namespace, 'refresh', n)
317
- }
318
- }
319
- }
320
- export { K as OAuthClient }
147
+ //#endregion
148
+ //#region ../oauth-client/src/client.js
149
+ var v = 6e4, y = class {
150
+ constructor({ server: e, clientId: t, redirectUri: n, scope: r }) {
151
+ this.server = e.replace(/\/$/, ""), this.clientId = t || window.location.origin, this.redirectUri = n || window.location.origin + window.location.pathname, this.scope = r || "atproto", this.namespace = this.clientId.replace(/[^a-z0-9]/gi, "_").slice(0, 32), this.storage = m(this.namespace), this._initPromise = null, this._refreshPromise = null;
152
+ }
153
+ async init() {
154
+ return this._initPromise ||= d(this.namespace), this._initPromise;
155
+ }
156
+ async login(e) {
157
+ await this.init();
158
+ let n = t(32), i = await r(n), a = t(16);
159
+ this.storage.set("codeVerifier", n), this.storage.set("oauthState", a), this.storage.set("clientId", this.clientId), this.storage.set("redirectUri", this.redirectUri);
160
+ let o = `${this.server}/oauth/par`, s = await p(this.namespace, "POST", o), c = new URLSearchParams({
161
+ client_id: this.clientId,
162
+ redirect_uri: this.redirectUri,
163
+ response_type: "code",
164
+ code_challenge: i,
165
+ code_challenge_method: "S256",
166
+ scope: this.scope,
167
+ state: a
168
+ });
169
+ e && c.set("login_hint", e);
170
+ let l = await fetch(o, {
171
+ method: "POST",
172
+ headers: {
173
+ "Content-Type": "application/x-www-form-urlencoded",
174
+ DPoP: s
175
+ },
176
+ body: c.toString()
177
+ });
178
+ if (!l.ok) {
179
+ let e = await l.json().catch(() => ({}));
180
+ throw Error(`PAR failed: ${e.error || l.status}`);
181
+ }
182
+ let { request_uri: u } = await l.json(), d = new URLSearchParams({
183
+ request_uri: u,
184
+ client_id: this.clientId
185
+ });
186
+ window.location.href = `${this.server}/oauth/authorize?${d}`;
187
+ }
188
+ async handleCallback() {
189
+ let e = new URLSearchParams(window.location.search), t = e.get("code"), n = e.get("state"), r = e.get("error");
190
+ if (r) throw Error(`OAuth error: ${r} - ${e.get("error_description") || ""}`);
191
+ if (!t || !n) return !1;
192
+ if (n !== this.storage.get("oauthState")) throw Error("OAuth state mismatch");
193
+ let i = this.storage.get("codeVerifier"), a = this.storage.get("clientId"), o = this.storage.get("redirectUri");
194
+ if (!i || !a || !o) throw Error("Missing OAuth session data");
195
+ await this.init();
196
+ let s = `${this.server}/oauth/token`, c = await p(this.namespace, "POST", s), l = await fetch(s, {
197
+ method: "POST",
198
+ headers: {
199
+ "Content-Type": "application/x-www-form-urlencoded",
200
+ DPoP: c
201
+ },
202
+ body: new URLSearchParams({
203
+ grant_type: "authorization_code",
204
+ code: t,
205
+ redirect_uri: o,
206
+ client_id: a,
207
+ code_verifier: i
208
+ })
209
+ });
210
+ if (!l.ok) {
211
+ let e = await l.json().catch(() => ({}));
212
+ throw Error(`Token exchange failed: ${e.error_description || l.statusText}`);
213
+ }
214
+ let u = await l.json();
215
+ return this._storeTokens(u), this.storage.remove("codeVerifier"), this.storage.remove("oauthState"), this.storage.remove("redirectUri"), window.history.replaceState({}, document.title, window.location.pathname), !0;
216
+ }
217
+ get isLoggedIn() {
218
+ return !!this.storage.get("accessToken") && !!this.storage.get("userDid");
219
+ }
220
+ get did() {
221
+ return this.storage.get("userDid");
222
+ }
223
+ get handle() {
224
+ return this.storage.get("userHandle");
225
+ }
226
+ async fetch(e, t = {}) {
227
+ await this.init();
228
+ let n = e.startsWith("http") ? e : `${this.server}${e}`, r = (t.method || "GET").toUpperCase(), i = await this._getValidToken();
229
+ if (!i) throw Error("Not authenticated");
230
+ let a = await p(this.namespace, r, n, i), o = {
231
+ ...t.headers,
232
+ Authorization: `DPoP ${i}`,
233
+ DPoP: a
234
+ }, s = await fetch(n, {
235
+ ...t,
236
+ method: r,
237
+ headers: o
238
+ });
239
+ if (s.status === 403 && (await s.clone().json().catch(() => ({}))).error === "ScopeMissingError") throw this.login(this.did), Error("Re-authenticating with updated scopes");
240
+ return s;
241
+ }
242
+ async logout() {
243
+ this.storage.clear(), await f(this.namespace), this._initPromise = null;
244
+ }
245
+ _storeTokens(e) {
246
+ this.storage.set("accessToken", e.access_token), e.refresh_token && this.storage.set("refreshToken", e.refresh_token), e.sub && this.storage.set("userDid", e.sub), e.handle && this.storage.set("userHandle", e.handle);
247
+ let t = Date.now() + (e.expires_in || 3600) * 1e3;
248
+ this.storage.set("tokenExpiresAt", t.toString());
249
+ }
250
+ async _getValidToken() {
251
+ let e = this.storage.get("accessToken"), t = parseInt(this.storage.get("tokenExpiresAt") || "0");
252
+ return e && Date.now() < t - v ? e : (this._refreshPromise ||= this._refresh().finally(() => {
253
+ this._refreshPromise = null;
254
+ }), this._refreshPromise);
255
+ }
256
+ async _refresh() {
257
+ let e = this.storage.get("refreshToken");
258
+ if (!e) return null;
259
+ let t = await g(this.namespace, "refresh");
260
+ if (!t) return await new Promise((e) => setTimeout(e, 150)), this.storage.get("accessToken");
261
+ try {
262
+ let t = this.storage.get("accessToken"), n = parseInt(this.storage.get("tokenExpiresAt") || "0");
263
+ if (t && Date.now() < n - v) return t;
264
+ let r = `${this.server}/oauth/token`, i = await p(this.namespace, "POST", r), a = await fetch(r, {
265
+ method: "POST",
266
+ headers: {
267
+ "Content-Type": "application/x-www-form-urlencoded",
268
+ DPoP: i
269
+ },
270
+ body: new URLSearchParams({
271
+ grant_type: "refresh_token",
272
+ refresh_token: e,
273
+ client_id: this.storage.get("clientId") || this.clientId
274
+ })
275
+ });
276
+ if (!a.ok) return this.storage.clear(), null;
277
+ let o = await a.json();
278
+ return this._storeTokens(o), o.access_token;
279
+ } finally {
280
+ _(this.namespace, "refresh", t);
281
+ }
282
+ }
283
+ };
284
+ //#endregion
285
+ export { y as OAuthClient };
package/public/admin.html CHANGED
@@ -6,10 +6,20 @@
6
6
  <title>Admin</title>
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com" />
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
+ <!-- Loaded off the critical path: media="print" keeps it from blocking the
10
+ first render, and the system-ui/Menlo fallbacks carry until it swaps in. -->
9
11
  <link
10
12
  href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Figtree:wght@400;500;600;700&display=swap"
11
13
  rel="stylesheet"
14
+ media="print"
15
+ onload="this.media = 'all'"
12
16
  />
17
+ <noscript>
18
+ <link
19
+ href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Figtree:wght@400;500;600;700&display=swap"
20
+ rel="stylesheet"
21
+ />
22
+ </noscript>
13
23
  <style>
14
24
  *,
15
25
  *::before,
@@ -1318,6 +1328,8 @@
1318
1328
 
1319
1329
  window.auth = auth
1320
1330
  let labelDefinitions = []
1331
+ // Started during boot so the overview's data is in flight while we auth
1332
+ let overviewPrefetch = null
1321
1333
 
1322
1334
  function toast(msg, type = '') {
1323
1335
  const el = document.createElement('div')
@@ -1397,8 +1409,17 @@
1397
1409
  }
1398
1410
  loginScreen.style.display = 'none'
1399
1411
 
1412
+ // Fire these together — awaiting them one at a time puts three round
1413
+ // trips in front of the first render.
1414
+ const whoamiPromise = api('/admin/whoami')
1415
+ const definitionsPromise = api('/admin/labels/definitions').catch(() => null)
1416
+ if (getURLState().tab === 'overview') {
1417
+ overviewPrefetch = api('/admin/info')
1418
+ overviewPrefetch.catch(() => {}) // loadOverview reports the failure
1419
+ }
1420
+
1400
1421
  try {
1401
- const whoami = await api('/admin/whoami')
1422
+ const whoami = await whoamiPromise
1402
1423
  document.getElementById('viewer-did').textContent = whoami.did
1403
1424
  } catch (e) {
1404
1425
  document.getElementById('error-msg').textContent =
@@ -1409,10 +1430,7 @@
1409
1430
  return
1410
1431
  }
1411
1432
 
1412
- try {
1413
- const result = await api('/admin/labels/definitions')
1414
- labelDefinitions = result.definitions || []
1415
- } catch {}
1433
+ labelDefinitions = (await definitionsPromise)?.definitions || []
1416
1434
 
1417
1435
  appEl.classList.add('visible')
1418
1436
  restoreFromURL()
@@ -1499,7 +1517,9 @@
1499
1517
 
1500
1518
  async function loadOverview() {
1501
1519
  try {
1502
- const info = await api('/admin/info')
1520
+ const pending = overviewPrefetch
1521
+ overviewPrefetch = null
1522
+ const info = await (pending || api('/admin/info'))
1503
1523
  const statusCards = document.getElementById('status-cards')
1504
1524
  const repoStatuses = info.repos || {}
1505
1525
  const total = Object.values(repoStatuses).reduce((a, b) => a + b, 0)