@hatk/hatk 0.0.1-alpha.50 → 0.0.1-alpha.52
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/adapter.d.ts.map +1 -1
- package/dist/adapter.js +2 -1
- package/dist/config.d.ts +13 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/db.js +8 -0
- package/dist/hooks.d.ts +45 -3
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +68 -9
- package/dist/indexer.d.ts.map +1 -1
- package/dist/indexer.js +16 -0
- package/dist/main.js +10 -0
- package/dist/push.d.ts +33 -0
- package/dist/push.d.ts.map +1 -0
- package/dist/push.js +180 -0
- package/dist/server-init.js +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +23 -0
- package/package.json +1 -1
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAgB,MAAM,WAAW,CAAA;AAEnF;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CA0BrE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBzF;AAED,wFAAwF;AACxF,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAgB,MAAM,WAAW,CAAA;AAEnF;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CA0BrE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBzF;AAED,wFAAwF;AACxF,eAAO,MAAM,WAAW,UAcvB,CAAA;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CACnB,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,EAChD,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,IAAI,KAAK,IAAI,6EA4BjF"}
|
package/dist/adapter.js
CHANGED
package/dist/config.d.ts
CHANGED
|
@@ -30,6 +30,16 @@ export interface BackfillConfig {
|
|
|
30
30
|
fetchTimeout: number;
|
|
31
31
|
maxRetries: number;
|
|
32
32
|
}
|
|
33
|
+
export interface ApnsPushConfig {
|
|
34
|
+
keyFile: string;
|
|
35
|
+
keyId: string;
|
|
36
|
+
teamId: string;
|
|
37
|
+
bundleId: string;
|
|
38
|
+
production?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface PushConfig {
|
|
41
|
+
apns: ApnsPushConfig;
|
|
42
|
+
}
|
|
33
43
|
export interface HatkConfig {
|
|
34
44
|
relay: string;
|
|
35
45
|
plc: string;
|
|
@@ -41,14 +51,16 @@ export interface HatkConfig {
|
|
|
41
51
|
backfill: BackfillConfig;
|
|
42
52
|
ftsRebuildInterval: number;
|
|
43
53
|
oauth: OAuthConfig | null;
|
|
54
|
+
push: PushConfig | null;
|
|
44
55
|
admins: string[];
|
|
45
56
|
}
|
|
46
57
|
/** Input type for defineConfig — fields that have defaults are optional. */
|
|
47
|
-
export type HatkConfigInput = Partial<Omit<HatkConfig, 'oauth' | 'backfill'>> & {
|
|
58
|
+
export type HatkConfigInput = Partial<Omit<HatkConfig, 'oauth' | 'backfill' | 'push'>> & {
|
|
48
59
|
oauth?: (Partial<OAuthConfig> & {
|
|
49
60
|
clients: OAuthClientConfig[];
|
|
50
61
|
}) | null;
|
|
51
62
|
backfill?: Partial<BackfillConfig>;
|
|
63
|
+
push?: PushConfig | null;
|
|
52
64
|
};
|
|
53
65
|
/** Identity function that provides type inference for hatk config files. */
|
|
54
66
|
export declare function defineConfig(config: HatkConfigInput): HatkConfigInput;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;IACrC,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAA;IACnC,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAA;IAC1C,OAAO,CAAC,EAAE,WAAW,EAAE,CAAA;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,OAAO,EAAE,iBAAiB,EAAE,CAAA;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,WAAW,EAAE,OAAO,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,cAAc,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,QAAQ,EAAE,cAAc,CAAA;IACxB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;IACzB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED,4EAA4E;AAC5E,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,UAAU,CAAC,CAAC,GAAG;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;IACrC,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAA;IACnC,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAA;IAC1C,OAAO,CAAC,EAAE,WAAW,EAAE,CAAA;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,OAAO,EAAE,iBAAiB,EAAE,CAAA;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,WAAW,EAAE,OAAO,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,cAAc,CAAA;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,cAAc,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,QAAQ,EAAE,cAAc,CAAA;IACxB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;IACzB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;IACvB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED,4EAA4E;AAC5E,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC,CAAC,GAAG;IACvF,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG;QAAE,OAAO,EAAE,iBAAiB,EAAE,CAAA;KAAE,CAAC,GAAG,IAAI,CAAA;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IAClC,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;CACzB,CAAA;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,CAErE;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAyDxE"}
|
package/dist/config.js
CHANGED
|
@@ -56,6 +56,7 @@ export async function loadConfig(configPath) {
|
|
|
56
56
|
},
|
|
57
57
|
ftsRebuildInterval: parseInt(env.FTS_REBUILD_INTERVAL || '') || parsed.ftsRebuildInterval || 5000,
|
|
58
58
|
oauth: null,
|
|
59
|
+
push: parsed.push || null,
|
|
59
60
|
admins: env.ADMINS ? env.ADMINS.split(',').map((s) => s.trim()) : parsed.admins || [],
|
|
60
61
|
};
|
|
61
62
|
const oauthRaw = parsed.oauth;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/database/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAkB,MAAM,aAAa,CAAA;AAC9D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAA;AAI1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,cAAc,CAAA;AAM1D,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AACD,wBAAgB,aAAa,IAAI,UAAU,CAE1C;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAMD,wBAAsB,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAcnG;AAMD,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,WAAW,EAAE,EAC3B,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/database/db.ts"],"names":[],"mappings":"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"}
|
package/dist/database/db.js
CHANGED
|
@@ -135,6 +135,14 @@ export async function initDatabase(adapter, dbPath, tableSchemas, ddlStatements)
|
|
|
135
135
|
}
|
|
136
136
|
await run(`CREATE INDEX IF NOT EXISTS idx_reports_status ON _reports(status)`);
|
|
137
137
|
await run(`CREATE INDEX IF NOT EXISTS idx_reports_subject_uri ON _reports(subject_uri)`);
|
|
138
|
+
// Push notification tokens
|
|
139
|
+
await run(`CREATE TABLE IF NOT EXISTS _push_tokens (
|
|
140
|
+
did TEXT NOT NULL,
|
|
141
|
+
token TEXT NOT NULL,
|
|
142
|
+
platform TEXT NOT NULL,
|
|
143
|
+
created_at TEXT NOT NULL,
|
|
144
|
+
PRIMARY KEY (did, token)
|
|
145
|
+
)`);
|
|
138
146
|
// OAuth tables
|
|
139
147
|
await port.executeMultiple(OAUTH_DDL);
|
|
140
148
|
// Migrations: add pds_auth_server to existing sessions tables
|
package/dist/hooks.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { OAuthConfig } from './config.ts';
|
|
2
2
|
import { type BaseContext } from './hydrate.ts';
|
|
3
|
+
import { type PushInterface } from './push.ts';
|
|
3
4
|
/** Context passed to the on-login hook after a successful OAuth login. */
|
|
4
5
|
export type OnLoginCtx = Omit<BaseContext, 'db'> & {
|
|
5
6
|
/** DID of the user who just logged in. */
|
|
@@ -26,18 +27,59 @@ export type OnLoginCtx = Omit<BaseContext, 'db'> & {
|
|
|
26
27
|
/** Delete a record from the user's PDS and local index. */
|
|
27
28
|
deleteRecord: (collection: string, rkey: string) => Promise<void>;
|
|
28
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
|
+
};
|
|
29
52
|
export declare function defineHook(event: 'on-login', handler: (ctx: OnLoginCtx) => Promise<void>): {
|
|
30
|
-
__type:
|
|
31
|
-
event:
|
|
53
|
+
__type: 'hook';
|
|
54
|
+
event: 'on-login';
|
|
32
55
|
handler: (ctx: OnLoginCtx) => Promise<void>;
|
|
33
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
|
+
};
|
|
34
65
|
/**
|
|
35
66
|
* Discover and load the on-login hook from the project's `hooks/` directory.
|
|
36
67
|
* Looks for `on-login.ts` or `on-login.js`. Safe to call if no hook exists.
|
|
37
68
|
*/
|
|
38
69
|
export declare function loadOnLoginHook(hooksDir: string): Promise<void>;
|
|
39
70
|
/** Register a hook from a scanned server/ module. */
|
|
40
|
-
export declare function registerHook(event: string, handler: Function): void;
|
|
71
|
+
export declare function registerHook(event: string, handler: Function, options?: any): void;
|
|
41
72
|
/** Fire the on-login hook if loaded. Errors are logged but never block login. */
|
|
42
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;
|
|
43
85
|
//# sourceMappingURL=hooks.d.ts.map
|
package/dist/hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
|
package/dist/hooks.js
CHANGED
|
@@ -12,19 +12,31 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
12
12
|
* Place hook modules in the `hooks/` directory. Currently supported hooks:
|
|
13
13
|
*
|
|
14
14
|
* - `on-login.ts` — called after each successful OAuth login
|
|
15
|
+
* - `on-commit-*.ts` — called after records are indexed from the firehose
|
|
15
16
|
*
|
|
16
|
-
* Each hook default-exports
|
|
17
|
-
* context object.
|
|
17
|
+
* Each hook default-exports the result of `defineHook()`.
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* ```ts
|
|
21
21
|
* // hooks/on-login.ts
|
|
22
|
-
* import
|
|
22
|
+
* import { defineHook } from '$hatk'
|
|
23
23
|
*
|
|
24
|
-
* export default async
|
|
25
|
-
* // Ensure the user's repo is backfilled on first login
|
|
24
|
+
* export default defineHook("on-login", async (ctx) => {
|
|
26
25
|
* await ctx.ensureRepo(ctx.did)
|
|
27
|
-
* }
|
|
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
|
+
* )
|
|
28
40
|
* ```
|
|
29
41
|
*/
|
|
30
42
|
import { existsSync } from 'node:fs';
|
|
@@ -34,10 +46,20 @@ import { log, emit } from "./logger.js";
|
|
|
34
46
|
import { setRepoStatus, runSQL } from "./database/db.js";
|
|
35
47
|
import { triggerAutoBackfill, awaitBackfill } from "./indexer.js";
|
|
36
48
|
import { buildBaseContext } from "./hydrate.js";
|
|
37
|
-
|
|
38
|
-
|
|
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}`);
|
|
39
60
|
}
|
|
40
61
|
let onLoginHook = null;
|
|
62
|
+
const onCommitHooks = [];
|
|
41
63
|
/**
|
|
42
64
|
* Discover and load the on-login hook from the project's `hooks/` directory.
|
|
43
65
|
* Looks for `on-login.ts` or `on-login.js`. Safe to call if no hook exists.
|
|
@@ -59,11 +81,16 @@ async function ensureRepo(did) {
|
|
|
59
81
|
await awaitBackfill(did);
|
|
60
82
|
}
|
|
61
83
|
/** Register a hook from a scanned server/ module. */
|
|
62
|
-
export function registerHook(event, handler) {
|
|
84
|
+
export function registerHook(event, handler, options) {
|
|
63
85
|
if (event === 'on-login') {
|
|
64
86
|
onLoginHook = handler;
|
|
65
87
|
log('[hooks] on-login hook registered');
|
|
66
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
|
+
}
|
|
67
94
|
}
|
|
68
95
|
/** Fire the on-login hook if loaded. Errors are logged but never block login. */
|
|
69
96
|
export async function fireOnLoginHook(did, oauthConfig) {
|
|
@@ -100,3 +127,35 @@ export async function fireOnLoginHook(did, oauthConfig) {
|
|
|
100
127
|
emit('hooks', 'on_login_error', { did, error: err.message });
|
|
101
128
|
}
|
|
102
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.handler({
|
|
144
|
+
action: item.action,
|
|
145
|
+
collection: item.collection,
|
|
146
|
+
record: item.record,
|
|
147
|
+
repo: item.authorDid,
|
|
148
|
+
uri: item.uri,
|
|
149
|
+
db: { query: base.db.query, run: runSQL },
|
|
150
|
+
lookup: base.lookup,
|
|
151
|
+
push,
|
|
152
|
+
}).catch((err) => {
|
|
153
|
+
emit('hooks', 'on_commit_error', {
|
|
154
|
+
collection: item.collection,
|
|
155
|
+
uri: item.uri,
|
|
156
|
+
error: err.message,
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
package/dist/indexer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexer.d.ts","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"indexer.d.ts","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"AAmKA;;;;;;;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
|
@@ -5,6 +5,7 @@ import { backfillRepo } from "./backfill.js";
|
|
|
5
5
|
import { rebuildAllIndexes } from "./database/fts.js";
|
|
6
6
|
import { log, emit, timer } from "./logger.js";
|
|
7
7
|
import { runLabelRules } from "./labels.js";
|
|
8
|
+
import { fireOnCommitHooks } from "./hooks.js";
|
|
8
9
|
import { getLexiconArray } from "./database/schema.js";
|
|
9
10
|
import { validateRecord } from '@bigmoves/lexicon';
|
|
10
11
|
let buffer = [];
|
|
@@ -71,6 +72,14 @@ async function flushBuffer() {
|
|
|
71
72
|
value: item.record,
|
|
72
73
|
}).catch(() => { });
|
|
73
74
|
}
|
|
75
|
+
// Fire on-commit hooks for inserted records (async, non-blocking)
|
|
76
|
+
fireOnCommitHooks(inserted.map((item) => ({
|
|
77
|
+
action: 'create',
|
|
78
|
+
collection: item.collection,
|
|
79
|
+
uri: item.uri,
|
|
80
|
+
authorDid: item.authorDid,
|
|
81
|
+
record: item.record,
|
|
82
|
+
})));
|
|
74
83
|
// Aggregate collection counts and unique DIDs for wide event
|
|
75
84
|
const collections = {};
|
|
76
85
|
const dids = new Set();
|
|
@@ -355,6 +364,13 @@ function processMessage(bytes, collections) {
|
|
|
355
364
|
const uri = `at://${did}/${op.path}`;
|
|
356
365
|
if (op.action === 'delete') {
|
|
357
366
|
deleteRecord(collection, uri);
|
|
367
|
+
fireOnCommitHooks([{
|
|
368
|
+
action: 'delete',
|
|
369
|
+
collection,
|
|
370
|
+
uri,
|
|
371
|
+
authorDid: did,
|
|
372
|
+
record: null,
|
|
373
|
+
}]);
|
|
358
374
|
continue;
|
|
359
375
|
}
|
|
360
376
|
for (const [cid, data] of blocks) {
|
package/dist/main.js
CHANGED
|
@@ -32,6 +32,7 @@ import { runBackfill } from "./backfill.js";
|
|
|
32
32
|
import { initOAuth } from "./oauth/server.js";
|
|
33
33
|
import { parseSessionCookie, getSessionCookieName } from "./oauth/session.js";
|
|
34
34
|
import { loadOnLoginHook } from "./hooks.js";
|
|
35
|
+
import { initPush, isPushEnabled } from "./push.js";
|
|
35
36
|
import { initSetup } from "./setup.js";
|
|
36
37
|
import { initServer } from "./server-init.js";
|
|
37
38
|
const configPath = process.argv[2] || 'hatk.config.ts';
|
|
@@ -132,6 +133,15 @@ if (config.oauth) {
|
|
|
132
133
|
await initOAuth(config.oauth, config.plc, config.relay);
|
|
133
134
|
log(`[main] OAuth initialized (issuer: ${config.oauth.issuer})`);
|
|
134
135
|
}
|
|
136
|
+
if (config.push) {
|
|
137
|
+
initPush(config.push, configDir);
|
|
138
|
+
if (isPushEnabled()) {
|
|
139
|
+
log(`[main] Push initialized (APNs bundle: ${config.push.apns.bundleId})`);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
log(`[main] Push configured but key file missing — push disabled`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
135
145
|
// 5. Start server immediately (don't wait for backfill)
|
|
136
146
|
const collectionSet = new Set(collections);
|
|
137
147
|
const backfillOpts = {
|
package/dist/push.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface ApnsConfig {
|
|
2
|
+
keyFile: string;
|
|
3
|
+
keyId: string;
|
|
4
|
+
teamId: string;
|
|
5
|
+
bundleId: string;
|
|
6
|
+
production?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface PushConfig {
|
|
9
|
+
apns: ApnsConfig;
|
|
10
|
+
}
|
|
11
|
+
export interface PushPayload {
|
|
12
|
+
did: string;
|
|
13
|
+
title: string;
|
|
14
|
+
body: string;
|
|
15
|
+
data?: Record<string, string>;
|
|
16
|
+
collapseId?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface PushInterface {
|
|
19
|
+
send: (payload: PushPayload) => Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
/** Initialize push with config. Must be called before send(). */
|
|
22
|
+
export declare function initPush(config: PushConfig, configDir: string): void;
|
|
23
|
+
/** Check if push is configured and available. */
|
|
24
|
+
export declare function isPushEnabled(): boolean;
|
|
25
|
+
/** Build the push interface injected into hook contexts. */
|
|
26
|
+
export declare function buildPushInterface(): PushInterface;
|
|
27
|
+
/** Register a push token for a DID. Upserts on conflict. */
|
|
28
|
+
export declare function registerToken(did: string, token: string, platform: string): Promise<void>;
|
|
29
|
+
/** Remove a push token. */
|
|
30
|
+
export declare function removeToken(token: string): Promise<void>;
|
|
31
|
+
/** Unregister a specific token for a DID. */
|
|
32
|
+
export declare function unregisterToken(did: string, token: string): Promise<void>;
|
|
33
|
+
//# sourceMappingURL=push.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../src/push.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,UAAU,CAAA;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9C;AAOD,iEAAiE;AACjE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CASpE;AAED,iDAAiD;AACjD,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED,4DAA4D;AAC5D,wBAAgB,kBAAkB,IAAI,aAAa,CAElD;AAgJD,4DAA4D;AAC5D,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO/F;AAED,2BAA2B;AAC3B,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9D;AAED,6CAA6C;AAC7C,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/E"}
|
package/dist/push.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Push notification delivery via APNs HTTP/2.
|
|
3
|
+
*
|
|
4
|
+
* Provides `push.send()` for use in on-commit hook context. Looks up device
|
|
5
|
+
* tokens, builds APNs payloads, and sends via HTTP/2. Self-cleans invalid
|
|
6
|
+
* tokens on Apple 410 responses. Fire-and-forget — failures are logged via
|
|
7
|
+
* `emit()` but never throw.
|
|
8
|
+
*/
|
|
9
|
+
import { connect } from 'node:http2';
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { createSign } from 'node:crypto';
|
|
12
|
+
import { resolve } from 'node:path';
|
|
13
|
+
import { emit } from "./logger.js";
|
|
14
|
+
import { runSQL, querySQL } from "./database/db.js";
|
|
15
|
+
let pushConfig = null;
|
|
16
|
+
let apnsKey = null;
|
|
17
|
+
let cachedJwt = null;
|
|
18
|
+
let http2Session = null;
|
|
19
|
+
/** Initialize push with config. Must be called before send(). */
|
|
20
|
+
export function initPush(config, configDir) {
|
|
21
|
+
pushConfig = config;
|
|
22
|
+
const keyPath = resolve(configDir, config.apns.keyFile);
|
|
23
|
+
try {
|
|
24
|
+
apnsKey = readFileSync(keyPath, 'utf8');
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
emit('push', 'init_error', { error: `APNs key file not found: ${keyPath}` });
|
|
28
|
+
pushConfig = null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Check if push is configured and available. */
|
|
32
|
+
export function isPushEnabled() {
|
|
33
|
+
return pushConfig !== null && apnsKey !== null;
|
|
34
|
+
}
|
|
35
|
+
/** Build the push interface injected into hook contexts. */
|
|
36
|
+
export function buildPushInterface() {
|
|
37
|
+
return { send };
|
|
38
|
+
}
|
|
39
|
+
/** Create a JWT for APNs authentication (cached for 50 minutes). */
|
|
40
|
+
function getApnsJwt() {
|
|
41
|
+
if (cachedJwt && Date.now() < cachedJwt.expires)
|
|
42
|
+
return cachedJwt.token;
|
|
43
|
+
if (!pushConfig || !apnsKey)
|
|
44
|
+
throw new Error('Push not initialized');
|
|
45
|
+
const header = Buffer.from(JSON.stringify({
|
|
46
|
+
alg: 'ES256',
|
|
47
|
+
kid: pushConfig.apns.keyId,
|
|
48
|
+
})).toString('base64url');
|
|
49
|
+
const now = Math.floor(Date.now() / 1000);
|
|
50
|
+
const claims = Buffer.from(JSON.stringify({
|
|
51
|
+
iss: pushConfig.apns.teamId,
|
|
52
|
+
iat: now,
|
|
53
|
+
})).toString('base64url');
|
|
54
|
+
const signer = createSign('SHA256');
|
|
55
|
+
signer.update(`${header}.${claims}`);
|
|
56
|
+
const signature = signer.sign(apnsKey, 'base64url');
|
|
57
|
+
const token = `${header}.${claims}.${signature}`;
|
|
58
|
+
cachedJwt = { token, expires: Date.now() + 50 * 60 * 1000 };
|
|
59
|
+
return token;
|
|
60
|
+
}
|
|
61
|
+
/** Get or create an HTTP/2 connection to APNs. */
|
|
62
|
+
function getHttp2Session() {
|
|
63
|
+
if (http2Session && !http2Session.closed && !http2Session.destroyed) {
|
|
64
|
+
return http2Session;
|
|
65
|
+
}
|
|
66
|
+
const host = pushConfig?.apns.production !== false
|
|
67
|
+
? 'https://api.push.apple.com'
|
|
68
|
+
: 'https://api.sandbox.push.apple.com';
|
|
69
|
+
emit('push', 'connecting', { host });
|
|
70
|
+
http2Session = connect(host, {
|
|
71
|
+
peerMaxConcurrentStreams: 100,
|
|
72
|
+
});
|
|
73
|
+
http2Session.on('connect', () => {
|
|
74
|
+
emit('push', 'connected', { host });
|
|
75
|
+
});
|
|
76
|
+
http2Session.on('error', (err) => {
|
|
77
|
+
emit('push', 'connection_error', { host, error: err.message });
|
|
78
|
+
http2Session = null;
|
|
79
|
+
});
|
|
80
|
+
http2Session.on('close', () => {
|
|
81
|
+
http2Session = null;
|
|
82
|
+
});
|
|
83
|
+
return http2Session;
|
|
84
|
+
}
|
|
85
|
+
/** Send a push notification to all devices registered for a DID. */
|
|
86
|
+
async function send(payload) {
|
|
87
|
+
if (!pushConfig || !apnsKey)
|
|
88
|
+
return;
|
|
89
|
+
const tokens = await querySQL(`SELECT token, platform FROM _push_tokens WHERE did = $1`, [payload.did]);
|
|
90
|
+
if (tokens.length === 0)
|
|
91
|
+
return;
|
|
92
|
+
const jwt = getApnsJwt();
|
|
93
|
+
const apnsPayload = JSON.stringify({
|
|
94
|
+
aps: {
|
|
95
|
+
alert: { title: payload.title, body: payload.body },
|
|
96
|
+
sound: 'default',
|
|
97
|
+
},
|
|
98
|
+
...(payload.data || {}),
|
|
99
|
+
});
|
|
100
|
+
for (const { token, platform } of tokens) {
|
|
101
|
+
if (platform !== 'apns')
|
|
102
|
+
continue;
|
|
103
|
+
sendToApns(token, apnsPayload, jwt, payload).catch(() => { });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** Send a single APNs push and handle the response. */
|
|
107
|
+
async function sendToApns(token, payload, jwt, original) {
|
|
108
|
+
const session = getHttp2Session();
|
|
109
|
+
const headers = {
|
|
110
|
+
':method': 'POST',
|
|
111
|
+
':path': `/3/device/${token}`,
|
|
112
|
+
'authorization': `bearer ${jwt}`,
|
|
113
|
+
'apns-topic': pushConfig.apns.bundleId,
|
|
114
|
+
'apns-push-type': 'alert',
|
|
115
|
+
};
|
|
116
|
+
if (original.collapseId) {
|
|
117
|
+
headers['apns-collapse-id'] = original.collapseId;
|
|
118
|
+
}
|
|
119
|
+
return new Promise((resolve) => {
|
|
120
|
+
const req = session.request(headers);
|
|
121
|
+
let settled = false;
|
|
122
|
+
const done = () => { if (settled)
|
|
123
|
+
return; settled = true; resolve(); };
|
|
124
|
+
req.setTimeout(15_000, () => {
|
|
125
|
+
req.close();
|
|
126
|
+
emit('push', 'send_error', { did: original.did, error: 'APNs request timed out' });
|
|
127
|
+
done();
|
|
128
|
+
});
|
|
129
|
+
let status = 0;
|
|
130
|
+
let body = '';
|
|
131
|
+
req.on('response', (headers) => {
|
|
132
|
+
status = headers[':status'];
|
|
133
|
+
});
|
|
134
|
+
req.on('data', (chunk) => {
|
|
135
|
+
body += chunk.toString();
|
|
136
|
+
});
|
|
137
|
+
req.on('end', async () => {
|
|
138
|
+
if (settled)
|
|
139
|
+
return;
|
|
140
|
+
if (status === 200) {
|
|
141
|
+
emit('push', 'sent', { did: original.did, token: token.slice(0, 8) + '...' });
|
|
142
|
+
}
|
|
143
|
+
else if (status === 410) {
|
|
144
|
+
// Token is no longer valid — remove it
|
|
145
|
+
await removeToken(token).catch(() => { });
|
|
146
|
+
emit('push', 'token_removed', { did: original.did, reason: 'expired' });
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
emit('push', 'send_error', {
|
|
150
|
+
did: original.did,
|
|
151
|
+
status,
|
|
152
|
+
body: body.slice(0, 200),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
done();
|
|
156
|
+
});
|
|
157
|
+
req.on('error', (err) => {
|
|
158
|
+
if (settled)
|
|
159
|
+
return;
|
|
160
|
+
emit('push', 'send_error', { did: original.did, error: err.message });
|
|
161
|
+
done();
|
|
162
|
+
});
|
|
163
|
+
req.write(payload);
|
|
164
|
+
req.end();
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/** Register a push token for a DID. Upserts on conflict. */
|
|
168
|
+
export async function registerToken(did, token, platform) {
|
|
169
|
+
await runSQL(`INSERT INTO _push_tokens (did, token, platform, created_at)
|
|
170
|
+
VALUES ($1, $2, $3, $4)
|
|
171
|
+
ON CONFLICT (did, token) DO UPDATE SET platform = excluded.platform`, [did, token, platform, new Date().toISOString()]);
|
|
172
|
+
}
|
|
173
|
+
/** Remove a push token. */
|
|
174
|
+
export async function removeToken(token) {
|
|
175
|
+
await runSQL(`DELETE FROM _push_tokens WHERE token = $1`, [token]);
|
|
176
|
+
}
|
|
177
|
+
/** Unregister a specific token for a DID. */
|
|
178
|
+
export async function unregisterToken(did, token) {
|
|
179
|
+
await runSQL(`DELETE FROM _push_tokens WHERE did = $1 AND token = $2`, [did, token]);
|
|
180
|
+
}
|
package/dist/server-init.js
CHANGED
|
@@ -38,7 +38,7 @@ export async function initServer(serverDir, opts) {
|
|
|
38
38
|
}
|
|
39
39
|
// 4. Register hooks
|
|
40
40
|
for (const entry of scanned.hooks) {
|
|
41
|
-
registerHook(entry.mod.event, entry.mod.handler);
|
|
41
|
+
registerHook(entry.mod.event, entry.mod.handler, entry.mod);
|
|
42
42
|
}
|
|
43
43
|
// 5. Register labels (clear first for hot-reload)
|
|
44
44
|
clearLabels();
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAyDA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AA0B9C;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAyDA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AA0B9C;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CA2L3F;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;IACzB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxF,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CA+zB5F;AAGD,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,OAAO,EAAE,OAAO,KAAK;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,GACpB,OAAO,WAAW,EAAE,MAAM,CAG5B"}
|
package/dist/server.js
CHANGED
|
@@ -154,6 +154,29 @@ export function registerCoreHandlers(collections, oauth) {
|
|
|
154
154
|
throw new InvalidRequestError('Authentication required');
|
|
155
155
|
return pdsUploadBlob(oauth, viewer, input, 'application/octet-stream');
|
|
156
156
|
});
|
|
157
|
+
registerCoreXrpcHandler('dev.hatk.push.registerToken', async (_params, _cursor, _limit, viewer, input) => {
|
|
158
|
+
if (!viewer)
|
|
159
|
+
throw new InvalidRequestError('Authentication required');
|
|
160
|
+
const body = input;
|
|
161
|
+
if (!body.token || typeof body.token !== 'string')
|
|
162
|
+
throw new InvalidRequestError('Missing or invalid token');
|
|
163
|
+
const platform = body.platform || 'apns';
|
|
164
|
+
if (!['apns', 'fcm', 'web'].includes(platform))
|
|
165
|
+
throw new InvalidRequestError('Invalid platform');
|
|
166
|
+
const { registerToken } = await import("./push.js");
|
|
167
|
+
await registerToken(viewer.did, body.token, platform);
|
|
168
|
+
return { success: true };
|
|
169
|
+
});
|
|
170
|
+
registerCoreXrpcHandler('dev.hatk.push.unregisterToken', async (_params, _cursor, _limit, viewer, input) => {
|
|
171
|
+
if (!viewer)
|
|
172
|
+
throw new InvalidRequestError('Authentication required');
|
|
173
|
+
const body = input;
|
|
174
|
+
if (!body.token || typeof body.token !== 'string')
|
|
175
|
+
throw new InvalidRequestError('Missing or invalid token');
|
|
176
|
+
const { unregisterToken } = await import("./push.js");
|
|
177
|
+
await unregisterToken(viewer.did, body.token);
|
|
178
|
+
return { success: true };
|
|
179
|
+
});
|
|
157
180
|
registerCoreXrpcHandler('dev.hatk.createReport', async (_params, _cursor, _limit, viewer, input) => {
|
|
158
181
|
if (!viewer)
|
|
159
182
|
throw new InvalidRequestError('Authentication required');
|