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 CHANGED
@@ -5,7 +5,18 @@
5
5
 
6
6
  Notifications for humans and agents: in-app inbox, email and webhook delivery, with a CLI, API, MCP server and SDK.
7
7
 
8
- **Status: 0.1.0, first release.** Works today: the notification model, preferences and mute, digest, an in-memory store and a D1 store (both pass one contract suite), signed webhook and email delivery through a dispatcher, an HTTP API in a Worker, an SDK, a CLI, MCP tools, per-recipient export and erase, and a retention sweep. Not done: a real email provider adapter, webhook endpoint management, and a web UI.
8
+ **Status: 0.2.1.** Breaking for 0.1.0 code and databases, see the CHANGELOG upgrade steps. Works today: the notification model, preferences and mute, digest, a store port from agentic-identity with its memory and D1 adapters, signed webhook and email delivery through a dispatcher, an HTTP API in a Worker, an SDK, a CLI, MCP tools, per-recipient export and erase, and a retention sweep. Not done: a real email provider adapter, webhook endpoint management, and a web UI.
9
+
10
+ ## Live demo
11
+
12
+ A demo Worker runs at https://agentic-notify-demo.hello-fd1.workers.dev. `GET /health` answers 200. The `/api/v1` routes need a bearer token, so without one they answer 401. The demo keeps its data in the EU and sweeps notifications after 7 days.
13
+
14
+ Redeploy your own copy with `wrangler.demo.jsonc` (create the D1 database with `--location weur`, put its id in the file, set the `NOTIFY_TOKENS` secret):
15
+
16
+ ```sh
17
+ npx wrangler secret put NOTIFY_TOKENS --config wrangler.demo.jsonc
18
+ WRANGLER_SEND_METRICS=false npm run deploy:demo
19
+ ```
9
20
 
10
21
  ## Install
11
22
 
@@ -18,9 +29,9 @@ npm install agentic-notify
18
29
  Library, with the memory store:
19
30
 
20
31
  ```ts
21
- import { createNotifier, MemoryStore } from "agentic-notify";
32
+ import { createNotifier, createMemoryStore } from "agentic-notify";
22
33
 
23
- const notifier = createNotifier({ store: new MemoryStore() });
34
+ const notifier = createNotifier({ store: createMemoryStore() });
24
35
  await notifier.send({
25
36
  recipient: { kind: "agent", id: "helper" },
26
37
  type: "approval_request",
@@ -78,6 +89,8 @@ Auth is a port: `PrincipalResolver` turns a request into `{ kind: "human" | "age
78
89
  ## Privacy
79
90
 
80
91
  - Export and erase work per recipient. `retentionMs` plus `sweep()` (or a cron trigger on the Worker, with `NOTIFY_RETENTION_DAYS`) deletes old notifications.
92
+ - Erase and sweep delete in batches of 100 inside one transaction each, so a large erase does not cost one query per row.
93
+ - The Worker reads `NOTIFY_REGION` (`eu`, `us` or `unknown`, default `eu`). The D1 adapter refuses a database that does not report a serving region in that area. For local runs without a real D1, set `NOTIFY_REGION=unknown`.
81
94
  - Logs hold ids, channel names and error names only. They never hold bodies or addresses.
82
95
  - Erase removes a recipient's own notifications and preferences. Notifications that name the person only as actor stay with their recipients.
83
96
 
@@ -1,3 +1,6 @@
1
+ // src/index.ts
2
+ import { createMemoryStore } from "agentic-identity";
3
+
1
4
  // src/delivery/dispatch.ts
2
5
  function createDispatcher(options) {
3
6
  return {
@@ -148,6 +151,7 @@ function createWebhookChannel(options) {
148
151
  }
149
152
 
150
153
  // src/index.ts
154
+ import { createD1Store, D1_SCHEMA } from "agentic-identity/cloudflare";
151
155
  var PACKAGE_NAME = "agentic-notify";
152
156
 
153
157
  export {
@@ -157,5 +161,8 @@ export {
157
161
  signPayload,
158
162
  verifySignature,
159
163
  createWebhookChannel,
160
- PACKAGE_NAME
164
+ PACKAGE_NAME,
165
+ createMemoryStore,
166
+ createD1Store,
167
+ D1_SCHEMA
161
168
  };
@@ -1,105 +1,3 @@
1
- import {
2
- canonicalJson,
3
- clampLimit,
4
- decodeCursor,
5
- encodeCursor
6
- } from "./chunk-GJFAXI2K.js";
7
-
8
- // package.json
9
- var package_default = {
10
- name: "agentic-notify",
11
- version: "0.1.0",
12
- description: "Notifications for humans and agents: in-app inbox, webhook and email delivery, with SDK, CLI, MCP server and Worker API.",
13
- keywords: [
14
- "notifications",
15
- "inbox",
16
- "webhook",
17
- "agents",
18
- "mcp",
19
- "cli",
20
- "cloudflare-workers",
21
- "typescript"
22
- ],
23
- license: "MIT",
24
- author: "Pooria Arab",
25
- repository: {
26
- type: "git",
27
- url: "git+https://github.com/pooriaarab/agentic-notify.git"
28
- },
29
- type: "module",
30
- private: false,
31
- engines: {
32
- node: ">=20"
33
- },
34
- files: [
35
- "dist"
36
- ],
37
- publishConfig: {
38
- access: "public"
39
- },
40
- mcpName: "io.github.pooriaarab/agentic-notify",
41
- main: "./dist/index.js",
42
- types: "./dist/index.d.ts",
43
- exports: {
44
- ".": {
45
- types: "./dist/index.d.ts",
46
- import: "./dist/index.js"
47
- },
48
- "./testing": {
49
- types: "./dist/testing.d.ts",
50
- import: "./dist/testing.js"
51
- },
52
- "./sdk": {
53
- types: "./dist/sdk.d.ts",
54
- import: "./dist/sdk.js"
55
- },
56
- "./worker": {
57
- types: "./dist/worker.d.ts",
58
- import: "./dist/worker.js"
59
- }
60
- },
61
- bin: {
62
- "agentic-notify": "./dist/cli.js",
63
- "agentic-notify-mcp": "./dist/mcp-bin.js"
64
- },
65
- scripts: {
66
- build: "tsup",
67
- typecheck: "tsc --noEmit",
68
- test: "vitest run",
69
- clean: "rm -rf dist",
70
- prepack: "npm run build",
71
- "ci:local": "npm run build && npm run typecheck && npm run check:worker && npm test",
72
- "check:worker": "esbuild src/worker.ts --bundle --platform=neutral --format=esm --log-level=warning --outfile=node_modules/.cache/worker-check.js"
73
- },
74
- dependencies: {
75
- "@modelcontextprotocol/sdk": "^1.12.0",
76
- hono: "^4.13.14",
77
- zod: "^3.25.0"
78
- },
79
- devDependencies: {
80
- "@types/node": "^22.0.0",
81
- esbuild: "^0.28.2",
82
- miniflare: "^4.20260730.0",
83
- tsup: "^8.0.0",
84
- typescript: "^5.6.0",
85
- vitest: "^3.0.0"
86
- },
87
- peerDependencies: {
88
- vitest: ">=3"
89
- },
90
- peerDependenciesMeta: {
91
- vitest: {
92
- optional: true
93
- }
94
- }
95
- };
96
-
97
- // src/version.ts
98
- if (typeof package_default.version !== "string" || package_default.version.length === 0) {
99
- throw new Error("package.json carries no version string");
100
- }
101
- var VERSION = package_default.version;
102
-
103
1
  // src/core/types.ts
104
2
  import { z } from "zod";
105
3
  var CHANNELS = ["inbox", "webhook", "email"];
@@ -142,12 +40,18 @@ function recipientKey(recipient) {
142
40
  return `${recipient.kind}:${recipient.id}`;
143
41
  }
144
42
 
145
- // src/core/service.ts
146
- import { z as z2 } from "zod";
147
-
148
43
  // src/core/gdpr.ts
149
44
  var NOTES = "notifications";
150
45
  var PREFS = "preferences";
46
+ var DELETE_BATCH = 100;
47
+ async function deleteAll(store, ids) {
48
+ for (let i = 0; i < ids.length; i += DELETE_BATCH) {
49
+ const batch = ids.slice(i, i + DELETE_BATCH);
50
+ await store.transaction(async (tx) => {
51
+ for (const id2 of batch) await tx.delete(NOTES, id2);
52
+ });
53
+ }
54
+ }
151
55
  async function* notificationDocs(store, recipient, ordered = true) {
152
56
  let cursor;
153
57
  do {
@@ -165,7 +69,7 @@ async function* notificationDocs(store, recipient, ordered = true) {
165
69
  async function exportRecipient(store, recipient) {
166
70
  const notifications = [];
167
71
  for await (const item of notificationDocs(store, recipient, false)) {
168
- const { recipientKey: _drop, ...rest } = item.doc;
72
+ const { recipientKey: _drop, ...rest } = item.data;
169
73
  notifications.push(notificationSchema.parse(rest));
170
74
  }
171
75
  notifications.sort((a, b) => a.createdAt - b.createdAt || (a.id < b.id ? -1 : 1));
@@ -179,7 +83,7 @@ async function eraseRecipient(store, recipient) {
179
83
  const ids = [];
180
84
  for await (const item of notificationDocs(store, recipient, false)) ids.push(item.id);
181
85
  if (ids.length === 0) break;
182
- for (const id2 of ids) await store.delete(NOTES, id2);
86
+ await deleteAll(store, ids);
183
87
  removed += ids.length;
184
88
  }
185
89
  await store.delete(PREFS, recipientKey(recipient));
@@ -192,20 +96,19 @@ async function sweepBefore(store, cutoff) {
192
96
  const gone = /* @__PURE__ */ new Set();
193
97
  for (; ; ) {
194
98
  const page = await store.query(NOTES, { orderBy: { field: "createdAt", direction: "asc" }, limit });
195
- const old = page.items.filter((i) => typeof i.doc.createdAt === "number" && i.doc.createdAt < cutoff);
99
+ const old = page.items.filter((i) => typeof i.data.createdAt === "number" && i.data.createdAt < cutoff);
196
100
  if (old.some((i) => gone.has(i.id))) throw new Error("retention sweep did not finish: deletes had no effect");
197
- for (const item of old) {
198
- await store.delete(NOTES, item.id);
199
- gone.add(item.id);
200
- }
101
+ await deleteAll(store, old.map((i) => i.id));
102
+ for (const item of old) gone.add(item.id);
201
103
  removed += old.length;
202
104
  if (old.length > 0) continue;
203
- if (page.items.length < limit || page.items.some((i) => typeof i.doc.createdAt === "number")) return removed;
105
+ if (page.items.length < limit || page.items.some((i) => typeof i.data.createdAt === "number")) return removed;
204
106
  throw new Error("retention sweep blocked: a full page of notifications has no usable createdAt");
205
107
  }
206
108
  }
207
109
 
208
110
  // src/core/service.ts
111
+ import { z as z2 } from "zod";
209
112
  var NotFoundError = class extends Error {
210
113
  code = "NOT_FOUND";
211
114
  constructor(message = "notification not found") {
@@ -220,6 +123,22 @@ function fromDoc(doc) {
220
123
  const { recipientKey: _drop, ...rest } = doc;
221
124
  return notificationSchema.parse(rest);
222
125
  }
126
+ var DEFAULT_LIMIT = 50;
127
+ var MAX_LIMIT = 200;
128
+ function clampLimit(limit) {
129
+ if (limit === void 0) return DEFAULT_LIMIT;
130
+ if (!Number.isInteger(limit) || limit < 1) throw new RangeError("limit must be an integer of 1 or more");
131
+ return Math.min(limit, MAX_LIMIT);
132
+ }
133
+ function checkCursor(cursor) {
134
+ try {
135
+ const bytes = Uint8Array.from(atob(cursor.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0));
136
+ const parsed = JSON.parse(new TextDecoder().decode(bytes));
137
+ if (Array.isArray(parsed) && parsed.length === 2 && Number.isFinite(parsed[0]) && typeof parsed[1] === "string") return;
138
+ } catch {
139
+ }
140
+ throw new RangeError("bad cursor");
141
+ }
223
142
  function createNotifier(options) {
224
143
  const { store } = options;
225
144
  const now = options.now ?? (() => Date.now());
@@ -253,41 +172,43 @@ function createNotifier(options) {
253
172
  readAt: null
254
173
  });
255
174
  if (!channels.includes("inbox")) return { notification, stored: false, channels, muted: false };
256
- if (!await store.create(NOTES, notification.id, toDoc(notification))) {
257
- throw new Error("notification id collision");
258
- }
175
+ await store.transaction(async (tx) => {
176
+ if (await tx.get(NOTES, notification.id)) throw new Error("notification id collision");
177
+ await tx.put(NOTES, notification.id, toDoc(notification));
178
+ });
259
179
  return { notification, stored: true, channels, muted: false };
260
180
  }
261
181
  async function list(recipient, opts = {}) {
262
182
  const r = recipientSchema.parse(recipient);
263
183
  const where = { recipientKey: recipientKey(r) };
264
184
  if (opts.unreadOnly) where.readAt = null;
185
+ if (opts.cursor !== void 0) checkCursor(opts.cursor);
186
+ const limit = clampLimit(opts.limit);
265
187
  const page = await store.query(NOTES, {
266
188
  where,
267
189
  orderBy: { field: "createdAt", direction: "desc" },
268
- limit: opts.limit,
190
+ limit,
269
191
  cursor: opts.cursor
270
192
  });
271
- return { items: page.items.map((i) => fromDoc(i.doc)), nextCursor: page.nextCursor };
193
+ return { items: page.items.map((i) => fromDoc(i.data)), nextCursor: page.nextCursor ?? null };
272
194
  }
273
- async function load(recipient, id2) {
274
- const r = recipientSchema.parse(recipient);
275
- const doc = await store.get(NOTES, id2);
276
- if (!doc || doc.recipientKey !== recipientKey(r)) throw new NotFoundError();
195
+ function check(doc, recipient) {
196
+ if (!doc || doc.recipientKey !== recipientKey(recipient)) throw new NotFoundError();
277
197
  return doc;
278
198
  }
279
199
  async function get(recipient, id2) {
280
- return fromDoc(await load(recipient, id2));
200
+ const r = recipientSchema.parse(recipient);
201
+ return fromDoc(check(await store.get(NOTES, id2), r));
281
202
  }
282
203
  async function markReadOnce(recipient, id2) {
283
- for (let attempt = 0; attempt < 5; attempt++) {
284
- const doc = await load(recipient, id2);
285
- const n = fromDoc(doc);
204
+ const r = recipientSchema.parse(recipient);
205
+ return store.transaction(async (tx) => {
206
+ const n = fromDoc(check(await tx.get(NOTES, id2), r));
286
207
  if (n.readAt !== null) return { notification: n, won: false };
287
208
  const next = notificationSchema.parse({ ...n, readAt: now() });
288
- if (await store.replaceIf(NOTES, id2, doc, toDoc(next))) return { notification: next, won: true };
289
- }
290
- throw new Error("could not mark read: too much contention");
209
+ await tx.put(NOTES, id2, toDoc(next));
210
+ return { notification: next, won: true };
211
+ });
291
212
  }
292
213
  async function markRead(recipient, id2) {
293
214
  return (await markReadOnce(recipient, id2)).notification;
@@ -366,110 +287,7 @@ function createNotifier(options) {
366
287
  };
367
288
  }
368
289
 
369
- // src/adapters/d1.ts
370
- var FIELD = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
371
- var SCHEMA = `CREATE TABLE IF NOT EXISTS notify_docs (
372
- collection TEXT NOT NULL,
373
- id TEXT NOT NULL,
374
- doc TEXT NOT NULL,
375
- PRIMARY KEY (collection, id)
376
- )`;
377
- function field(name) {
378
- if (!FIELD.test(name)) throw new RangeError("bad field name");
379
- return `json_extract(doc, '$.${name}')`;
380
- }
381
- function bindable(v) {
382
- return typeof v === "boolean" ? v ? 1 : 0 : v;
383
- }
384
- var TYPES = {
385
- number: ["integer", "real"],
386
- string: ["text"],
387
- boolean: ["true", "false"]
388
- };
389
- var INDEXES = [
390
- `CREATE INDEX IF NOT EXISTS notify_by_recipient ON notify_docs (collection, json_extract(doc, '$.recipientKey'), json_extract(doc, '$.createdAt'), id)`,
391
- `CREATE INDEX IF NOT EXISTS notify_by_created ON notify_docs (collection, json_extract(doc, '$.createdAt'), id)`
392
- ];
393
- async function migrateD1(db) {
394
- for (const sql of [SCHEMA, ...INDEXES]) await db.prepare(sql).bind().run();
395
- }
396
- var D1Store = class {
397
- constructor(db) {
398
- this.db = db;
399
- }
400
- db;
401
- async get(collection, id2) {
402
- const row = await this.db.prepare("SELECT doc FROM notify_docs WHERE collection = ? AND id = ?").bind(collection, id2).first();
403
- return row ? JSON.parse(row.doc) : null;
404
- }
405
- async put(collection, id2, doc) {
406
- await this.db.prepare("INSERT OR REPLACE INTO notify_docs (collection, id, doc) VALUES (?, ?, ?)").bind(collection, id2, canonicalJson(doc)).run();
407
- }
408
- async create(collection, id2, doc) {
409
- const res = await this.db.prepare("INSERT OR IGNORE INTO notify_docs (collection, id, doc) VALUES (?, ?, ?)").bind(collection, id2, canonicalJson(doc)).run();
410
- return (res.meta.changes ?? 0) > 0;
411
- }
412
- async replaceIf(collection, id2, expected, next) {
413
- const res = await this.db.prepare("UPDATE notify_docs SET doc = ? WHERE collection = ? AND id = ? AND doc = ?").bind(canonicalJson(next), collection, id2, canonicalJson(expected)).run();
414
- return (res.meta.changes ?? 0) > 0;
415
- }
416
- async delete(collection, id2) {
417
- await this.db.prepare("DELETE FROM notify_docs WHERE collection = ? AND id = ?").bind(collection, id2).run();
418
- }
419
- async query(collection, query = {}) {
420
- const limit = clampLimit(query.limit);
421
- const desc = query.orderBy?.direction === "desc";
422
- const key = query.orderBy ? field(query.orderBy.field) : "id";
423
- const conds = ["collection = ?"];
424
- const args = [collection];
425
- for (const [name, value] of Object.entries(query.where ?? {})) {
426
- if (value === null) conds.push(`${field(name)} IS NULL`);
427
- else {
428
- const types = TYPES[typeof value] ?? [];
429
- conds.push(`${field(name)} = ? AND json_type(doc, '$.${name}') IN (${types.map(() => "?").join(",")})`);
430
- args.push(bindable(value), ...types);
431
- }
432
- }
433
- if (query.cursor !== void 0) {
434
- const [cv, cid] = decodeCursor(query.cursor);
435
- if (query.orderBy && cv !== null) {
436
- const allowed = TYPES[typeof cv] ?? [];
437
- const marks = allowed.map(() => "?").join(",");
438
- const bad = await this.db.prepare(
439
- `SELECT 1 AS x FROM notify_docs WHERE ${conds.join(" AND ")} AND ${key} IS NOT NULL AND json_type(doc, '$.${query.orderBy.field}') NOT IN (${marks}) LIMIT 1`
440
- ).bind(...args, ...allowed).first();
441
- if (bad) throw new RangeError("bad cursor");
442
- }
443
- const idCmp = desc ? "<" : ">";
444
- if (!query.orderBy) {
445
- conds.push(`id ${idCmp} ?`);
446
- args.push(cid);
447
- } else if (cv === null) {
448
- conds.push(desc ? `(${key} IS NULL AND id < ?)` : `(${key} IS NOT NULL OR id > ?)`);
449
- args.push(cid);
450
- } else if (desc) {
451
- conds.push(`(${key} < ? OR ${key} IS NULL OR (${key} = ? AND id < ?))`);
452
- args.push(bindable(cv), bindable(cv), cid);
453
- } else {
454
- conds.push(`(${key} > ? OR (${key} = ? AND id > ?))`);
455
- args.push(bindable(cv), bindable(cv), cid);
456
- }
457
- }
458
- const dir = desc ? "DESC" : "ASC";
459
- const sql = `SELECT id, doc FROM notify_docs WHERE ${conds.join(" AND ")} ORDER BY ${key} ${dir}, id ${dir} LIMIT ?`;
460
- const { results } = await this.db.prepare(sql).bind(...args, limit + 1).all();
461
- const rows = results.slice(0, limit).map((r) => ({ id: r.id, doc: JSON.parse(r.doc) }));
462
- const last = rows[rows.length - 1];
463
- const lastKey = last && query.orderBy ? last.doc[query.orderBy.field] ?? null : last?.id ?? null;
464
- return {
465
- items: rows,
466
- nextCursor: results.length > limit && last ? encodeCursor(lastKey, last.id) : null
467
- };
468
- }
469
- };
470
-
471
290
  export {
472
- VERSION,
473
291
  CHANNELS,
474
292
  recipientSchema,
475
293
  typeNameSchema,
@@ -478,8 +296,7 @@ export {
478
296
  DEFAULT_CHANNELS,
479
297
  defaultPreferences,
480
298
  recipientKey,
299
+ NOTES,
481
300
  NotFoundError,
482
- createNotifier,
483
- migrateD1,
484
- D1Store
301
+ createNotifier
485
302
  };
@@ -0,0 +1,101 @@
1
+ // package.json
2
+ var package_default = {
3
+ name: "agentic-notify",
4
+ version: "0.2.1",
5
+ description: "Notifications for humans and agents: in-app inbox, webhook and email delivery, with SDK, CLI, MCP server and Worker API.",
6
+ keywords: [
7
+ "notifications",
8
+ "inbox",
9
+ "webhook",
10
+ "agents",
11
+ "mcp",
12
+ "cli",
13
+ "cloudflare-workers",
14
+ "typescript"
15
+ ],
16
+ license: "MIT",
17
+ author: "Pooria Arab",
18
+ repository: {
19
+ type: "git",
20
+ url: "git+https://github.com/pooriaarab/agentic-notify.git"
21
+ },
22
+ type: "module",
23
+ private: false,
24
+ engines: {
25
+ node: ">=20"
26
+ },
27
+ files: [
28
+ "dist"
29
+ ],
30
+ publishConfig: {
31
+ access: "public"
32
+ },
33
+ mcpName: "io.github.pooriaarab/agentic-notify",
34
+ main: "./dist/index.js",
35
+ types: "./dist/index.d.ts",
36
+ exports: {
37
+ ".": {
38
+ types: "./dist/index.d.ts",
39
+ import: "./dist/index.js"
40
+ },
41
+ "./testing": {
42
+ types: "./dist/testing.d.ts",
43
+ import: "./dist/testing.js"
44
+ },
45
+ "./sdk": {
46
+ types: "./dist/sdk.d.ts",
47
+ import: "./dist/sdk.js"
48
+ },
49
+ "./worker": {
50
+ types: "./dist/worker.d.ts",
51
+ import: "./dist/worker.js"
52
+ }
53
+ },
54
+ bin: {
55
+ "agentic-notify": "./dist/cli.js",
56
+ "agentic-notify-mcp": "./dist/mcp-bin.js"
57
+ },
58
+ scripts: {
59
+ build: "tsup",
60
+ typecheck: "tsc --noEmit",
61
+ test: "vitest run",
62
+ clean: "rm -rf dist",
63
+ prepack: "npm run build",
64
+ "ci:local": "npm run build && npm run typecheck && npm run check:worker && npm test",
65
+ "deploy:demo": "wrangler deploy --config wrangler.demo.jsonc",
66
+ "check:worker": "esbuild src/worker.ts --bundle --platform=neutral --format=esm --log-level=warning --outfile=node_modules/.cache/worker-check.js"
67
+ },
68
+ dependencies: {
69
+ "@modelcontextprotocol/sdk": "^1.12.0",
70
+ "agentic-identity": "^0.4.0",
71
+ hono: "^4.13.14",
72
+ zod: "^3.25.0"
73
+ },
74
+ devDependencies: {
75
+ "@types/node": "^22.0.0",
76
+ esbuild: "^0.28.2",
77
+ miniflare: "^4.20260730.0",
78
+ tsup: "^8.0.0",
79
+ typescript: "^5.6.0",
80
+ vitest: "^3.0.0",
81
+ wrangler: "^4.155.0"
82
+ },
83
+ peerDependencies: {
84
+ vitest: ">=3"
85
+ },
86
+ peerDependenciesMeta: {
87
+ vitest: {
88
+ optional: true
89
+ }
90
+ }
91
+ };
92
+
93
+ // src/version.ts
94
+ if (typeof package_default.version !== "string" || package_default.version.length === 0) {
95
+ throw new Error("package.json carries no version string");
96
+ }
97
+ var VERSION = package_default.version;
98
+
99
+ export {
100
+ VERSION
101
+ };
package/dist/cli.js CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  PACKAGE_NAME
4
- } from "./chunk-6CKFBZOF.js";
4
+ } from "./chunk-3N77SYRA.js";
5
5
  import {
6
6
  ApiError,
7
7
  createClient
8
8
  } from "./chunk-FJPEUDTG.js";
9
9
  import "./chunk-KJKM56FT.js";
10
+ import "./chunk-ARL7FN6Y.js";
10
11
  import {
11
12
  VERSION
12
- } from "./chunk-FMU2ED2H.js";
13
- import "./chunk-GJFAXI2K.js";
13
+ } from "./chunk-PHY45IVQ.js";
14
14
 
15
15
  // src/cli.ts
16
16
  import { realpathSync } from "fs";
@@ -1,6 +1,7 @@
1
- import { R as RecipientExport } from './gdpr-9I4eV86m.js';
2
- import { S as Store, D as DeliveryChannel, L as Logger, b as Doc, Q as Query, P as Page } from './types-Dkst26cb.js';
3
- import { S as SendInput, N as Notification, b as Channel, R as Recipient, D as Digest, P as Preferences } from './types-GuAgyMOc.js';
1
+ import { R as RecipientExport } from './gdpr-BAg1U1w6.js';
2
+ import { Store } from 'agentic-identity';
3
+ import { S as SendInput, N as Notification, C as Channel, R as Recipient, D as Digest, P as Preferences } from './types-anA8DMQH.js';
4
+ import { D as DeliveryChannel, L as Logger } from './types-BdX7UTFu.js';
4
5
 
5
6
  interface NotifierOptions {
6
7
  store: Store;
@@ -73,34 +74,4 @@ declare function createDispatcher(options: DispatcherOptions): {
73
74
  notify(input: SendInput): Promise<DispatchResult>;
74
75
  };
75
76
 
76
- /** The slice of the Cloudflare D1 binding this adapter uses. */
77
- interface D1Like {
78
- prepare(sql: string): {
79
- bind(...values: unknown[]): {
80
- first<T = unknown>(): Promise<T | null>;
81
- all<T = unknown>(): Promise<{
82
- results: T[];
83
- }>;
84
- run(): Promise<{
85
- meta: {
86
- changes?: number;
87
- };
88
- }>;
89
- };
90
- };
91
- }
92
- /** Create the table and indexes. Safe to run on every start. */
93
- declare function migrateD1(db: D1Like): Promise<void>;
94
- /** Store adapter for Cloudflare D1. Run `migrateD1` once first. */
95
- declare class D1Store implements Store {
96
- private readonly db;
97
- constructor(db: D1Like);
98
- get(collection: string, id: string): Promise<Doc | null>;
99
- put(collection: string, id: string, doc: Doc): Promise<void>;
100
- create(collection: string, id: string, doc: Doc): Promise<boolean>;
101
- replaceIf(collection: string, id: string, expected: Doc, next: Doc): Promise<boolean>;
102
- delete(collection: string, id: string): Promise<void>;
103
- query(collection: string, query?: Query): Promise<Page>;
104
- }
105
-
106
- export { type D1Like as D, type ListOptions as L, NotFoundError as N, type SendResult as S, D1Store as a, type DispatchResult as b, type DispatcherOptions as c, type ListResult as d, type Notifier as e, type NotifierOptions as f, createDispatcher as g, createNotifier as h, migrateD1 as m };
77
+ export { type DispatchResult as D, type ListOptions as L, NotFoundError as N, type SendResult as S, type DispatcherOptions as a, type ListResult as b, type Notifier as c, type NotifierOptions as d, createDispatcher as e, createNotifier as f };
@@ -1,4 +1,4 @@
1
- import { R as Recipient, P as Preferences, N as Notification } from './types-GuAgyMOc.js';
1
+ import { R as Recipient, P as Preferences, N as Notification } from './types-anA8DMQH.js';
2
2
 
3
3
  interface RecipientExport {
4
4
  recipient: Recipient;
package/dist/index.d.ts CHANGED
@@ -1,11 +1,14 @@
1
- export { D as D1Like, a as D1Store, b as DispatchResult, c as DispatcherOptions, L as ListOptions, d as ListResult, N as NotFoundError, e as Notifier, f as NotifierOptions, S as SendResult, g as createDispatcher, h as createNotifier, m as migrateD1 } from './d1-CUcNko0m.js';
2
- import { D as DeliveryChannel } from './types-Dkst26cb.js';
3
- export { a as DeliveryError, b as Doc, L as Logger, M as MemoryStore, P as Page, Q as Query, c as Scalar, S as Store } from './types-Dkst26cb.js';
4
- import { R as Recipient } from './types-GuAgyMOc.js';
5
- export { A as Actor, C as CHANNELS, b as Channel, c as DEFAULT_CHANNELS, D as Digest, d as DigestGroup, N as Notification, P as Preferences, a as ResourceRef, S as SendInput, e as defaultPreferences, r as recipientKey } from './types-GuAgyMOc.js';
6
- export { E as EmailChannelOptions, a as EmailMessage, b as EmailPort, c as createEmailChannel } from './email-UqtllxjF.js';
7
- export { R as RecipientExport } from './gdpr-9I4eV86m.js';
1
+ export { D as DispatchResult, a as DispatcherOptions, L as ListOptions, b as ListResult, N as NotFoundError, c as Notifier, d as NotifierOptions, S as SendResult, e as createDispatcher, f as createNotifier } from './dispatch-xe2IAqWe.js';
2
+ export { Doc, Page, Query, Scalar, Store, StoreOps, createMemoryStore } from 'agentic-identity';
3
+ import { R as Recipient } from './types-anA8DMQH.js';
4
+ export { A as Actor, b as CHANNELS, C as Channel, c as DEFAULT_CHANNELS, D as Digest, d as DigestGroup, N as Notification, P as Preferences, a as ResourceRef, S as SendInput, e as defaultPreferences, r as recipientKey } from './types-anA8DMQH.js';
5
+ import { D as DeliveryChannel } from './types-BdX7UTFu.js';
6
+ export { a as DeliveryError, L as Logger } from './types-BdX7UTFu.js';
7
+ export { E as EmailChannelOptions, a as EmailMessage, b as EmailPort, c as createEmailChannel } from './testing-46doJP5Y.js';
8
+ export { D1Like, D1_SCHEMA, createD1Store } from 'agentic-identity/cloudflare';
9
+ export { R as RecipientExport } from './gdpr-BAg1U1w6.js';
8
10
  import 'zod';
11
+ import 'agentic-identity/testing';
9
12
 
10
13
  declare const VERSION: string;
11
14