agentic-notify 0.1.0 → 0.2.1
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/README.md +16 -3
- package/dist/{chunk-6CKFBZOF.js → chunk-3N77SYRA.js} +8 -1
- package/dist/{chunk-FMU2ED2H.js → chunk-ARL7FN6Y.js} +52 -235
- package/dist/chunk-PHY45IVQ.js +101 -0
- package/dist/cli.js +3 -3
- package/dist/{d1-CUcNko0m.d.ts → dispatch-xe2IAqWe.d.ts} +5 -34
- package/dist/{gdpr-9I4eV86m.d.ts → gdpr-BAg1U1w6.d.ts} +1 -1
- package/dist/index.d.ts +10 -7
- package/dist/index.js +10 -10
- package/dist/mcp-bin.js +23 -15
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +82 -7
- package/dist/sdk.d.ts +8 -8
- package/dist/{email-UqtllxjF.d.ts → testing-46doJP5Y.d.ts} +3 -2
- package/dist/testing.d.ts +4 -12
- package/dist/testing.js +2 -147
- package/dist/types-BdX7UTFu.d.ts +20 -0
- package/dist/{types-GuAgyMOc.d.ts → types-anA8DMQH.d.ts} +31 -31
- package/dist/worker.d.ts +10 -6
- package/dist/worker.js +17 -7
- package/package.json +5 -2
- package/dist/chunk-DEPJ3SHO.js +0 -86
- package/dist/chunk-GJFAXI2K.js +0 -104
- package/dist/types-Dkst26cb.d.ts +0 -69
package/dist/worker.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
3
|
-
import { R as Recipient } from './types-
|
|
4
|
-
import '
|
|
5
|
-
import './
|
|
2
|
+
import { c as Notifier, e as createDispatcher } from './dispatch-xe2IAqWe.js';
|
|
3
|
+
import { R as Recipient } from './types-anA8DMQH.js';
|
|
4
|
+
import { D1Like } from 'agentic-identity/cloudflare';
|
|
5
|
+
import './gdpr-BAg1U1w6.js';
|
|
6
|
+
import 'agentic-identity';
|
|
7
|
+
import './types-BdX7UTFu.js';
|
|
6
8
|
|
|
7
9
|
/** Who is calling. `kind` has no default: a missing kind is an error. */
|
|
8
10
|
declare const principalSchema: z.ZodObject<{
|
|
@@ -11,12 +13,12 @@ declare const principalSchema: z.ZodObject<{
|
|
|
11
13
|
/** Allowed to send notifications to others. */
|
|
12
14
|
canSend: z.ZodOptional<z.ZodBoolean>;
|
|
13
15
|
}, "strict", z.ZodTypeAny, {
|
|
14
|
-
id: string;
|
|
15
16
|
kind: "human" | "agent";
|
|
17
|
+
id: string;
|
|
16
18
|
canSend?: boolean | undefined;
|
|
17
19
|
}, {
|
|
18
|
-
id: string;
|
|
19
20
|
kind: "human" | "agent";
|
|
21
|
+
id: string;
|
|
20
22
|
canSend?: boolean | undefined;
|
|
21
23
|
}>;
|
|
22
24
|
type Principal = z.infer<typeof principalSchema>;
|
|
@@ -38,6 +40,8 @@ interface WorkerEnv {
|
|
|
38
40
|
DB?: D1Like;
|
|
39
41
|
/** Secret. JSON map of bearer token (32 bytes or more) to principal. */
|
|
40
42
|
NOTIFY_TOKENS?: string;
|
|
43
|
+
/** Data region of the store: "eu", "us" or "unknown". Default "eu". */
|
|
44
|
+
NOTIFY_REGION?: string;
|
|
41
45
|
/** Retention window in days. Unset keeps notifications. */
|
|
42
46
|
NOTIFY_RETENTION_DAYS?: string;
|
|
43
47
|
}
|
package/dist/worker.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
NOTES,
|
|
3
3
|
NotFoundError,
|
|
4
|
-
VERSION,
|
|
5
4
|
createNotifier,
|
|
6
|
-
migrateD1,
|
|
7
5
|
preferencesSchema,
|
|
8
6
|
recipientSchema,
|
|
9
7
|
resourceRefSchema,
|
|
10
8
|
typeNameSchema
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import
|
|
9
|
+
} from "./chunk-ARL7FN6Y.js";
|
|
10
|
+
import {
|
|
11
|
+
VERSION
|
|
12
|
+
} from "./chunk-PHY45IVQ.js";
|
|
13
13
|
|
|
14
14
|
// src/api.ts
|
|
15
15
|
import { Hono } from "hono";
|
|
@@ -113,17 +113,27 @@ function createApp(options) {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
// src/worker.ts
|
|
116
|
+
import { parseRegion } from "agentic-identity";
|
|
117
|
+
import { createD1Store, D1_SCHEMA } from "agentic-identity/cloudflare";
|
|
116
118
|
function json(value, status = 200) {
|
|
117
119
|
return new Response(JSON.stringify(value), { status, headers: { "content-type": "application/json" } });
|
|
118
120
|
}
|
|
121
|
+
async function hasLegacyRows(db) {
|
|
122
|
+
const table = await db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'notify_docs'").bind().first();
|
|
123
|
+
if (!table) return false;
|
|
124
|
+
return await db.prepare("SELECT 1 AS found FROM notify_docs LIMIT 1").bind().first() !== null;
|
|
125
|
+
}
|
|
119
126
|
function createWorker(config) {
|
|
120
127
|
const apps = /* @__PURE__ */ new WeakMap();
|
|
121
128
|
async function buildNotifier(env) {
|
|
122
129
|
if (!env.DB) return null;
|
|
123
|
-
await
|
|
130
|
+
if (await hasLegacyRows(env.DB)) throw new Error("notify_docs holds rows that were not copied to store_docs");
|
|
131
|
+
await env.DB.prepare(D1_SCHEMA).bind().run();
|
|
124
132
|
const days = env.NOTIFY_RETENTION_DAYS === void 0 ? void 0 : Number(env.NOTIFY_RETENTION_DAYS);
|
|
133
|
+
const store = createD1Store(env.DB, { region: parseRegion(env.NOTIFY_REGION ?? "eu") });
|
|
134
|
+
await store.query(NOTES, { limit: 1 });
|
|
125
135
|
return createNotifier({
|
|
126
|
-
store
|
|
136
|
+
store,
|
|
127
137
|
retentionMs: days === void 0 ? void 0 : days * 864e5
|
|
128
138
|
});
|
|
129
139
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-notify",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Notifications for humans and agents: in-app inbox, webhook and email delivery, with SDK, CLI, MCP server and Worker API.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"notifications",
|
|
@@ -61,10 +61,12 @@
|
|
|
61
61
|
"clean": "rm -rf dist",
|
|
62
62
|
"prepack": "npm run build",
|
|
63
63
|
"ci:local": "npm run build && npm run typecheck && npm run check:worker && npm test",
|
|
64
|
+
"deploy:demo": "wrangler deploy --config wrangler.demo.jsonc",
|
|
64
65
|
"check:worker": "esbuild src/worker.ts --bundle --platform=neutral --format=esm --log-level=warning --outfile=node_modules/.cache/worker-check.js"
|
|
65
66
|
},
|
|
66
67
|
"dependencies": {
|
|
67
68
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
69
|
+
"agentic-identity": "^0.4.0",
|
|
68
70
|
"hono": "^4.13.14",
|
|
69
71
|
"zod": "^3.25.0"
|
|
70
72
|
},
|
|
@@ -74,7 +76,8 @@
|
|
|
74
76
|
"miniflare": "^4.20260730.0",
|
|
75
77
|
"tsup": "^8.0.0",
|
|
76
78
|
"typescript": "^5.6.0",
|
|
77
|
-
"vitest": "^3.0.0"
|
|
79
|
+
"vitest": "^3.0.0",
|
|
80
|
+
"wrangler": "^4.155.0"
|
|
78
81
|
},
|
|
79
82
|
"peerDependencies": {
|
|
80
83
|
"vitest": ">=3"
|
package/dist/chunk-DEPJ3SHO.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
PACKAGE_NAME
|
|
3
|
-
} from "./chunk-6CKFBZOF.js";
|
|
4
|
-
import {
|
|
5
|
-
ApiError
|
|
6
|
-
} from "./chunk-FJPEUDTG.js";
|
|
7
|
-
import {
|
|
8
|
-
VERSION,
|
|
9
|
-
preferencesSchema,
|
|
10
|
-
recipientSchema,
|
|
11
|
-
resourceRefSchema,
|
|
12
|
-
typeNameSchema
|
|
13
|
-
} from "./chunk-FMU2ED2H.js";
|
|
14
|
-
|
|
15
|
-
// src/mcp.ts
|
|
16
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
17
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
18
|
-
import { z } from "zod";
|
|
19
|
-
async function wrap(fn) {
|
|
20
|
-
try {
|
|
21
|
-
return { content: [{ type: "text", text: JSON.stringify(await fn()) }] };
|
|
22
|
-
} catch (error) {
|
|
23
|
-
if (error instanceof ApiError) {
|
|
24
|
-
return { content: [{ type: "text", text: JSON.stringify({ error: error.code, status: error.status }) }], isError: true };
|
|
25
|
-
}
|
|
26
|
-
throw error;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
function createMcpServer(client) {
|
|
30
|
-
const server = new McpServer({ name: PACKAGE_NAME, version: VERSION });
|
|
31
|
-
const need = (fn) => () => wrap(async () => {
|
|
32
|
-
if (!client) throw new ApiError(0, "not_configured");
|
|
33
|
-
return fn(client);
|
|
34
|
-
});
|
|
35
|
-
const read = { readOnlyHint: true };
|
|
36
|
-
const write = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
37
|
-
server.registerTool(
|
|
38
|
-
"ping",
|
|
39
|
-
{ description: "Check that the server runs. Returns the package version.", inputSchema: {}, annotations: read },
|
|
40
|
-
async () => ({ content: [{ type: "text", text: JSON.stringify({ ok: true, version: VERSION }) }] })
|
|
41
|
-
);
|
|
42
|
-
server.registerTool("list_notifications", {
|
|
43
|
-
description: "List your notifications, newest first.",
|
|
44
|
-
inputSchema: { unreadOnly: z.boolean().optional(), limit: z.number().int().min(1).max(200).optional(), cursor: z.string().optional() },
|
|
45
|
-
annotations: read
|
|
46
|
-
}, (a) => need((c) => c.list(a))());
|
|
47
|
-
server.registerTool(
|
|
48
|
-
"read_notification",
|
|
49
|
-
{ description: "Get one notification by id.", inputSchema: { id: z.string() }, annotations: read },
|
|
50
|
-
({ id }) => need((c) => c.get(id))()
|
|
51
|
-
);
|
|
52
|
-
server.registerTool(
|
|
53
|
-
"mark_read",
|
|
54
|
-
{ description: "Mark one notification as read.", inputSchema: { id: z.string() }, annotations: write },
|
|
55
|
-
({ id }) => need((c) => c.markRead(id))()
|
|
56
|
-
);
|
|
57
|
-
server.registerTool(
|
|
58
|
-
"mark_all_read",
|
|
59
|
-
{ description: "Mark all your notifications as read.", inputSchema: {}, annotations: write },
|
|
60
|
-
need((c) => c.markAllRead())
|
|
61
|
-
);
|
|
62
|
-
server.registerTool(
|
|
63
|
-
"get_preferences",
|
|
64
|
-
{ description: "Read your notification preferences.", inputSchema: {}, annotations: read },
|
|
65
|
-
need((c) => c.getPreferences())
|
|
66
|
-
);
|
|
67
|
-
server.registerTool("set_preferences", {
|
|
68
|
-
description: "Replace your notification preferences: channels per type, mute, muted types.",
|
|
69
|
-
inputSchema: preferencesSchema.shape,
|
|
70
|
-
annotations: write
|
|
71
|
-
}, (a) => need((c) => c.setPreferences(a))());
|
|
72
|
-
server.registerTool("send_notification", {
|
|
73
|
-
description: "Send a notification. You must hold the send right. You are the actor.",
|
|
74
|
-
inputSchema: { recipient: recipientSchema, type: typeNameSchema, resource: resourceRefSchema, body: z.string().max(2e3) },
|
|
75
|
-
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }
|
|
76
|
-
}, (a) => need((c) => c.send(a))());
|
|
77
|
-
return server;
|
|
78
|
-
}
|
|
79
|
-
async function startMcp(client) {
|
|
80
|
-
await createMcpServer(client).connect(new StdioServerTransport());
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export {
|
|
84
|
-
createMcpServer,
|
|
85
|
-
startMcp
|
|
86
|
-
};
|
package/dist/chunk-GJFAXI2K.js
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
// src/core/store.ts
|
|
2
|
-
var MAX_LIMIT = 200;
|
|
3
|
-
var DEFAULT_LIMIT = 50;
|
|
4
|
-
function clampLimit(limit) {
|
|
5
|
-
if (limit === void 0) return DEFAULT_LIMIT;
|
|
6
|
-
if (!Number.isInteger(limit) || limit < 1) {
|
|
7
|
-
throw new RangeError("limit must be an integer of 1 or more");
|
|
8
|
-
}
|
|
9
|
-
return Math.min(limit, MAX_LIMIT);
|
|
10
|
-
}
|
|
11
|
-
function encodeCursor(value, id) {
|
|
12
|
-
return btoa(unescape(encodeURIComponent(JSON.stringify([value, id]))));
|
|
13
|
-
}
|
|
14
|
-
function decodeCursor(cursor) {
|
|
15
|
-
try {
|
|
16
|
-
const parsed = JSON.parse(decodeURIComponent(escape(atob(cursor))));
|
|
17
|
-
if (Array.isArray(parsed) && parsed.length === 2 && typeof parsed[1] === "string" && (parsed[0] === null || ["string", "number", "boolean"].includes(typeof parsed[0]))) {
|
|
18
|
-
return [parsed[0], parsed[1]];
|
|
19
|
-
}
|
|
20
|
-
} catch {
|
|
21
|
-
}
|
|
22
|
-
throw new RangeError("bad cursor");
|
|
23
|
-
}
|
|
24
|
-
function compare(a, b) {
|
|
25
|
-
if (a === b) return 0;
|
|
26
|
-
if (a === null) return -1;
|
|
27
|
-
if (b === null) return 1;
|
|
28
|
-
return a < b ? -1 : 1;
|
|
29
|
-
}
|
|
30
|
-
function canonicalJson(value) {
|
|
31
|
-
return JSON.stringify(
|
|
32
|
-
value,
|
|
33
|
-
(_k, v) => v && typeof v === "object" && !Array.isArray(v) ? Object.fromEntries(Object.entries(v).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) : v
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
function sameDoc(a, b) {
|
|
37
|
-
return canonicalJson(a) === canonicalJson(b);
|
|
38
|
-
}
|
|
39
|
-
var MemoryStore = class {
|
|
40
|
-
data = /* @__PURE__ */ new Map();
|
|
41
|
-
coll(name) {
|
|
42
|
-
let c = this.data.get(name);
|
|
43
|
-
if (!c) {
|
|
44
|
-
c = /* @__PURE__ */ new Map();
|
|
45
|
-
this.data.set(name, c);
|
|
46
|
-
}
|
|
47
|
-
return c;
|
|
48
|
-
}
|
|
49
|
-
async get(collection, id) {
|
|
50
|
-
const doc = this.coll(collection).get(id);
|
|
51
|
-
return doc ? structuredClone(doc) : null;
|
|
52
|
-
}
|
|
53
|
-
async put(collection, id, doc) {
|
|
54
|
-
this.coll(collection).set(id, structuredClone(doc));
|
|
55
|
-
}
|
|
56
|
-
async create(collection, id, doc) {
|
|
57
|
-
const c = this.coll(collection);
|
|
58
|
-
if (c.has(id)) return false;
|
|
59
|
-
c.set(id, structuredClone(doc));
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
async replaceIf(collection, id, expected, next) {
|
|
63
|
-
const c = this.coll(collection);
|
|
64
|
-
const current = c.get(id);
|
|
65
|
-
if (!current || !sameDoc(current, expected)) return false;
|
|
66
|
-
c.set(id, structuredClone(next));
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
async delete(collection, id) {
|
|
70
|
-
this.coll(collection).delete(id);
|
|
71
|
-
}
|
|
72
|
-
async query(collection, query = {}) {
|
|
73
|
-
const limit = clampLimit(query.limit);
|
|
74
|
-
const field = query.orderBy?.field;
|
|
75
|
-
const dir = query.orderBy?.direction === "desc" ? -1 : 1;
|
|
76
|
-
const where = Object.entries(query.where ?? {});
|
|
77
|
-
const key = (id, doc) => field ? doc[field] ?? null : id;
|
|
78
|
-
let rows = [...this.coll(collection)].filter(([, doc]) => where.every(([k, v]) => (doc[k] ?? null) === v)).sort(([ia, a], [ib, b]) => dir * (compare(key(ia, a), key(ib, b)) || compare(ia, ib)));
|
|
79
|
-
if (query.cursor !== void 0) {
|
|
80
|
-
const [cv, cid] = decodeCursor(query.cursor);
|
|
81
|
-
const kind = (v) => v === null ? "null" : typeof v;
|
|
82
|
-
if (rows.some(([id, doc]) => key(id, doc) !== null && cv !== null && kind(key(id, doc)) !== kind(cv))) {
|
|
83
|
-
throw new RangeError("bad cursor");
|
|
84
|
-
}
|
|
85
|
-
rows = rows.filter(([id, doc]) => dir * (compare(key(id, doc), cv) || compare(id, cid)) > 0);
|
|
86
|
-
}
|
|
87
|
-
const slice = rows.slice(0, limit + 1);
|
|
88
|
-
const hasMore = slice.length > limit;
|
|
89
|
-
const items = slice.slice(0, limit).map(([id, doc]) => ({ id, doc: structuredClone(doc) }));
|
|
90
|
-
const last = items[items.length - 1];
|
|
91
|
-
return {
|
|
92
|
-
items,
|
|
93
|
-
nextCursor: hasMore && last ? encodeCursor(key(last.id, last.doc), last.id) : null
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
export {
|
|
99
|
-
clampLimit,
|
|
100
|
-
encodeCursor,
|
|
101
|
-
decodeCursor,
|
|
102
|
-
canonicalJson,
|
|
103
|
-
MemoryStore
|
|
104
|
-
};
|
package/dist/types-Dkst26cb.d.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { N as Notification } from './types-GuAgyMOc.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Store port. Documents are flat JSON objects in named collections.
|
|
5
|
-
* The shape fits document stores and SQL alike: equality filters, one
|
|
6
|
-
* orderBy, a limit, cursor paging. No joins.
|
|
7
|
-
*/
|
|
8
|
-
type Scalar = string | number | boolean | null;
|
|
9
|
-
type Doc = Record<string, unknown>;
|
|
10
|
-
interface Query {
|
|
11
|
-
/** Equality filters on top-level scalar fields. */
|
|
12
|
-
where?: Record<string, Scalar>;
|
|
13
|
-
/** One sort field. Ties break by id, in the same direction. */
|
|
14
|
-
orderBy?: {
|
|
15
|
-
field: string;
|
|
16
|
-
direction: "asc" | "desc";
|
|
17
|
-
};
|
|
18
|
-
limit?: number;
|
|
19
|
-
/** Opaque value from a previous page. */
|
|
20
|
-
cursor?: string;
|
|
21
|
-
}
|
|
22
|
-
interface Page {
|
|
23
|
-
items: {
|
|
24
|
-
id: string;
|
|
25
|
-
doc: Doc;
|
|
26
|
-
}[];
|
|
27
|
-
nextCursor: string | null;
|
|
28
|
-
}
|
|
29
|
-
interface Store {
|
|
30
|
-
get(collection: string, id: string): Promise<Doc | null>;
|
|
31
|
-
/** Insert or replace. */
|
|
32
|
-
put(collection: string, id: string, doc: Doc): Promise<void>;
|
|
33
|
-
/** Insert only. Returns false when the id exists. Atomic. */
|
|
34
|
-
create(collection: string, id: string, doc: Doc): Promise<boolean>;
|
|
35
|
-
/** Replace only when the stored doc still equals `expected`. Equality is structural: key order does not matter. Atomic. */
|
|
36
|
-
replaceIf(collection: string, id: string, expected: Doc, next: Doc): Promise<boolean>;
|
|
37
|
-
delete(collection: string, id: string): Promise<void>;
|
|
38
|
-
query(collection: string, query?: Query): Promise<Page>;
|
|
39
|
-
}
|
|
40
|
-
/** In-memory adapter. Also the reference for the contract suite. */
|
|
41
|
-
declare class MemoryStore implements Store {
|
|
42
|
-
private readonly data;
|
|
43
|
-
private coll;
|
|
44
|
-
get(collection: string, id: string): Promise<Doc | null>;
|
|
45
|
-
put(collection: string, id: string, doc: Doc): Promise<void>;
|
|
46
|
-
create(collection: string, id: string, doc: Doc): Promise<boolean>;
|
|
47
|
-
replaceIf(collection: string, id: string, expected: Doc, next: Doc): Promise<boolean>;
|
|
48
|
-
delete(collection: string, id: string): Promise<void>;
|
|
49
|
-
query(collection: string, query?: Query): Promise<Page>;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** A delivery channel other than the inbox. */
|
|
53
|
-
interface DeliveryChannel {
|
|
54
|
-
/** Resolves "skipped" when the recipient has no target (no endpoint, no address). Throws on failure. */
|
|
55
|
-
deliver(notification: Notification): Promise<"sent" | "skipped">;
|
|
56
|
-
}
|
|
57
|
-
declare class DeliveryError extends Error {
|
|
58
|
-
readonly attempts: number;
|
|
59
|
-
readonly code = "DELIVERY_FAILED";
|
|
60
|
-
constructor(message: string, attempts: number, options?: {
|
|
61
|
-
cause?: unknown;
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
/** Logger that takes ids and counts only. Never pass content or addresses. */
|
|
65
|
-
interface Logger {
|
|
66
|
-
warn(message: string, fields?: Record<string, string | number>): void;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export { type DeliveryChannel as D, type Logger as L, MemoryStore as M, type Page as P, type Query as Q, type Store as S, DeliveryError as a, type Doc as b, type Scalar as c };
|