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

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/cli.js CHANGED
@@ -611,6 +611,7 @@ backfill:
611
611
  encoding: 'application/json',
612
612
  schema: {
613
613
  type: 'object',
614
+ required: ['items'],
614
615
  properties: {
615
616
  items: { type: 'array', items: { type: 'unknown' } },
616
617
  cursor: { type: 'string' },
@@ -668,6 +669,7 @@ backfill:
668
669
  encoding: 'application/json',
669
670
  schema: {
670
671
  type: 'object',
672
+ required: ['items'],
671
673
  properties: {
672
674
  items: { type: 'array', items: { type: 'unknown' } },
673
675
  cursor: { type: 'string' },
@@ -699,6 +701,7 @@ backfill:
699
701
  encoding: 'application/json',
700
702
  schema: {
701
703
  type: 'object',
704
+ required: ['items'],
702
705
  properties: {
703
706
  items: { type: 'array', items: { type: 'unknown' } },
704
707
  cursor: { type: 'string' },
@@ -793,11 +796,12 @@ public
793
796
  writeFileSync(join(dir, 'Dockerfile'), `FROM node:25-slim
794
797
  WORKDIR /app
795
798
  COPY package.json package-lock.json ./
796
- RUN npm ci --omit=dev
799
+ RUN npm ci
797
800
  COPY . .
798
801
  RUN node_modules/.bin/hatk build
802
+ RUN npm prune --omit=dev
799
803
  EXPOSE 3000
800
- CMD ["node", "--no-warnings", "node_modules/@hatk/hatk/dist/main.js", "config.yaml"]
804
+ CMD ["node", "node_modules/@hatk/hatk/dist/main.js", "config.yaml"]
801
805
  `);
802
806
  const pkgDeps = { '@hatk/oauth-client': '*', hatk: '*' };
803
807
  const pkgDevDeps = {
@@ -807,6 +811,7 @@ CMD ["node", "--no-warnings", "node_modules/@hatk/hatk/dist/main.js", "config.ya
807
811
  typescript: '^5',
808
812
  vite: '^6',
809
813
  vitest: '^4',
814
+ '@types/node': '^22',
810
815
  };
811
816
  if (withSvelte) {
812
817
  pkgDevDeps['@sveltejs/adapter-static'] = '^3';
@@ -926,6 +931,7 @@ export default defineConfig({
926
931
  <head>
927
932
  <meta charset="utf-8" />
928
933
  <meta name="viewport" content="width=device-width, initial-scale=1" />
934
+ <meta name="description" content="${name}" />
929
935
  <title>${name}</title>
930
936
  %sveltekit.head%
931
937
  </head>
@@ -1437,7 +1443,11 @@ else if (command === 'dev') {
1437
1443
  else {
1438
1444
  // No frontend — just run the hatk server directly
1439
1445
  const mainPath = resolve(import.meta.dirname, 'main.js');
1440
- execSync(`npx tsx ${mainPath} config.yaml`, { stdio: 'inherit', cwd: process.cwd() });
1446
+ execSync(`npx tsx ${mainPath} config.yaml`, {
1447
+ stdio: 'inherit',
1448
+ cwd: process.cwd(),
1449
+ env: { ...process.env, DEV_MODE: '1' },
1450
+ });
1441
1451
  }
1442
1452
  }
1443
1453
  catch (e) {
@@ -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,GAC/D,MAAM,CAo8BR"}
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";
@@ -39,12 +41,13 @@ function readBodyRaw(req) {
39
41
  }
40
42
  export function startServer(port, collections, publicDir, oauth, admins = [], resolveViewer) {
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
  }
@@ -864,6 +867,21 @@ export function startServer(port, collections, publicDir, oauth, admins = [], re
864
867
  throw err;
865
868
  }
866
869
  }
870
+ // GET /robots.txt — serve from user's public dir or fall back to hatk default
871
+ if (url.pathname === '/robots.txt') {
872
+ const userRobots = publicDir ? join(publicDir, 'robots.txt') : null;
873
+ const defaultRobots = join(import.meta.dirname, '../public/robots.txt');
874
+ const robotsPath = userRobots && existsSync(userRobots) ? userRobots : defaultRobots;
875
+ try {
876
+ const content = await readFile(robotsPath);
877
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
878
+ res.end(content);
879
+ return;
880
+ }
881
+ catch {
882
+ // fall through
883
+ }
884
+ }
867
885
  // Static file serving
868
886
  if (publicDir) {
869
887
  try {
@@ -912,15 +930,33 @@ export function startServer(port, collections, publicDir, oauth, admins = [], re
912
930
  server.listen(port, () => log(`[server] ${oauth?.issuer || `http://localhost:${port}`}`));
913
931
  return server;
914
932
  }
933
+ function sendJson(res, status, body) {
934
+ const acceptEncoding = res.req?.headers['accept-encoding'] || '';
935
+ if (body.length > 1024 && /\bgzip\b/.test(acceptEncoding)) {
936
+ const compressed = gzipSync(body);
937
+ res.writeHead(status, {
938
+ 'Content-Type': 'application/json',
939
+ 'Content-Encoding': 'gzip',
940
+ Vary: 'Accept-Encoding',
941
+ ...(status === 200 ? { 'Cache-Control': 'no-store' } : {}),
942
+ });
943
+ res.end(compressed);
944
+ }
945
+ else {
946
+ res.writeHead(status, {
947
+ 'Content-Type': 'application/json',
948
+ ...(status === 200 ? { 'Cache-Control': 'no-store' } : {}),
949
+ });
950
+ res.end(body);
951
+ }
952
+ }
915
953
  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)));
954
+ sendJson(res, 200, Buffer.from(JSON.stringify(data, (_, v) => normalizeValue(v))));
918
955
  }
919
956
  function jsonError(res, status, message) {
920
957
  if (res.headersSent)
921
958
  return;
922
- res.writeHead(status, { 'Content-Type': 'application/json' });
923
- res.end(JSON.stringify({ error: message }));
959
+ sendJson(res, status, Buffer.from(JSON.stringify({ error: message })));
924
960
  }
925
961
  /** Proxy a request to the user's PDS with DPoP + automatic nonce retry + token refresh. */
926
962
  async function proxyToPds(oauthConfig, session, method, pdsUrl, body) {
@@ -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"}
@@ -71,6 +71,7 @@ export function hatk(opts) {
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,14 @@
1
1
  {
2
2
  "name": "@hatk/hatk",
3
- "version": "0.0.1-alpha.2",
3
+ "version": "0.0.1-alpha.4",
4
4
  "bin": {
5
5
  "hatk": "dist/cli.js"
6
6
  },
7
+ "files": [
8
+ "dist",
9
+ "fonts",
10
+ "public"
11
+ ],
7
12
  "type": "module",
8
13
  "exports": {
9
14
  "./feeds": "./dist/feeds.js",
@@ -19,7 +24,6 @@
19
24
  "./test/browser": "./dist/test-browser.js",
20
25
  "./vite-plugin": "./dist/vite-plugin.js"
21
26
  },
22
- "files": ["dist", "fonts", "public"],
23
27
  "scripts": {
24
28
  "build": "tsc -p tsconfig.build.json",
25
29
  "prepublishOnly": "npm run build"
@@ -0,0 +1,2 @@
1
+ User-agent: *
2
+ Allow: /