@hatk/hatk 0.0.1-alpha.8 → 0.0.1-alpha.81

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 (175) hide show
  1. package/dist/adapter.d.ts +19 -0
  2. package/dist/adapter.d.ts.map +1 -0
  3. package/dist/adapter.js +111 -0
  4. package/dist/backfill.d.ts +29 -2
  5. package/dist/backfill.d.ts.map +1 -1
  6. package/dist/backfill.js +136 -51
  7. package/dist/car.d.ts +42 -10
  8. package/dist/car.d.ts.map +1 -1
  9. package/dist/car.js +154 -14
  10. package/dist/cli.js +243 -1043
  11. package/dist/config.d.ts +82 -1
  12. package/dist/config.d.ts.map +1 -1
  13. package/dist/config.js +44 -9
  14. package/dist/database/adapter-factory.d.ts +6 -0
  15. package/dist/database/adapter-factory.d.ts.map +1 -0
  16. package/dist/database/adapter-factory.js +20 -0
  17. package/dist/database/adapters/duckdb-search.d.ts +12 -0
  18. package/dist/database/adapters/duckdb-search.d.ts.map +1 -0
  19. package/dist/database/adapters/duckdb-search.js +27 -0
  20. package/dist/database/adapters/duckdb.d.ts +25 -0
  21. package/dist/database/adapters/duckdb.d.ts.map +1 -0
  22. package/dist/database/adapters/duckdb.js +161 -0
  23. package/dist/database/adapters/sqlite-search.d.ts +16 -0
  24. package/dist/database/adapters/sqlite-search.d.ts.map +1 -0
  25. package/dist/database/adapters/sqlite-search.js +76 -0
  26. package/dist/database/adapters/sqlite.d.ts +18 -0
  27. package/dist/database/adapters/sqlite.d.ts.map +1 -0
  28. package/dist/database/adapters/sqlite.js +88 -0
  29. package/dist/{db.d.ts → database/db.d.ts} +57 -6
  30. package/dist/database/db.d.ts.map +1 -0
  31. package/dist/{db.js → database/db.js} +755 -552
  32. package/dist/database/dialect.d.ts +45 -0
  33. package/dist/database/dialect.d.ts.map +1 -0
  34. package/dist/database/dialect.js +72 -0
  35. package/dist/{fts.d.ts → database/fts.d.ts} +7 -0
  36. package/dist/database/fts.d.ts.map +1 -0
  37. package/dist/{fts.js → database/fts.js} +116 -32
  38. package/dist/database/index.d.ts +7 -0
  39. package/dist/database/index.d.ts.map +1 -0
  40. package/dist/database/index.js +6 -0
  41. package/dist/database/ports.d.ts +50 -0
  42. package/dist/database/ports.d.ts.map +1 -0
  43. package/dist/database/ports.js +1 -0
  44. package/dist/{schema.d.ts → database/schema.d.ts} +14 -3
  45. package/dist/database/schema.d.ts.map +1 -0
  46. package/dist/{schema.js → database/schema.js} +81 -41
  47. package/dist/dev-entry.d.ts +8 -0
  48. package/dist/dev-entry.d.ts.map +1 -0
  49. package/dist/dev-entry.js +125 -0
  50. package/dist/feeds.d.ts +12 -8
  51. package/dist/feeds.d.ts.map +1 -1
  52. package/dist/feeds.js +51 -6
  53. package/dist/hooks.d.ts +85 -0
  54. package/dist/hooks.d.ts.map +1 -0
  55. package/dist/hooks.js +163 -0
  56. package/dist/hydrate.d.ts +7 -6
  57. package/dist/hydrate.d.ts.map +1 -1
  58. package/dist/hydrate.js +4 -16
  59. package/dist/indexer.d.ts +133 -3
  60. package/dist/indexer.d.ts.map +1 -1
  61. package/dist/indexer.js +406 -66
  62. package/dist/jetstream.d.ts +118 -0
  63. package/dist/jetstream.d.ts.map +1 -0
  64. package/dist/jetstream.js +225 -0
  65. package/dist/labels.d.ts +36 -0
  66. package/dist/labels.d.ts.map +1 -1
  67. package/dist/labels.js +71 -6
  68. package/dist/lexicon-resolve.d.ts.map +1 -1
  69. package/dist/lexicon-resolve.js +27 -112
  70. package/dist/lexicons/com/atproto/label/defs.json +75 -0
  71. package/dist/lexicons/com/atproto/moderation/defs.json +30 -0
  72. package/dist/lexicons/com/atproto/repo/strongRef.json +21 -0
  73. package/dist/lexicons/dev/hatk/applyWrites.json +87 -0
  74. package/dist/lexicons/dev/hatk/createRecord.json +40 -0
  75. package/dist/lexicons/dev/hatk/createReport.json +48 -0
  76. package/dist/lexicons/dev/hatk/deleteRecord.json +25 -0
  77. package/dist/lexicons/dev/hatk/describeCollections.json +41 -0
  78. package/dist/lexicons/dev/hatk/describeFeeds.json +29 -0
  79. package/dist/lexicons/dev/hatk/describeLabels.json +45 -0
  80. package/dist/lexicons/dev/hatk/getFeed.json +30 -0
  81. package/dist/lexicons/dev/hatk/getPreferences.json +19 -0
  82. package/dist/lexicons/dev/hatk/getRecord.json +26 -0
  83. package/dist/lexicons/dev/hatk/getRecords.json +32 -0
  84. package/dist/lexicons/dev/hatk/putPreference.json +28 -0
  85. package/dist/lexicons/dev/hatk/putRecord.json +41 -0
  86. package/dist/lexicons/dev/hatk/searchRecords.json +32 -0
  87. package/dist/lexicons/dev/hatk/uploadBlob.json +23 -0
  88. package/dist/logger.d.ts +29 -0
  89. package/dist/logger.d.ts.map +1 -1
  90. package/dist/logger.js +29 -0
  91. package/dist/main.js +169 -74
  92. package/dist/mst.d.ts +18 -1
  93. package/dist/mst.d.ts.map +1 -1
  94. package/dist/mst.js +19 -8
  95. package/dist/oauth/db.d.ts +3 -1
  96. package/dist/oauth/db.d.ts.map +1 -1
  97. package/dist/oauth/db.js +56 -19
  98. package/dist/oauth/discovery.d.ts.map +1 -1
  99. package/dist/oauth/discovery.js +13 -1
  100. package/dist/oauth/server.d.ts +92 -1
  101. package/dist/oauth/server.d.ts.map +1 -1
  102. package/dist/oauth/server.js +352 -37
  103. package/dist/oauth/service-describe.d.ts +31 -0
  104. package/dist/oauth/service-describe.d.ts.map +1 -0
  105. package/dist/oauth/service-describe.js +61 -0
  106. package/dist/oauth/session.d.ts +32 -0
  107. package/dist/oauth/session.d.ts.map +1 -0
  108. package/dist/oauth/session.js +131 -0
  109. package/dist/opengraph.d.ts +10 -0
  110. package/dist/opengraph.d.ts.map +1 -1
  111. package/dist/opengraph.js +80 -40
  112. package/dist/pds-proxy.d.ts +82 -0
  113. package/dist/pds-proxy.d.ts.map +1 -0
  114. package/dist/pds-proxy.js +356 -0
  115. package/dist/private-collections.d.ts +8 -0
  116. package/dist/private-collections.d.ts.map +1 -0
  117. package/dist/private-collections.js +22 -0
  118. package/dist/push.d.ts +54 -0
  119. package/dist/push.d.ts.map +1 -0
  120. package/dist/push.js +367 -0
  121. package/dist/renderer.d.ts +27 -0
  122. package/dist/renderer.d.ts.map +1 -0
  123. package/dist/renderer.js +46 -0
  124. package/dist/resolve-hatk.d.ts +6 -0
  125. package/dist/resolve-hatk.d.ts.map +1 -0
  126. package/dist/resolve-hatk.js +20 -0
  127. package/dist/response.d.ts +16 -0
  128. package/dist/response.d.ts.map +1 -0
  129. package/dist/response.js +69 -0
  130. package/dist/scanner.d.ts +21 -0
  131. package/dist/scanner.d.ts.map +1 -0
  132. package/dist/scanner.js +88 -0
  133. package/dist/seed.d.ts +19 -0
  134. package/dist/seed.d.ts.map +1 -1
  135. package/dist/seed.js +43 -4
  136. package/dist/server-init.d.ts +8 -0
  137. package/dist/server-init.d.ts.map +1 -0
  138. package/dist/server-init.js +62 -0
  139. package/dist/server.d.ts +26 -3
  140. package/dist/server.d.ts.map +1 -1
  141. package/dist/server.js +858 -638
  142. package/dist/setup.d.ts +28 -1
  143. package/dist/setup.d.ts.map +1 -1
  144. package/dist/setup.js +50 -3
  145. package/dist/templates/feed.tpl +14 -0
  146. package/dist/templates/hook.tpl +5 -0
  147. package/dist/templates/label.tpl +15 -0
  148. package/dist/templates/og.tpl +17 -0
  149. package/dist/templates/seed.tpl +11 -0
  150. package/dist/templates/setup.tpl +5 -0
  151. package/dist/templates/test-feed.tpl +19 -0
  152. package/dist/templates/test-xrpc.tpl +19 -0
  153. package/dist/templates/xrpc.tpl +41 -0
  154. package/dist/test.d.ts +1 -1
  155. package/dist/test.d.ts.map +1 -1
  156. package/dist/test.js +41 -32
  157. package/dist/views.js +1 -1
  158. package/dist/vite-plugin.d.ts +1 -1
  159. package/dist/vite-plugin.d.ts.map +1 -1
  160. package/dist/vite-plugin.js +254 -66
  161. package/dist/xrpc.d.ts +84 -11
  162. package/dist/xrpc.d.ts.map +1 -1
  163. package/dist/xrpc.js +211 -41
  164. package/package.json +17 -9
  165. package/public/admin-auth.js +271 -306
  166. package/public/admin.html +177 -61
  167. package/dist/db.d.ts.map +0 -1
  168. package/dist/fts.d.ts.map +0 -1
  169. package/dist/oauth/hooks.d.ts +0 -10
  170. package/dist/oauth/hooks.d.ts.map +0 -1
  171. package/dist/oauth/hooks.js +0 -40
  172. package/dist/schema.d.ts.map +0 -1
  173. package/dist/test-browser.d.ts +0 -14
  174. package/dist/test-browser.d.ts.map +0 -1
  175. package/dist/test-browser.js +0 -26
@@ -0,0 +1,85 @@
1
+ import type { OAuthConfig } from './config.ts';
2
+ import { type BaseContext } from './hydrate.ts';
3
+ import { type PushInterface } from './push.ts';
4
+ /** Context passed to the on-login hook after a successful OAuth login. */
5
+ export type OnLoginCtx = Omit<BaseContext, 'db'> & {
6
+ /** DID of the user who just logged in. */
7
+ did: string;
8
+ /** Database access with both read and write. */
9
+ db: {
10
+ query: (sql: string, params?: unknown[]) => Promise<unknown[]>;
11
+ run: (sql: string, params?: unknown[]) => Promise<void>;
12
+ };
13
+ /** Trigger a backfill for a DID and wait for it to complete. */
14
+ ensureRepo: (did: string) => Promise<void>;
15
+ /** Write a record to the user's PDS and index locally. */
16
+ createRecord: (collection: string, record: Record<string, unknown>, opts?: {
17
+ rkey?: string;
18
+ }) => Promise<{
19
+ uri?: string;
20
+ cid?: string;
21
+ }>;
22
+ /** Create or update a record on the user's PDS and index locally. */
23
+ putRecord: (collection: string, rkey: string, record: Record<string, unknown>) => Promise<{
24
+ uri?: string;
25
+ cid?: string;
26
+ }>;
27
+ /** Delete a record from the user's PDS and local index. */
28
+ deleteRecord: (collection: string, rkey: string) => Promise<void>;
29
+ };
30
+ /** Context passed to on-commit hooks after a record is indexed. */
31
+ export type OnCommitCtx = {
32
+ /** Whether the record was created or deleted. */
33
+ action: 'create' | 'delete';
34
+ /** The collection NSID that matched. */
35
+ collection: string;
36
+ /** The record value (null for deletes). */
37
+ record: Record<string, any> | null;
38
+ /** DID of the committing actor. */
39
+ repo: string;
40
+ /** AT URI of the record. */
41
+ uri: string;
42
+ /** Database access (read and write). */
43
+ db: {
44
+ query: (sql: string, params?: unknown[]) => Promise<unknown[]>;
45
+ run: (sql: string, params?: unknown[]) => Promise<void>;
46
+ };
47
+ /** Typed record lookup (same as BaseContext). */
48
+ lookup: BaseContext['lookup'];
49
+ /** Push notification delivery. */
50
+ push: PushInterface;
51
+ };
52
+ export declare function defineHook(event: 'on-login', handler: (ctx: OnLoginCtx) => Promise<void>): {
53
+ __type: 'hook';
54
+ event: 'on-login';
55
+ handler: (ctx: OnLoginCtx) => Promise<void>;
56
+ };
57
+ export declare function defineHook(event: 'on-commit', options: {
58
+ collections: string[];
59
+ }, handler: (ctx: OnCommitCtx) => Promise<void>): {
60
+ __type: 'hook';
61
+ event: 'on-commit';
62
+ collections: string[];
63
+ handler: (ctx: OnCommitCtx) => Promise<void>;
64
+ };
65
+ /**
66
+ * Discover and load the on-login hook from the project's `hooks/` directory.
67
+ * Looks for `on-login.ts` or `on-login.js`. Safe to call if no hook exists.
68
+ */
69
+ export declare function loadOnLoginHook(hooksDir: string): Promise<void>;
70
+ /** Register a hook from a scanned server/ module. */
71
+ export declare function registerHook(event: string, handler: Function, options?: any): void;
72
+ /** Fire the on-login hook if loaded. Errors are logged but never block login. */
73
+ export declare function fireOnLoginHook(did: string, oauthConfig: OAuthConfig | null): Promise<void>;
74
+ /**
75
+ * Fire on-commit hooks for a batch of indexed records.
76
+ * Runs async and non-blocking — errors are logged but never throw.
77
+ */
78
+ export declare function fireOnCommitHooks(items: Array<{
79
+ action: 'create' | 'delete';
80
+ collection: string;
81
+ uri: string;
82
+ authorDid: string;
83
+ record: Record<string, any> | null;
84
+ }>): void;
85
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
package/dist/hooks.js ADDED
@@ -0,0 +1,163 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ /**
10
+ * Lifecycle hooks that run in response to server events.
11
+ *
12
+ * Place hook modules in the `hooks/` directory. Currently supported hooks:
13
+ *
14
+ * - `on-login.ts` — called after each successful OAuth login
15
+ * - `on-commit-*.ts` — called after records are indexed from the firehose
16
+ *
17
+ * Each hook default-exports the result of `defineHook()`.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * // hooks/on-login.ts
22
+ * import { defineHook } from '$hatk'
23
+ *
24
+ * export default defineHook("on-login", async (ctx) => {
25
+ * await ctx.ensureRepo(ctx.did)
26
+ * })
27
+ * ```
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * // hooks/on-commit-favorite.ts
32
+ * import { defineHook } from '$hatk'
33
+ *
34
+ * export default defineHook("on-commit", { collections: ["social.grain.favorite"] },
35
+ * async ({ action, collection, record, repo, uri, db, lookup, push }) => {
36
+ * if (action !== "create") return
37
+ * // send push notification, etc.
38
+ * }
39
+ * )
40
+ * ```
41
+ */
42
+ import { existsSync } from 'node:fs';
43
+ import { resolve } from 'node:path';
44
+ import { pdsCreateRecord, pdsPutRecord, pdsDeleteRecord } from "./pds-proxy.js";
45
+ import { log, emit } from "./logger.js";
46
+ import { setRepoStatus, runSQL } from "./database/db.js";
47
+ import { triggerAutoBackfill, awaitBackfill } from "./indexer.js";
48
+ import { buildBaseContext } from "./hydrate.js";
49
+ import { buildPushInterface, isPushEnabled } from "./push.js";
50
+ export function defineHook(event, ...args) {
51
+ if (event === 'on-login') {
52
+ return { __type: 'hook', event, handler: args[0] };
53
+ }
54
+ if (event === 'on-commit') {
55
+ const options = args[0];
56
+ const handler = args[1];
57
+ return { __type: 'hook', event, collections: options.collections, handler };
58
+ }
59
+ throw new Error(`Unknown hook event: ${event}`);
60
+ }
61
+ let onLoginHook = null;
62
+ const onCommitHooks = [];
63
+ /**
64
+ * Discover and load the on-login hook from the project's `hooks/` directory.
65
+ * Looks for `on-login.ts` or `on-login.js`. Safe to call if no hook exists.
66
+ */
67
+ export async function loadOnLoginHook(hooksDir) {
68
+ const tsPath = resolve(hooksDir, 'on-login.ts');
69
+ const jsPath = resolve(hooksDir, 'on-login.js');
70
+ const path = existsSync(tsPath) ? tsPath : existsSync(jsPath) ? jsPath : null;
71
+ if (!path)
72
+ return;
73
+ const mod = await import(__rewriteRelativeImportExtension(/* @vite-ignore */ `${path}?t=${Date.now()}`));
74
+ onLoginHook = mod.default;
75
+ log('[hooks] on-login hook loaded');
76
+ }
77
+ /** Mark a DID as pending, trigger auto-backfill, and wait for completion. */
78
+ async function ensureRepo(did) {
79
+ await setRepoStatus(did, 'pending');
80
+ triggerAutoBackfill(did);
81
+ await awaitBackfill(did);
82
+ }
83
+ /** Register a hook from a scanned server/ module. */
84
+ export function registerHook(event, handler, options) {
85
+ if (event === 'on-login') {
86
+ onLoginHook = handler;
87
+ log('[hooks] on-login hook registered');
88
+ }
89
+ else if (event === 'on-commit') {
90
+ const collections = new Set(options?.collections || []);
91
+ onCommitHooks.push({ collections, handler: handler });
92
+ log(`[hooks] on-commit hook registered (collections: ${[...collections].join(', ')})`);
93
+ }
94
+ }
95
+ /** Fire the on-login hook if loaded. Errors are logged but never block login. */
96
+ export async function fireOnLoginHook(did, oauthConfig) {
97
+ if (!onLoginHook)
98
+ return;
99
+ try {
100
+ const base = buildBaseContext({ did });
101
+ const viewer = { did };
102
+ const hookPromise = onLoginHook({
103
+ ...base,
104
+ did,
105
+ db: { query: base.db.query, run: runSQL },
106
+ ensureRepo,
107
+ createRecord: async (collection, record, opts) => {
108
+ if (!oauthConfig)
109
+ throw new Error('No OAuth config — cannot write to PDS');
110
+ return pdsCreateRecord(oauthConfig, viewer, { collection, record, rkey: opts?.rkey });
111
+ },
112
+ putRecord: async (collection, rkey, record) => {
113
+ if (!oauthConfig)
114
+ throw new Error('No OAuth config — cannot write to PDS');
115
+ return pdsPutRecord(oauthConfig, viewer, { collection, rkey, record });
116
+ },
117
+ deleteRecord: async (collection, rkey) => {
118
+ if (!oauthConfig)
119
+ throw new Error('No OAuth config — cannot write to PDS');
120
+ await pdsDeleteRecord(oauthConfig, viewer, { collection, rkey });
121
+ },
122
+ });
123
+ const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error('on-login hook timed out after 30s')), 30_000));
124
+ await Promise.race([hookPromise, timeout]);
125
+ }
126
+ catch (err) {
127
+ emit('hooks', 'on_login_error', { did, error: err.message });
128
+ }
129
+ }
130
+ /**
131
+ * Fire on-commit hooks for a batch of indexed records.
132
+ * Runs async and non-blocking — errors are logged but never throw.
133
+ */
134
+ export function fireOnCommitHooks(items) {
135
+ if (onCommitHooks.length === 0)
136
+ return;
137
+ const base = buildBaseContext(null);
138
+ const push = isPushEnabled() ? buildPushInterface() : { send: async () => { } };
139
+ for (const item of items) {
140
+ for (const hook of onCommitHooks) {
141
+ if (hook.collections.size > 0 && !hook.collections.has(item.collection))
142
+ continue;
143
+ hook
144
+ .handler({
145
+ action: item.action,
146
+ collection: item.collection,
147
+ record: item.record,
148
+ repo: item.authorDid,
149
+ uri: item.uri,
150
+ db: { query: base.db.query, run: runSQL },
151
+ lookup: base.lookup,
152
+ push,
153
+ })
154
+ .catch((err) => {
155
+ emit('hooks', 'on_commit_error', {
156
+ collection: item.collection,
157
+ uri: item.uri,
158
+ error: err.message,
159
+ });
160
+ });
161
+ }
162
+ }
163
+ }
package/dist/hydrate.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import type { Row } from './lex-types.ts';
2
2
  export type { Row };
3
- export interface HydrateContext<T = unknown> {
4
- items: Row<T>[];
3
+ export interface BaseContext {
5
4
  viewer: {
6
5
  did: string;
6
+ handle?: string;
7
7
  } | null;
8
8
  db: {
9
9
  query: (sql: string, params?: unknown[]) => Promise<unknown[]>;
@@ -12,12 +12,13 @@ export interface HydrateContext<T = unknown> {
12
12
  lookup: <R = unknown>(collection: string, field: string, values: string[]) => Promise<Map<string, Row<R>>>;
13
13
  count: (collection: string, field: string, values: string[]) => Promise<Map<string, number>>;
14
14
  labels: (uris: string[]) => Promise<Map<string, unknown[]>>;
15
- blobUrl: (did: string, ref: unknown, preset?: 'avatar' | 'banner' | 'feed_thumbnail' | 'feed_fullsize') => string | undefined;
15
+ blobUrl: (did: string, ref: unknown, preset?: string) => string | undefined;
16
16
  }
17
17
  /** Fetch records for URIs, reshape them, and filter out taken-down DIDs. */
18
18
  export declare function resolveRecords(uris: string[]): Promise<Row<unknown>[]>;
19
- /** Build a HydrateContext for a feed's hydrate function. */
20
- export declare function buildHydrateContext(items: Row<unknown>[], viewer: {
19
+ /** Build a BaseContext for hydration. */
20
+ export declare function buildBaseContext(viewer: {
21
21
  did: string;
22
- } | null): HydrateContext;
22
+ handle?: string;
23
+ } | null): BaseContext;
23
24
  //# sourceMappingURL=hydrate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../src/hydrate.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AAEzC,YAAY,EAAE,GAAG,EAAE,CAAA;AAInB,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IACzC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;IACf,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC9B,EAAE,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;KAAE,CAAA;IACtE,UAAU,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7F,MAAM,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1G,KAAK,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC5F,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAA;IAC3D,OAAO,EAAE,CACP,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,OAAO,EACZ,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,gBAAgB,GAAG,eAAe,KAC9D,MAAM,GAAG,SAAS,CAAA;CACxB;AAID,4EAA4E;AAC5E,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAoC5E;AAID,4DAA4D;AAC5D,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,cAAc,CA4BzG"}
1
+ {"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../src/hydrate.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AAEzC,YAAY,EAAE,GAAG,EAAE,CAAA;AAInB,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC/C,EAAE,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;KAAE,CAAA;IACtE,UAAU,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7F,MAAM,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1G,KAAK,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC5F,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAA;IAC3D,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;CAC5E;AAID,4EAA4E;AAC5E,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAoC5E;AAID,yCAAyC;AACzC,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,WAAW,CAkB7F"}
package/dist/hydrate.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getRecordsByUris, countByFieldBatch, lookupByFieldBatch, querySQL, reshapeRow, queryLabelsForUris, filterTakendownDids, } from "./db.js";
1
+ import { getRecordsMap, countByFieldBatch, lookupByFieldBatch, querySQL, queryLabelsForUris, filterTakendownDids, getRecordsByUris, reshapeRow, } from "./database/db.js";
2
2
  import { blobUrl } from "./xrpc.js";
3
3
  // --- Record Resolution ---
4
4
  /** Fetch records for URIs, reshape them, and filter out taken-down DIDs. */
@@ -39,24 +39,12 @@ export async function resolveRecords(uris) {
39
39
  .filter((r) => r != null);
40
40
  }
41
41
  // --- Context Builder ---
42
- /** Build a HydrateContext for a feed's hydrate function. */
43
- export function buildHydrateContext(items, viewer) {
42
+ /** Build a BaseContext for hydration. */
43
+ export function buildBaseContext(viewer) {
44
44
  return {
45
- items,
46
45
  viewer,
47
46
  db: { query: querySQL },
48
- getRecords: async (collection, uris) => {
49
- if (uris.length === 0)
50
- return new Map();
51
- const records = await getRecordsByUris(collection, uris);
52
- const map = new Map();
53
- for (const r of records) {
54
- const shaped = reshapeRow(r, r?.__childData, r?.__unionData);
55
- if (shaped)
56
- map.set(shaped.uri, shaped);
57
- }
58
- return map;
59
- },
47
+ getRecords: getRecordsMap,
60
48
  lookup: async (collection, field, values) => {
61
49
  if (values.length === 0)
62
50
  return new Map();
package/dist/indexer.d.ts CHANGED
@@ -1,14 +1,144 @@
1
+ /** A single normalized repo operation, independent of the wire it arrived on. */
2
+ export interface CommitOp {
3
+ action: 'create' | 'update' | 'delete';
4
+ collection: string;
5
+ rkey: string;
6
+ /** Absent on deletes. */
7
+ cid?: string;
8
+ /** Absent on deletes. */
9
+ record?: Record<string, any>;
10
+ }
11
+ /** Record the latest firehose sequence seen. Source of truth for cursor persistence and reconnect resume. */
12
+ export declare function noteSeq(seq: number): void;
13
+ /** The highest seq this process has seen, or null before the first event. */
14
+ export declare function getLastSeq(): number | null;
15
+ /**
16
+ * Persist the latest firehose sequence when it has advanced past the stored
17
+ * cursor. Runs on a timer independent of the write path: an app whose
18
+ * collections rarely appear on the firehose never flushes a batch, so the
19
+ * flush-path cursor write alone leaves the stored cursor frozen — and a frozen
20
+ * cursor makes the relay replay its whole retention window at line rate
21
+ * (~135 GB/hour observed against bsky.network) on every boot and reconnect.
22
+ */
23
+ export declare function checkpointCursor(): Promise<void>;
24
+ /** Point cursor persistence at a stream's own `_cursor` row. See {@link cursorKey}. */
25
+ export declare function setCursorKey(key: 'relay' | 'jetstream'): void;
26
+ /**
27
+ * The cursor a reconnect should resume from: the latest seq this process has
28
+ * seen, falling back to the boot-time cursor before any message has arrived.
29
+ * Reusing the boot-time cursor on every reconnect would replay everything
30
+ * received since the process started.
31
+ */
32
+ export declare function resumeCursor(liveSeq: number | null, bootCursor: string | null | undefined): string | null | undefined;
33
+ /** Reset module cursor state between tests. */
34
+ export declare function _resetCursorStateForTests(): void;
35
+ /**
36
+ * Drain the write buffer synchronously instead of waiting out
37
+ * FLUSH_INTERVAL_MS. Lets end-to-end tests assert on rows immediately after
38
+ * feeding a frame.
39
+ */
40
+ export declare function _flushForTests(): Promise<void>;
41
+ /**
42
+ * Auto-backfill a DID's repo when first seen on the firehose.
43
+ *
44
+ * Fetches the full repo via CAR export, inserts all records, then replays any
45
+ * firehose events that arrived during the backfill. Concurrency is capped at
46
+ * `maxConcurrentBackfills`. Failed backfills retry with exponential delay up
47
+ * to `maxRetries`.
48
+ */
49
+ /** Wait for a DID's backfill to complete if one is in flight. */
50
+ export declare function awaitBackfill(did: string): Promise<void>;
1
51
  export declare function triggerAutoBackfill(did: string, attempt?: number): Promise<void>;
2
- interface IndexerOpts {
3
- relayUrl: string;
52
+ /**
53
+ * Indexing behaviour shared by every stream source. Both the relay firehose
54
+ * and the Jetstream live tail feed the same buffers, backfill signalling, and
55
+ * cursor machinery — only the wire differs.
56
+ */
57
+ export interface IndexerCoreOpts {
58
+ plcUrl: string;
4
59
  collections: Set<string>;
5
60
  signalCollections?: Set<string>;
6
61
  pinnedRepos?: Set<string>;
7
- cursor?: string | null;
8
62
  fetchTimeout: number;
9
63
  maxRetries: number;
64
+ parallelism?: number;
10
65
  ftsRebuildInterval?: number;
11
66
  }
67
+ /** Configuration for the relay firehose indexer. */
68
+ interface IndexerOpts extends IndexerCoreOpts {
69
+ relayUrl: string;
70
+ cursor?: string | null;
71
+ }
72
+ /**
73
+ * Connect to the AT Protocol relay firehose and begin indexing.
74
+ *
75
+ * Opens a WebSocket to `subscribeRepos`, processes commit messages synchronously
76
+ * on the event loop to minimize backpressure, and batches writes through
77
+ * {@link flushBuffer}. New DIDs trigger auto-backfill via {@link triggerAutoBackfill}.
78
+ * Reconnects automatically on disconnect after a 3s delay.
79
+ *
80
+ * @returns The WebSocket connection (for shutdown coordination)
81
+ */
82
+ export declare function configureIndexer(opts: IndexerCoreOpts): Promise<void>;
12
83
  export declare function startIndexer(opts: IndexerOpts): Promise<WebSocket>;
84
+ /** Configuration for an auxiliary firehose (see {@link startAuxIndexer}). */
85
+ export interface AuxIndexerOpts {
86
+ relayUrl: string;
87
+ collections: Set<string>;
88
+ cursor?: string | null;
89
+ }
90
+ /** The `_cursor` row an auxiliary firehose persists its position to. */
91
+ export declare function auxCursorKey(relayUrl: string): string;
92
+ /**
93
+ * Tail a second `subscribeRepos` alongside the primary stream.
94
+ *
95
+ * A relay is one coordinate system; a PDS tailed directly is another. Nothing
96
+ * below the wire cares which socket a frame arrived on — `processMessage`
97
+ * decodes it and `applyCommit` indexes it — so the only state an extra source
98
+ * needs of its own is a seq and a cursor row. Both live in this closure,
99
+ * keyed by URL, so an aux stream never advances (or resumes from) the primary
100
+ * cursor. Use this when a repo's PDS is not behind the relay being tailed —
101
+ * a self-hosted network, a dev stack with more than one PDS — rather than
102
+ * standing up a relay just to merge two streams.
103
+ *
104
+ * Must be called after {@link configureIndexer} (or {@link startIndexer}),
105
+ * which owns the shared indexer configuration.
106
+ */
107
+ export declare function startAuxIndexer(opts: AuxIndexerOpts): WebSocket;
108
+ /**
109
+ * Handle a `#identity` firehose event for a DID. The `handle` field on the
110
+ * event is optional per the lexicon, and some emitters omit it (signalling
111
+ * "re-resolve"). When absent, we re-resolve from the PLC directory so handle
112
+ * renames propagate even when the relay payload is sparse.
113
+ *
114
+ * Only updates DIDs we already track (present in repoStatusCache) to avoid
115
+ * writing rows for the entire network.
116
+ */
117
+ export declare function handleIdentityEvent(did: string, payloadHandle: string | undefined): Promise<void>;
118
+ /**
119
+ * Whether a collection's records may be written from network data.
120
+ *
121
+ * Private collections are AppView-authoritative: nothing on the network may
122
+ * write or delete their rows, so stream ops naming them are spoofed by
123
+ * definition and must be dropped regardless of which source delivered them.
124
+ */
125
+ export declare function isIndexableCollection(collection: string, collections: Set<string>): boolean;
126
+ /**
127
+ * Apply a repo's commit ops to the index.
128
+ *
129
+ * Wire-agnostic: the relay path reaches here after CBOR/CAR decoding, the
130
+ * Jetstream path after parsing JSON. Callers must have already filtered `ops`
131
+ * through {@link isIndexableCollection}.
132
+ *
133
+ * Handles auto-backfill signalling, buffering for DIDs mid-backfill, lexicon
134
+ * validation, and delete/put routing.
135
+ */
136
+ export declare function applyCommit(did: string, ops: CommitOp[]): void;
137
+ /**
138
+ * Process a single firehose message. Decodes the CBOR header/body, filters
139
+ * for relevant collections, validates records against lexicons, and routes
140
+ * writes to the buffer (or pending buffer if the DID is mid-backfill).
141
+ */
142
+ export declare function processMessage(bytes: Uint8Array, collections: Set<string>, onSeq?: (seq: number) => void): void;
13
143
  export {};
14
144
  //# sourceMappingURL=indexer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"indexer.d.ts","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"AAkIA,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDjF;AAED,UAAU,WAAW;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACxB,iBAAiB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC/B,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAyBD,wBAAsB,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAkDxE"}
1
+ {"version":3,"file":"indexer.d.ts","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"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"}