@hatk/hatk 0.0.1-alpha.2 → 0.0.1-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/indexer.js CHANGED
@@ -18,7 +18,7 @@ let ftsRebuildInterval = 500;
18
18
  const pendingBuffers = new Map();
19
19
  // Track in-flight backfills to avoid duplicates
20
20
  const backfillInFlight = new Set();
21
- const MAX_CONCURRENT_BACKFILLS = 5;
21
+ const pendingReschedule = new Set();
22
22
  // In-memory cache of repo status to avoid flooding the DB read queue
23
23
  const repoStatusCache = new Map();
24
24
  // Set by startIndexer
@@ -27,6 +27,7 @@ let indexerSignalCollections;
27
27
  let indexerPinnedRepos = null;
28
28
  let indexerFetchTimeout;
29
29
  let indexerMaxRetries;
30
+ let maxConcurrentBackfills = 3;
30
31
  async function flushBuffer() {
31
32
  if (buffer.length === 0)
32
33
  return;
@@ -113,6 +114,16 @@ function bufferWrite(item) {
113
114
  export async function triggerAutoBackfill(did, attempt = 0) {
114
115
  if (backfillInFlight.has(did))
115
116
  return;
117
+ if (backfillInFlight.size >= maxConcurrentBackfills) {
118
+ if (!pendingReschedule.has(did)) {
119
+ pendingReschedule.add(did);
120
+ setTimeout(() => {
121
+ pendingReschedule.delete(did);
122
+ triggerAutoBackfill(did, attempt);
123
+ }, 10_000);
124
+ }
125
+ return;
126
+ }
116
127
  backfillInFlight.add(did);
117
128
  pendingBuffers.set(did, []);
118
129
  if (attempt === 0)
@@ -193,6 +204,7 @@ export async function startIndexer(opts) {
193
204
  indexerPinnedRepos = opts.pinnedRepos || null;
194
205
  indexerFetchTimeout = fetchTimeout;
195
206
  indexerMaxRetries = opts.maxRetries;
207
+ maxConcurrentBackfills = opts.parallelism ?? 3;
196
208
  // Pre-populate repo status cache from DB so non-signal updates
197
209
  // (e.g. profile changes) are processed for already-tracked DIDs
198
210
  if (repoStatusCache.size === 0) {
@@ -264,7 +276,7 @@ function processMessage(bytes, collections) {
264
276
  repoStatusCache.set(did, 'unknown');
265
277
  }
266
278
  if (hasSignalOp && (!indexerPinnedRepos || indexerPinnedRepos.has(did))) {
267
- if (repoStatus === null && backfillInFlight.size < MAX_CONCURRENT_BACKFILLS) {
279
+ if (repoStatus === null && backfillInFlight.size < maxConcurrentBackfills) {
268
280
  repoStatusCache.set(did, 'pending');
269
281
  triggerAutoBackfill(did);
270
282
  }
package/dist/main.js CHANGED
@@ -5,7 +5,7 @@ import { log } from "./logger.js";
5
5
  import { loadConfig } from "./config.js";
6
6
  import { loadLexicons, storeLexicons, discoverCollections, generateTableSchema, generateCreateTableSQL, } from "./schema.js";
7
7
  import { discoverViews } from "./views.js";
8
- import { initDatabase, getCursor, querySQL, backfillChildTables } from "./db.js";
8
+ import { initDatabase, getCursor, querySQL } from "./db.js";
9
9
  import { initFeeds, listFeeds } from "./feeds.js";
10
10
  import { initXrpc, listXrpc, configureRelay } from "./xrpc.js";
11
11
  import { initOpengraph } from "./opengraph.js";
@@ -19,10 +19,15 @@ 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
- const configPath = process.argv[2] || 'config.yaml';
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
+ }
26
+ const configPath = process.argv[2] || 'hatk.config.ts';
23
27
  const configDir = dirname(resolve(configPath));
28
+ logMemory('startup');
24
29
  // 1. Load config
25
- const config = loadConfig(configPath);
30
+ const config = await loadConfig(configPath);
26
31
  configureRelay(config.relay);
27
32
  // 2. Load lexicons, validate schemas, and discover collections
28
33
  const lexicons = loadLexicons(resolve(configDir, 'lexicons'));
@@ -74,9 +79,8 @@ 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
- // 3a. Backfill child tables for decomposed arrays (one-time migration)
79
- await backfillChildTables();
80
84
  // 3b. Run setup hooks (after DB init, before server)
81
85
  await initSetup(resolve(configDir, 'setup'));
82
86
  // Detect orphaned tables
@@ -106,9 +110,34 @@ if (config.oauth) {
106
110
  await initOAuth(config.oauth, config.plc, config.relay);
107
111
  log(`[main] OAuth initialized (issuer: ${config.oauth.issuer})`);
108
112
  }
113
+ logMemory('before-server');
109
114
  // 5. Start server immediately (don't wait for backfill)
110
115
  const collectionSet = new Set(collections);
111
- startServer(config.port, collections, config.publicDir, config.oauth, config.admins);
116
+ const backfillOpts = {
117
+ pdsUrl: relayHttpUrl(config.relay),
118
+ plcUrl: config.plc,
119
+ collections: collectionSet,
120
+ config: config.backfill,
121
+ };
122
+ function runBackfillAndRestart() {
123
+ runBackfill(backfillOpts)
124
+ .then((recordCount) => {
125
+ log('[main] Backfill complete, rebuilding FTS indexes...');
126
+ return rebuildAllIndexes(collections).then(() => recordCount);
127
+ })
128
+ .then((recordCount) => {
129
+ log('[main] FTS indexes ready');
130
+ if (recordCount > 0) {
131
+ logMemory('after-backfill');
132
+ log('[main] Restarting to reclaim memory...');
133
+ process.exit(1);
134
+ }
135
+ })
136
+ .catch((err) => {
137
+ console.error('[main] Backfill error:', err.message);
138
+ });
139
+ }
140
+ startServer(config.port, collections, config.publicDir, config.oauth, config.admins, undefined, runBackfillAndRestart);
112
141
  log(`\nhatk running:`);
113
142
  log(` Relay: ${config.relay}`);
114
143
  log(` Database: ${config.database}`);
@@ -117,6 +146,7 @@ log(` Collections: ${collections.join(', ')}`);
117
146
  log(` Feeds: ${listFeeds()
118
147
  .map((f) => f.name)
119
148
  .join(', ')}`);
149
+ logMemory('after-server');
120
150
  // 6. Start indexer with cursor
121
151
  const cursor = await getCursor('relay');
122
152
  startIndexer({
@@ -127,22 +157,13 @@ startIndexer({
127
157
  cursor,
128
158
  fetchTimeout: config.backfill.fetchTimeout,
129
159
  maxRetries: config.backfill.maxRetries,
160
+ parallelism: config.backfill.parallelism,
130
161
  ftsRebuildInterval: config.ftsRebuildInterval,
131
162
  });
132
163
  // 7. Run backfill in background
133
- runBackfill({
134
- pdsUrl: relayHttpUrl(config.relay),
135
- plcUrl: config.plc,
136
- collections: collectionSet,
137
- config: config.backfill,
138
- })
139
- .then(() => {
140
- log('[main] Backfill complete, rebuilding FTS indexes...');
141
- return rebuildAllIndexes(collections);
142
- })
143
- .then(() => {
144
- log('[main] FTS indexes ready');
145
- })
146
- .catch((err) => {
147
- console.error('[main] Backfill error:', err.message);
164
+ runBackfillAndRestart();
165
+ // Graceful shutdown
166
+ process.on('SIGTERM', () => {
167
+ log('[main] Received SIGTERM, shutting down...');
168
+ process.exit(0);
148
169
  });
package/dist/mst.d.ts CHANGED
@@ -2,5 +2,7 @@ export interface MstEntry {
2
2
  path: string;
3
3
  cid: string;
4
4
  }
5
- export declare function walkMst(blocks: Map<string, Uint8Array>, rootCid: string): MstEntry[];
5
+ export declare function walkMst(blocks: {
6
+ get(cid: string): Uint8Array | undefined;
7
+ }, rootCid: string): Generator<MstEntry>;
6
8
  //# sourceMappingURL=mst.d.ts.map
package/dist/mst.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mst.d.ts","sourceRoot":"","sources":["../src/mst.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE,CAiCpF"}
1
+ {"version":3,"file":"mst.d.ts","sourceRoot":"","sources":["../src/mst.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,wBAAiB,OAAO,CAAC,MAAM,EAAE;IAAE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAA;CAAE,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CA8BnH"}
package/dist/mst.js CHANGED
@@ -1,14 +1,13 @@
1
1
  import { cborDecode } from "./cbor.js";
2
- export function walkMst(blocks, rootCid) {
3
- const entries = [];
4
- function visit(cid, prefix) {
2
+ export function* walkMst(blocks, rootCid) {
3
+ function* visit(cid, prefix) {
5
4
  const data = blocks.get(cid);
6
5
  if (!data)
7
6
  return prefix;
8
7
  const { value: node } = cborDecode(data);
9
8
  // Visit left subtree
10
9
  if (node.l?.$link)
11
- visit(node.l.$link, prefix);
10
+ yield* visit(node.l.$link, prefix);
12
11
  let lastKey = prefix;
13
12
  for (const entry of node.e || []) {
14
13
  const keySuffix = entry.k instanceof Uint8Array ? new TextDecoder().decode(entry.k) : entry.k;
@@ -16,15 +15,14 @@ export function walkMst(blocks, rootCid) {
16
15
  const fullKey = lastKey.substring(0, prefixLen) + keySuffix;
17
16
  lastKey = fullKey;
18
17
  if (entry.v?.$link) {
19
- entries.push({ path: fullKey, cid: entry.v.$link });
18
+ yield { path: fullKey, cid: entry.v.$link };
20
19
  }
21
20
  // Visit right subtree
22
21
  if (entry.t?.$link) {
23
- visit(entry.t.$link, lastKey);
22
+ yield* visit(entry.t.$link, lastKey);
24
23
  }
25
24
  }
26
25
  return lastKey;
27
26
  }
28
- visit(rootCid, '');
29
- return entries;
27
+ yield* visit(rootCid, '');
30
28
  }
package/dist/server.d.ts CHANGED
@@ -2,5 +2,5 @@ import { type Server, type IncomingMessage } from 'node:http';
2
2
  import type { OAuthConfig } from './config.ts';
3
3
  export declare function startServer(port: number, collections: string[], publicDir: string | null, oauth: OAuthConfig | null, admins?: string[], resolveViewer?: (req: IncomingMessage) => {
4
4
  did: string;
5
- } | null): Server;
5
+ } | null, onResync?: () => void): Server;
6
6
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,KAAK,eAAe,EAAE,MAAM,WAAW,CAAA;AAiD3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AA2B9C,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,GAAG,EAAE,eAAe,KAAK;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAC/D,MAAM,CAm7BR"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,KAAK,eAAe,EAAE,MAAM,WAAW,CAAA;AAmD3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AA2B9C,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,GAAG,EAAE,eAAe,KAAK;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAChE,QAAQ,CAAC,EAAE,MAAM,IAAI,GACpB,MAAM,CA28BR"}
package/dist/server.js CHANGED
@@ -1,4 +1,6 @@
1
1
  import { createServer } from 'node:http';
2
+ import { gzipSync } from 'node:zlib';
3
+ import { existsSync } from 'node:fs';
2
4
  import { readFile } from 'node:fs/promises';
3
5
  import { join, extname } from 'node:path';
4
6
  import { queryRecords, getRecordByUri, searchRecords, getSchema, reshapeRow, setRepoStatus, getRepoStatus, getRepoRetryInfo, querySQL, insertRecord, deleteRecord, queryLabelsForUris, insertLabels, searchAccounts, listReposPaginated, getCollectionCounts, normalizeValue, getSchemaDump, getPreferences, putPreference, } from "./db.js";
@@ -37,14 +39,15 @@ function readBodyRaw(req) {
37
39
  req.on('error', reject);
38
40
  });
39
41
  }
40
- export function startServer(port, collections, publicDir, oauth, admins = [], resolveViewer) {
42
+ export function startServer(port, collections, publicDir, oauth, admins = [], resolveViewer, onResync) {
41
43
  const coreXrpc = (method) => `/xrpc/dev.hatk.${method}`;
44
+ const devMode = process.env.DEV_MODE === '1';
42
45
  function requireAdmin(viewer, res) {
43
46
  if (!viewer) {
44
47
  jsonError(res, 401, 'Authentication required');
45
48
  return false;
46
49
  }
47
- if (!admins.includes(viewer.did)) {
50
+ if (!devMode && !admins.includes(viewer.did)) {
48
51
  jsonError(res, 403, 'Admin access required');
49
52
  return false;
50
53
  }
@@ -447,9 +450,10 @@ export function startServer(port, collections, publicDir, oauth, admins = [], re
447
450
  }
448
451
  for (const did of repoList) {
449
452
  await setRepoStatus(did, 'pending');
450
- triggerAutoBackfill(did);
451
453
  }
452
454
  jsonResponse(res, { resyncing: repoList.length });
455
+ if (onResync)
456
+ onResync();
453
457
  return;
454
458
  }
455
459
  // POST /admin/repos/remove — remove DIDs from tracking
@@ -478,7 +482,14 @@ export function startServer(port, collections, publicDir, oauth, admins = [], re
478
482
  const sizeRows = await querySQL(`SELECT database_size, memory_usage, memory_limit FROM pragma_database_size()`);
479
483
  const dbInfo = sizeRows[0] ?? {};
480
484
  const collectionCounts = await getCollectionCounts();
481
- jsonResponse(res, { repos: counts, duckdb: dbInfo, collections: collectionCounts });
485
+ const mem = process.memoryUsage();
486
+ const node = {
487
+ rss: `${(mem.rss / 1024 / 1024).toFixed(1)} MiB`,
488
+ heapUsed: `${(mem.heapUsed / 1024 / 1024).toFixed(1)} MiB`,
489
+ heapTotal: `${(mem.heapTotal / 1024 / 1024).toFixed(1)} MiB`,
490
+ external: `${(mem.external / 1024 / 1024).toFixed(1)} MiB`,
491
+ };
492
+ jsonResponse(res, { repos: counts, duckdb: dbInfo, node, collections: collectionCounts });
482
493
  return;
483
494
  }
484
495
  // GET /admin/info/:did — repo status info
@@ -864,6 +875,21 @@ export function startServer(port, collections, publicDir, oauth, admins = [], re
864
875
  throw err;
865
876
  }
866
877
  }
878
+ // GET /robots.txt — serve from user's public dir or fall back to hatk default
879
+ if (url.pathname === '/robots.txt') {
880
+ const userRobots = publicDir ? join(publicDir, 'robots.txt') : null;
881
+ const defaultRobots = join(import.meta.dirname, '../public/robots.txt');
882
+ const robotsPath = userRobots && existsSync(userRobots) ? userRobots : defaultRobots;
883
+ try {
884
+ const content = await readFile(robotsPath);
885
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
886
+ res.end(content);
887
+ return;
888
+ }
889
+ catch {
890
+ // fall through
891
+ }
892
+ }
867
893
  // Static file serving
868
894
  if (publicDir) {
869
895
  try {
@@ -912,15 +938,33 @@ export function startServer(port, collections, publicDir, oauth, admins = [], re
912
938
  server.listen(port, () => log(`[server] ${oauth?.issuer || `http://localhost:${port}`}`));
913
939
  return server;
914
940
  }
941
+ function sendJson(res, status, body) {
942
+ const acceptEncoding = res.req?.headers['accept-encoding'] || '';
943
+ if (body.length > 1024 && /\bgzip\b/.test(acceptEncoding)) {
944
+ const compressed = gzipSync(body);
945
+ res.writeHead(status, {
946
+ 'Content-Type': 'application/json',
947
+ 'Content-Encoding': 'gzip',
948
+ Vary: 'Accept-Encoding',
949
+ ...(status === 200 ? { 'Cache-Control': 'no-store' } : {}),
950
+ });
951
+ res.end(compressed);
952
+ }
953
+ else {
954
+ res.writeHead(status, {
955
+ 'Content-Type': 'application/json',
956
+ ...(status === 200 ? { 'Cache-Control': 'no-store' } : {}),
957
+ });
958
+ res.end(body);
959
+ }
960
+ }
915
961
  function jsonResponse(res, data) {
916
- res.writeHead(200, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
917
- res.end(JSON.stringify(data, (_, v) => normalizeValue(v)));
962
+ sendJson(res, 200, Buffer.from(JSON.stringify(data, (_, v) => normalizeValue(v))));
918
963
  }
919
964
  function jsonError(res, status, message) {
920
965
  if (res.headersSent)
921
966
  return;
922
- res.writeHead(status, { 'Content-Type': 'application/json' });
923
- res.end(JSON.stringify({ error: message }));
967
+ sendJson(res, status, Buffer.from(JSON.stringify({ error: message })));
924
968
  }
925
969
  /** Proxy a request to the user's PDS with DPoP + automatic nonce retry + token refresh. */
926
970
  async function proxyToPds(oauthConfig, session, method, pdsUrl, body) {
package/dist/test.js CHANGED
@@ -14,14 +14,14 @@ import { validateLexicons } from '@bigmoves/lexicon';
14
14
  import { packCursor, unpackCursor, isTakendownDid, filterTakendownDids } from "./db.js";
15
15
  import { seed as createSeedHelpers } from "./seed.js";
16
16
  /**
17
- * Find the project's config.yaml by walking up from cwd.
18
- * Returns the resolved config path, or falls back to 'config.yaml'.
17
+ * Find the project's hatk.config.ts by walking up from cwd.
18
+ * Returns the resolved config path, or falls back to 'hatk.config.ts'.
19
19
  */
20
20
  function findConfigPath() {
21
21
  const explicit = process.env.APPVIEW_CONFIG;
22
22
  if (explicit)
23
23
  return resolve(explicit);
24
- return resolve('config.yaml');
24
+ return resolve('hatk.config.ts');
25
25
  }
26
26
  /**
27
27
  * Boot an in-memory hatk context for unit tests.
@@ -34,7 +34,7 @@ function findConfigPath() {
34
34
  */
35
35
  export async function createTestContext() {
36
36
  const configPath = findConfigPath();
37
- const config = loadConfig(configPath);
37
+ const config = await loadConfig(configPath);
38
38
  const configDir = dirname(resolve(configPath));
39
39
  configureRelay(config.relay);
40
40
  // Load and validate lexicons
@@ -1 +1 @@
1
- {"version":3,"file":"vite-plugin.d.ts","sourceRoot":"","sources":["../src/vite-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAKlC,wBAAgB,IAAI,CAAC,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAsFrD"}
1
+ {"version":3,"file":"vite-plugin.d.ts","sourceRoot":"","sources":["../src/vite-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAKlC,wBAAgB,IAAI,CAAC,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAuFrD"}
@@ -64,13 +64,14 @@ export function hatk(opts) {
64
64
  const mainPath = resolve(import.meta.dirname, 'main.js');
65
65
  const watchDirs = ['xrpc', 'feeds', 'labels', 'jobs', 'setup', 'lexicons'].filter((d) => existsSync(d));
66
66
  const watchArgs = watchDirs.flatMap((d) => ['--watch-path', d]);
67
- serverProcess = spawn('npx', ['tsx', 'watch', ...watchArgs, mainPath, 'config.yaml'], {
67
+ serverProcess = spawn('npx', ['tsx', 'watch', ...watchArgs, mainPath, 'hatk.config.ts'], {
68
68
  stdio: 'inherit',
69
69
  cwd: process.cwd(),
70
70
  env: {
71
71
  ...process.env,
72
72
  PORT: String(backendPort),
73
73
  OAUTH_ISSUER: process.env.OAUTH_ISSUER || issuer,
74
+ DEV_MODE: '1',
74
75
  },
75
76
  });
76
77
  server.httpServer?.on('close', () => {
package/package.json CHANGED
@@ -1,9 +1,15 @@
1
1
  {
2
2
  "name": "@hatk/hatk",
3
- "version": "0.0.1-alpha.2",
3
+ "version": "0.0.1-alpha.21",
4
+ "license": "MIT",
4
5
  "bin": {
5
6
  "hatk": "dist/cli.js"
6
7
  },
8
+ "files": [
9
+ "dist",
10
+ "fonts",
11
+ "public"
12
+ ],
7
13
  "type": "module",
8
14
  "exports": {
9
15
  "./feeds": "./dist/feeds.js",
@@ -17,9 +23,9 @@
17
23
  "./setup": "./dist/setup.js",
18
24
  "./test": "./dist/test.js",
19
25
  "./test/browser": "./dist/test-browser.js",
26
+ "./config": "./dist/config.js",
20
27
  "./vite-plugin": "./dist/vite-plugin.js"
21
28
  },
22
- "files": ["dist", "fonts", "public"],
23
29
  "scripts": {
24
30
  "build": "tsc -p tsconfig.build.json",
25
31
  "prepublishOnly": "npm run build"
@@ -0,0 +1,2 @@
1
+ User-agent: *
2
+ Allow: /