@hatk/hatk 0.0.1-alpha.12 → 0.0.1-alpha.14

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":"backfill.d.ts","sourceRoot":"","sources":["../src/backfill.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD,6CAA6C;AAC7C,UAAU,YAAY;IACpB,wFAAwF;IACxF,MAAM,EAAE,MAAM,CAAA;IACd,8FAA8F;IAC9F,MAAM,EAAE,MAAM,CAAA;IACd,yEAAyE;IACzE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACxB,qDAAqD;IACrD,MAAM,EAAE,cAAc,CAAA;CACvB;AAuGD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwI/G;AAgCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAiInE"}
1
+ {"version":3,"file":"backfill.d.ts","sourceRoot":"","sources":["../src/backfill.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD,6CAA6C;AAC7C,UAAU,YAAY;IACpB,wFAAwF;IACxF,MAAM,EAAE,MAAM,CAAA;IACd,8FAA8F;IAC9F,MAAM,EAAE,MAAM,CAAA;IACd,yEAAyE;IACzE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACxB,qDAAqD;IACrD,MAAM,EAAE,cAAc,CAAA;CACvB;AAuGD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsJ/G;AAgCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAiInE"}
package/dist/backfill.js CHANGED
@@ -153,10 +153,25 @@ export async function backfillRepo(did, collections, fetchTimeout) {
153
153
  throw httpErr;
154
154
  }
155
155
  resolvedSince = lastRev;
156
- const { roots, blocks, byteLength } = await parseCarStream(res.body);
156
+ let { roots, blocks, byteLength } = await parseCarStream(res.body);
157
157
  carSizeBytes = byteLength;
158
- // Decode commit to get MST root
159
- const rootData = blocks.get(roots[0]);
158
+ // Decode commit to get MST root — if the diff CAR is missing the root block,
159
+ // fall back to a full import (the PDS compacted past our `since` rev)
160
+ let rootData = blocks.get(roots[0]);
161
+ if (!rootData && lastRev) {
162
+ lastRev = null;
163
+ resolvedSince = null;
164
+ res = await fetch(baseUrl, { signal: controller.signal });
165
+ if (!res.ok) {
166
+ const httpErr = new Error(`getRepo failed for ${did}: ${res.status}`);
167
+ httpErr.httpStatus = res.status;
168
+ throw httpErr;
169
+ }
170
+ ;
171
+ ({ roots, blocks, byteLength } = await parseCarStream(res.body));
172
+ carSizeBytes = byteLength;
173
+ rootData = blocks.get(roots[0]);
174
+ }
160
175
  if (!rootData)
161
176
  throw new Error(`No root block for ${did}`);
162
177
  const { value: commit } = cborDecode(rootData);
package/dist/config.js CHANGED
@@ -27,7 +27,7 @@ export function loadConfig(configPath) {
27
27
  fetchTimeout: parseInt(env.BACKFILL_FETCH_TIMEOUT || '') || backfillRaw.fetchTimeout || 300,
28
28
  maxRetries: parseInt(env.BACKFILL_MAX_RETRIES || '') || backfillRaw.maxRetries || 5,
29
29
  },
30
- ftsRebuildInterval: parseInt(env.FTS_REBUILD_INTERVAL || '') || parsed.ftsRebuildInterval || 500,
30
+ ftsRebuildInterval: parseInt(env.FTS_REBUILD_INTERVAL || '') || parsed.ftsRebuildInterval || 5000,
31
31
  oauth: null,
32
32
  admins: env.ADMINS ? env.ADMINS.split(',').map((s) => s.trim()) : parsed.admins || [],
33
33
  };
package/dist/db.js CHANGED
@@ -115,8 +115,8 @@ async function all(sql, ...params) {
115
115
  }
116
116
  export async function initDatabase(dbPath, tableSchemas, ddlStatements) {
117
117
  instance = await DuckDBInstance.create(dbPath === ':memory:' ? undefined : dbPath, {
118
- memory_limit: '512MB',
119
- threads: '2',
118
+ memory_limit: '256MB',
119
+ threads: '1',
120
120
  });
121
121
  con = await instance.connect();
122
122
  readCon = await instance.connect();
package/dist/fts.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"fts.d.ts","sourceRoot":"","sources":["../src/fts.ts"],"names":[],"mappings":"AAwEA,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAE7D;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAElE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0FrE;AAokBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB5E"}
1
+ {"version":3,"file":"fts.d.ts","sourceRoot":"","sources":["../src/fts.ts"],"names":[],"mappings":"AAwEA,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAE7D;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAElE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0FrE;AAokBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B5E"}
package/dist/fts.js CHANGED
@@ -752,6 +752,11 @@ export async function rebuildAllIndexes(collections) {
752
752
  errors.push(`${collection}: ${err.message}`);
753
753
  }
754
754
  }
755
+ // Compact WAL to free DuckDB memory after heavy FTS operations
756
+ try {
757
+ await runSQL('CHECKPOINT');
758
+ }
759
+ catch { }
755
760
  emit('fts', 'rebuild', {
756
761
  collections_total: collections.length,
757
762
  collections_rebuilt: rebuilt,
package/dist/main.js CHANGED
@@ -19,8 +19,13 @@ import { runBackfill } from "./backfill.js";
19
19
  import { initOAuth } from "./oauth/server.js";
20
20
  import { loadOnLoginHook } from "./oauth/hooks.js";
21
21
  import { initSetup } from "./setup.js";
22
+ function logMemory(phase) {
23
+ const mem = process.memoryUsage();
24
+ log(`[mem] ${phase}: heap=${Math.round(mem.heapUsed / 1024 / 1024)}MB rss=${Math.round(mem.rss / 1024 / 1024)}MB external=${Math.round(mem.external / 1024 / 1024)}MB arrayBuffers=${Math.round(mem.arrayBuffers / 1024 / 1024)}MB`);
25
+ }
22
26
  const configPath = process.argv[2] || 'config.yaml';
23
27
  const configDir = dirname(resolve(configPath));
28
+ logMemory('startup');
24
29
  // 1. Load config
25
30
  const config = loadConfig(configPath);
26
31
  configureRelay(config.relay);
@@ -74,6 +79,7 @@ if (config.database !== ':memory:') {
74
79
  mkdirSync(dirname(config.database), { recursive: true });
75
80
  }
76
81
  await initDatabase(config.database, schemas, ddlStatements);
82
+ logMemory('after-db-init');
77
83
  log(`[main] DuckDB initialized (${config.database === ':memory:' ? 'in-memory' : config.database})`);
78
84
  // 3b. Run setup hooks (after DB init, before server)
79
85
  await initSetup(resolve(configDir, 'setup'));
@@ -104,6 +110,7 @@ if (config.oauth) {
104
110
  await initOAuth(config.oauth, config.plc, config.relay);
105
111
  log(`[main] OAuth initialized (issuer: ${config.oauth.issuer})`);
106
112
  }
113
+ logMemory('before-server');
107
114
  // 5. Start server immediately (don't wait for backfill)
108
115
  const collectionSet = new Set(collections);
109
116
  startServer(config.port, collections, config.publicDir, config.oauth, config.admins);
@@ -115,6 +122,7 @@ log(` Collections: ${collections.join(', ')}`);
115
122
  log(` Feeds: ${listFeeds()
116
123
  .map((f) => f.name)
117
124
  .join(', ')}`);
125
+ logMemory('after-server');
118
126
  // 6. Start indexer with cursor
119
127
  const cursor = await getCursor('relay');
120
128
  startIndexer({
@@ -145,3 +153,8 @@ runBackfill({
145
153
  .catch((err) => {
146
154
  console.error('[main] Backfill error:', err.message);
147
155
  });
156
+ // Graceful shutdown
157
+ process.on('SIGTERM', () => {
158
+ log('[main] Received SIGTERM, shutting down...');
159
+ process.exit(0);
160
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hatk/hatk",
3
- "version": "0.0.1-alpha.12",
3
+ "version": "0.0.1-alpha.14",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "hatk": "dist/cli.js"