@hatk/hatk 0.0.1-alpha.40 → 0.0.1-alpha.41

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":"dev-entry.d.ts","sourceRoot":"","sources":["../src/dev-entry.ts"],"names":[],"mappings":"AA2GA,eAAO,MAAM,OAAO,yCAKlB,CAAA;AAEF,yEAAyE;AACzE,wBAAsB,YAAY,kBAEjC;AAED,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA"}
1
+ {"version":3,"file":"dev-entry.d.ts","sourceRoot":"","sources":["../src/dev-entry.ts"],"names":[],"mappings":"AA4GA,eAAO,MAAM,OAAO,yCAKlB,CAAA;AAEF,yEAAyE;AACzE,wBAAsB,YAAY,kBAEjC;AAED,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA"}
package/dist/dev-entry.js CHANGED
@@ -9,7 +9,7 @@ import { initDatabase, migrateSchema, getSchemaDump } from "./database/db.js";
9
9
  import { createAdapter } from "./database/adapter-factory.js";
10
10
  import { getDialect } from "./database/dialect.js";
11
11
  import { setSearchPort } from "./database/fts.js";
12
- import { configureRelay } from "./xrpc.js";
12
+ import { configureRelay, configureOAuth } from "./xrpc.js";
13
13
  import { initOAuth } from "./oauth/server.js";
14
14
  import { initServer } from "./server-init.js";
15
15
  import { createHandler, registerCoreHandlers } from "./server.js";
@@ -63,6 +63,7 @@ catch { }
63
63
  await initServer(resolve(configDir, 'server'));
64
64
  // Register built-in dev.hatk.* handlers so callXrpc() can find them
65
65
  registerCoreHandlers(collections, config.oauth);
66
+ configureOAuth(config.oauth);
66
67
  if (config.oauth) {
67
68
  await initOAuth(config.oauth, config.plc, config.relay);
68
69
  }
package/dist/hooks.d.ts CHANGED
@@ -1,9 +1,30 @@
1
+ import type { OAuthConfig } from './config.ts';
2
+ import { type BaseContext } from './hydrate.ts';
1
3
  /** Context passed to the on-login hook after a successful OAuth login. */
2
- export type OnLoginCtx = {
4
+ export type OnLoginCtx = Omit<BaseContext, 'db'> & {
3
5
  /** DID of the user who just logged in. */
4
6
  did: string;
5
- /** Trigger a backfill for a DID if it hasn't been indexed yet. */
7
+ /** Database access with both read and write. */
8
+ db: {
9
+ query: (sql: string, params?: unknown[]) => Promise<unknown[]>;
10
+ run: (sql: string, params?: unknown[]) => Promise<void>;
11
+ };
12
+ /** Trigger a backfill for a DID and wait for it to complete. */
6
13
  ensureRepo: (did: string) => Promise<void>;
14
+ /** Write a record to the user's PDS and index locally. */
15
+ createRecord: (collection: string, record: Record<string, unknown>, opts?: {
16
+ rkey?: string;
17
+ }) => Promise<{
18
+ uri?: string;
19
+ cid?: string;
20
+ }>;
21
+ /** Create or update a record on the user's PDS and index locally. */
22
+ putRecord: (collection: string, rkey: string, record: Record<string, unknown>) => Promise<{
23
+ uri?: string;
24
+ cid?: string;
25
+ }>;
26
+ /** Delete a record from the user's PDS and local index. */
27
+ deleteRecord: (collection: string, rkey: string) => Promise<void>;
7
28
  };
8
29
  export declare function defineHook(event: 'on-login', handler: (ctx: OnLoginCtx) => Promise<void>): {
9
30
  __type: "hook";
@@ -18,5 +39,5 @@ export declare function loadOnLoginHook(hooksDir: string): Promise<void>;
18
39
  /** Register a hook from a scanned server/ module. */
19
40
  export declare function registerHook(event: string, handler: Function): void;
20
41
  /** Fire the on-login hook if loaded. Errors are logged but never block login. */
21
- export declare function fireOnLoginHook(did: string): Promise<void>;
42
+ export declare function fireOnLoginHook(did: string, oauthConfig: OAuthConfig | null): Promise<void>;
22
43
  //# sourceMappingURL=hooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AA2BA,0EAA0E;AAC1E,MAAM,MAAM,UAAU,GAAG;IACvB,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAA;IACX,kEAAkE;IAClE,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3C,CAAA;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC;;;mBAA5B,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC;EAExF;AAMD;;;GAGG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQrE;AAQD,qDAAqD;AACrD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAKnE;AAED,iFAAiF;AACjF,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhE"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAK9C,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAA;AAEjE,0EAA0E;AAC1E,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG;IACjD,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAA;IACX,gDAAgD;IAChD,EAAE,EAAE;QACF,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;QAC9D,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KACxD,CAAA;IACD,gEAAgE;IAChE,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C,0DAA0D;IAC1D,YAAY,EAAE,CACZ,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KACrB,OAAO,CAAC;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC5C,qEAAqE;IACrE,SAAS,EAAE,CACT,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC5C,2DAA2D;IAC3D,YAAY,EAAE,CACZ,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,KACT,OAAO,CAAC,IAAI,CAAC,CAAA;CACnB,CAAA;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC;;;mBAA5B,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC;EAExF;AAMD;;;GAGG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQrE;AASD,qDAAqD;AACrD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAKnE;AAED,iFAAiF;AACjF,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BjG"}
package/dist/hooks.js CHANGED
@@ -29,9 +29,11 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
29
29
  */
30
30
  import { existsSync } from 'node:fs';
31
31
  import { resolve } from 'node:path';
32
- import { log } from "./logger.js";
33
- import { setRepoStatus } from "./database/db.js";
34
- import { triggerAutoBackfill } from "./indexer.js";
32
+ import { pdsCreateRecord, pdsPutRecord, pdsDeleteRecord } from "./pds-proxy.js";
33
+ import { log, emit } from "./logger.js";
34
+ import { setRepoStatus, runSQL } from "./database/db.js";
35
+ import { triggerAutoBackfill, awaitBackfill } from "./indexer.js";
36
+ import { buildBaseContext } from "./hydrate.js";
35
37
  export function defineHook(event, handler) {
36
38
  return { __type: 'hook', event, handler };
37
39
  }
@@ -50,10 +52,11 @@ export async function loadOnLoginHook(hooksDir) {
50
52
  onLoginHook = mod.default;
51
53
  log('[hooks] on-login hook loaded');
52
54
  }
53
- /** Mark a DID as pending and trigger auto-backfill. */
55
+ /** Mark a DID as pending, trigger auto-backfill, and wait for completion. */
54
56
  async function ensureRepo(did) {
55
57
  await setRepoStatus(did, 'pending');
56
58
  triggerAutoBackfill(did);
59
+ await awaitBackfill(did);
57
60
  }
58
61
  /** Register a hook from a scanned server/ module. */
59
62
  export function registerHook(event, handler) {
@@ -63,13 +66,37 @@ export function registerHook(event, handler) {
63
66
  }
64
67
  }
65
68
  /** Fire the on-login hook if loaded. Errors are logged but never block login. */
66
- export async function fireOnLoginHook(did) {
69
+ export async function fireOnLoginHook(did, oauthConfig) {
67
70
  if (!onLoginHook)
68
71
  return;
69
72
  try {
70
- await onLoginHook({ did, ensureRepo });
73
+ const base = buildBaseContext({ did });
74
+ const viewer = { did };
75
+ const hookPromise = onLoginHook({
76
+ ...base,
77
+ did,
78
+ db: { query: base.db.query, run: runSQL },
79
+ ensureRepo,
80
+ createRecord: async (collection, record, opts) => {
81
+ if (!oauthConfig)
82
+ throw new Error('No OAuth config — cannot write to PDS');
83
+ return pdsCreateRecord(oauthConfig, viewer, { collection, record, rkey: opts?.rkey });
84
+ },
85
+ putRecord: async (collection, rkey, record) => {
86
+ if (!oauthConfig)
87
+ throw new Error('No OAuth config — cannot write to PDS');
88
+ return pdsPutRecord(oauthConfig, viewer, { collection, rkey, record });
89
+ },
90
+ deleteRecord: async (collection, rkey) => {
91
+ if (!oauthConfig)
92
+ throw new Error('No OAuth config — cannot write to PDS');
93
+ await pdsDeleteRecord(oauthConfig, viewer, { collection, rkey });
94
+ },
95
+ });
96
+ const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error('on-login hook timed out after 30s')), 30_000));
97
+ await Promise.race([hookPromise, timeout]);
71
98
  }
72
99
  catch (err) {
73
- console.error('[hooks] onLogin hook error:', err.message);
100
+ emit('hooks', 'on_login_error', { did, error: err.message });
74
101
  }
75
102
  }
package/dist/indexer.d.ts CHANGED
@@ -6,6 +6,8 @@
6
6
  * `maxConcurrentBackfills`. Failed backfills retry with exponential delay up
7
7
  * to `maxRetries`.
8
8
  */
9
+ /** Wait for a DID's backfill to complete if one is in flight. */
10
+ export declare function awaitBackfill(did: string): Promise<void>;
9
11
  export declare function triggerAutoBackfill(did: string, attempt?: number): Promise<void>;
10
12
  /** Configuration for the firehose indexer. */
11
13
  interface IndexerOpts {
@@ -1 +1 @@
1
- {"version":3,"file":"indexer.d.ts","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"AAuJA;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAgEjF;AAED,8CAA8C;AAC9C,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,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAyBD;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAmDxE"}
1
+ {"version":3,"file":"indexer.d.ts","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"AAwJA;;;;;;;GAOG;AACH,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGxD;AAED,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CA4EjF;AAED,8CAA8C;AAC9C,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,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAyBD;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAmDxE"}
package/dist/indexer.js CHANGED
@@ -18,6 +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 backfillPromises = new Map();
21
22
  const pendingReschedule = new Set();
22
23
  // In-memory cache of repo status to avoid flooding the DB read queue
23
24
  const repoStatusCache = new Map();
@@ -130,6 +131,11 @@ function bufferWrite(item) {
130
131
  * `maxConcurrentBackfills`. Failed backfills retry with exponential delay up
131
132
  * to `maxRetries`.
132
133
  */
134
+ /** Wait for a DID's backfill to complete if one is in flight. */
135
+ export function awaitBackfill(did) {
136
+ const entry = backfillPromises.get(did);
137
+ return entry ? entry.promise : Promise.resolve();
138
+ }
133
139
  export async function triggerAutoBackfill(did, attempt = 0) {
134
140
  if (backfillInFlight.has(did))
135
141
  return;
@@ -145,6 +151,11 @@ export async function triggerAutoBackfill(did, attempt = 0) {
145
151
  }
146
152
  backfillInFlight.add(did);
147
153
  pendingBuffers.set(did, []);
154
+ if (!backfillPromises.has(did)) {
155
+ let resolveBackfill;
156
+ const promise = new Promise((r) => { resolveBackfill = r; });
157
+ backfillPromises.set(did, { promise, resolve: resolveBackfill });
158
+ }
148
159
  if (attempt === 0)
149
160
  await setRepoStatus(did, 'pending');
150
161
  const elapsed = timer();
@@ -184,6 +195,12 @@ export async function triggerAutoBackfill(did, attempt = 0) {
184
195
  error,
185
196
  retry_count: currentRetryCount,
186
197
  });
198
+ // Resolve awaiting callers (e.g. on-login hooks)
199
+ const entry = backfillPromises.get(did);
200
+ if (entry) {
201
+ entry.resolve();
202
+ backfillPromises.delete(did);
203
+ }
187
204
  if (status === 'error' && currentRetryCount < indexerMaxRetries) {
188
205
  const delaySecs = Math.min(currentRetryCount * 60, 3600);
189
206
  const delayMs = Math.max(delaySecs, 60) * 1000;
package/dist/main.js CHANGED
@@ -19,7 +19,7 @@ import { createAdapter } from "./database/adapter-factory.js";
19
19
  import { getDialect } from "./database/dialect.js";
20
20
  import { setSearchPort } from "./database/fts.js";
21
21
  import { initFeeds, listFeeds } from "./feeds.js";
22
- import { initXrpc, listXrpc, configureRelay, callXrpc } from "./xrpc.js";
22
+ import { initXrpc, listXrpc, configureRelay, configureOAuth, callXrpc } from "./xrpc.js";
23
23
  import { initOpengraph } from "./opengraph.js";
24
24
  import { initLabels, getLabelDefinitions } from "./labels.js";
25
25
  import { startIndexer } from "./indexer.js";
@@ -112,6 +112,7 @@ else {
112
112
  }
113
113
  // Register built-in dev.hatk.* handlers so callXrpc() can find them
114
114
  registerCoreHandlers(collections, config.oauth);
115
+ configureOAuth(config.oauth);
115
116
  // Write db/schema.sql (after setup, so setup-created tables are included)
116
117
  try {
117
118
  const schemaDir = resolve(configDir, 'db');
@@ -432,7 +432,7 @@ export async function handleCallback(config, code, state, iss) {
432
432
  dpopJkt: serverJkt,
433
433
  tokenExpiresAt: tokenData.expires_in ? Math.floor(Date.now() / 1000) + tokenData.expires_in : undefined,
434
434
  });
435
- await fireOnLoginHook(did);
435
+ await fireOnLoginHook(did, config);
436
436
  // Generate authorization code for the client
437
437
  const clientCode = randomToken();
438
438
  await storeAuthCode(clientCode, request.request_uri);
package/dist/xrpc.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  import type { BaseContext } from './hydrate.ts';
2
2
  import type { Row, FlatRow } from './lex-types.ts';
3
+ import type { OAuthConfig } from './config.ts';
3
4
  export type { Row, FlatRow };
5
+ /** Set the OAuth config used for record write helpers. Called once during boot. */
6
+ export declare function configureOAuth(config: OAuthConfig | null): void;
4
7
  /** Thrown from XRPC handlers to return a 400 response with an error message. */
5
8
  export declare class InvalidRequestError extends Error {
6
9
  status: number;
@@ -47,6 +50,17 @@ export interface XrpcContext<P = Record<string, string>, Records extends Record<
47
50
  }>;
48
51
  resolve: <R = unknown>(uris: string[]) => Promise<Row<R>[]>;
49
52
  exists: (collection: string, filters: Record<string, string>) => Promise<boolean>;
53
+ createRecord: (collection: string, record: Record<string, unknown>, opts?: {
54
+ rkey?: string;
55
+ }) => Promise<{
56
+ uri?: string;
57
+ cid?: string;
58
+ }>;
59
+ putRecord: (collection: string, rkey: string, record: Record<string, unknown>) => Promise<{
60
+ uri?: string;
61
+ cid?: string;
62
+ }>;
63
+ deleteRecord: (collection: string, rkey: string) => Promise<void>;
50
64
  }
51
65
  /** Set the relay URL used for blob URL generation. Called once during boot. */
52
66
  export declare function configureRelay(relay: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"xrpc.d.ts","sourceRoot":"","sources":["../src/xrpc.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"xrpc.d.ts","sourceRoot":"","sources":["../src/xrpc.ts"],"names":[],"mappings":"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"}
package/dist/xrpc.js CHANGED
@@ -32,6 +32,12 @@ import { log, emit, timer } from "./logger.js";
32
32
  import { querySQL, runSQL, packCursor, unpackCursor, isTakendownDid, filterTakendownDids, searchRecords, findUriByFields, } from "./database/db.js";
33
33
  import { resolveRecords, buildBaseContext } from "./hydrate.js";
34
34
  import { getLexicon } from "./database/schema.js";
35
+ import { pdsCreateRecord, pdsPutRecord, pdsDeleteRecord } from "./pds-proxy.js";
36
+ let _oauthConfig = null;
37
+ /** Set the OAuth config used for record write helpers. Called once during boot. */
38
+ export function configureOAuth(config) {
39
+ _oauthConfig = config;
40
+ }
35
41
  /** Thrown from XRPC handlers to return a 400 response with an error message. */
36
42
  export class InvalidRequestError extends Error {
37
43
  status = 400;
@@ -89,6 +95,27 @@ export function buildXrpcContext(params, cursor, limit, viewer, input) {
89
95
  const uri = await findUriByFields(collection, conditions);
90
96
  return uri !== null;
91
97
  },
98
+ createRecord: async (collection, record, opts) => {
99
+ if (!_oauthConfig)
100
+ throw new Error('No OAuth config — cannot write to PDS');
101
+ if (!viewer)
102
+ throw new Error('Authentication required to write records');
103
+ return pdsCreateRecord(_oauthConfig, viewer, { collection, record, rkey: opts?.rkey });
104
+ },
105
+ putRecord: async (collection, rkey, record) => {
106
+ if (!_oauthConfig)
107
+ throw new Error('No OAuth config — cannot write to PDS');
108
+ if (!viewer)
109
+ throw new Error('Authentication required to write records');
110
+ return pdsPutRecord(_oauthConfig, viewer, { collection, rkey, record });
111
+ },
112
+ deleteRecord: async (collection, rkey) => {
113
+ if (!_oauthConfig)
114
+ throw new Error('No OAuth config — cannot write to PDS');
115
+ if (!viewer)
116
+ throw new Error('Authentication required to write records');
117
+ await pdsDeleteRecord(_oauthConfig, viewer, { collection, rkey });
118
+ },
92
119
  };
93
120
  }
94
121
  const handlers = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hatk/hatk",
3
- "version": "0.0.1-alpha.40",
3
+ "version": "0.0.1-alpha.41",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "hatk": "dist/cli.js"