agentic-notify 0.3.0 → 0.4.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 +54 -11
- package/dist/{chunk-O574VONP.js → chunk-O2W4ELN4.js} +4 -4
- package/dist/cli.js +10 -2
- package/dist/{dispatch-LBnkLOQg.d.ts → dispatch-CH4Ju-_1.d.ts} +4 -4
- package/dist/{gdpr-CUq5MUwo.d.ts → gdpr-C3YxbZp-.d.ts} +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.js +1 -1
- package/dist/mcp-bin.js +2 -2
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +1 -1
- package/dist/sdk.d.ts +10 -10
- package/dist/{testing-B5slvYDV.d.ts → testing-DEBqTQFK.d.ts} +2 -2
- package/dist/testing.d.ts +3 -3
- package/dist/types-BAG4ZSoy.d.ts +101 -0
- package/dist/{types-DONKNIOo.d.ts → types-DhgcIImw.d.ts} +1 -1
- package/dist/worker.d.ts +16 -33
- package/dist/worker.js +67 -62
- package/package.json +4 -4
- package/dist/types-C842YAMe.d.ts +0 -217
package/README.md
CHANGED
|
@@ -5,16 +5,15 @@
|
|
|
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.
|
|
8
|
+
**Status: 0.4.1.** Breaking for Worker auth, see "Migrating from `NOTIFY_TOKENS`" below. 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
9
|
|
|
10
10
|
## Live demo
|
|
11
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
|
|
12
|
+
A demo Worker runs at https://agentic-notify-demo.hello-fd1.workers.dev. `GET /health` answers 200. The `/api/v1` routes need a key, so without one they answer 401. The demo keeps its data in the EU and sweeps notifications after 7 days.
|
|
13
13
|
|
|
14
|
-
Redeploy your own copy with `wrangler.demo.jsonc` (create the D1 database with `--location weur`, put its id in the file,
|
|
14
|
+
Redeploy your own copy with `wrangler.demo.jsonc` (create the D1 database with `--location weur`, put its id in the file, then add principals and keys, see Identity):
|
|
15
15
|
|
|
16
16
|
```sh
|
|
17
|
-
npx wrangler secret put NOTIFY_TOKENS --config wrangler.demo.jsonc
|
|
18
17
|
WRANGLER_SEND_METRICS=false npm run deploy:demo
|
|
19
18
|
```
|
|
20
19
|
|
|
@@ -42,16 +41,16 @@ await notifier.send({
|
|
|
42
41
|
const { items } = await notifier.list({ kind: "agent", id: "helper" });
|
|
43
42
|
```
|
|
44
43
|
|
|
45
|
-
Worker (D1 binding `DB
|
|
44
|
+
Worker (D1 binding `DB`):
|
|
46
45
|
|
|
47
46
|
```sh
|
|
48
47
|
# Create the database first: npx wrangler d1 create agentic-notify --location weur
|
|
49
|
-
# NOTIFY_TOKENS is JSON: { "<token of 32+ bytes>": { "kind": "human", "id": "ana", "canSend": true } }
|
|
50
|
-
npx wrangler secret put NOTIFY_TOKENS
|
|
51
48
|
npx wrangler deploy
|
|
52
49
|
```
|
|
53
50
|
|
|
54
|
-
|
|
51
|
+
The Worker reads keys and principals from the same D1 database, with `agentic-identity`. Issue a key for each caller with `agentic-identity` (for example `issueCredential`, or its Worker), into this database. See Identity below.
|
|
52
|
+
|
|
53
|
+
Without a D1 binding, every `/api/v1` call answers 503. A request without a valid key answers 401, on unknown paths too. Nobody gets in by default.
|
|
55
54
|
|
|
56
55
|
CLI, SDK and MCP talk to that Worker:
|
|
57
56
|
|
|
@@ -64,7 +63,9 @@ npx agentic-notify mcp # tools: ping, list_notifications, read_notification
|
|
|
64
63
|
# export_data, erase_data, send_notification
|
|
65
64
|
```
|
|
66
65
|
|
|
67
|
-
|
|
66
|
+
`npx agentic-notify mcp --help` (or `-h`) prints the usage and exits 0. `npx agentic-notify mcp --version` (or `-V` or `-v`) prints the version and exits 0. Neither starts the server.
|
|
67
|
+
|
|
68
|
+
The MCP server needs `NOTIFY_URL` and `NOTIFY_TOKEN`. Without them only `ping` works. `erase_data` needs `confirm: true` and a key with `notify:admin`. `send_notification` needs `notify-send:write`. A tool that lacks its scope reports 403.
|
|
68
69
|
|
|
69
70
|
```ts
|
|
70
71
|
import { createClient } from "agentic-notify/sdk";
|
|
@@ -74,7 +75,16 @@ console.log(await client.unreadCount());
|
|
|
74
75
|
|
|
75
76
|
## HTTP API
|
|
76
77
|
|
|
77
|
-
All routes sit under `/api/v1` and need `Authorization: Bearer <
|
|
78
|
+
All routes sit under `/api/v1` and need `Authorization: Bearer <key>`. `GET /health` is open. A missing or bad key answers 401. A good key without the scope of the route answers 403. Each route needs one scope:
|
|
79
|
+
|
|
80
|
+
| Scope | Routes |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| `notify:read` | `GET /notifications`, `GET /notifications/:id`, `GET /unread-count`, `GET /digest`, `GET /preferences`, `GET /me/export` |
|
|
83
|
+
| `notify:write` | `POST /notifications/:id/read`, `POST /notifications/read-all`, `PUT /preferences` |
|
|
84
|
+
| `notify-send:write` | `POST /notifications` |
|
|
85
|
+
| `notify:admin` | `DELETE /me` |
|
|
86
|
+
|
|
87
|
+
A scope with a higher action covers the lower ones, so `notify:admin` covers `notify:write` and `notify:read`. `*:admin` covers all. `notify-send` is a separate resource, so a key that can only send cannot read.
|
|
78
88
|
|
|
79
89
|
| Route | Use |
|
|
80
90
|
| --- | --- |
|
|
@@ -87,7 +97,22 @@ All routes sit under `/api/v1` and need `Authorization: Bearer <token>`. `GET /h
|
|
|
87
97
|
|
|
88
98
|
## Identity
|
|
89
99
|
|
|
90
|
-
|
|
100
|
+
The Worker authenticates with `agentic-identity`. `requirePrincipal` from `agentic-identity/http` reads the credential, and the `Auth` port checks that it is not expired or revoked. The default `Auth` takes a bearer key, and also a `session` cookie that `agentic-identity` sets. A write with a cookie is refused, because no origin is allowed here. Pass your own `Auth` to accept bearer keys only. The default `Auth` is `createStoreAuth` over the same D1 store. Each route checks one scope (see HTTP API). A delegated agent holds only the scopes that its person also holds.
|
|
101
|
+
|
|
102
|
+
A person, and a `user_token` of that person, use the inbox of the person. An agent (`agent`, `agent_of_human` or `agent_of_agent`) uses the inbox of its own id. A caller reads and changes only its own notifications.
|
|
103
|
+
|
|
104
|
+
To use another identity system, call `createWorker({ auth: (env, store) => myAuth })`, where `auth` builds your own `Auth` from the Worker env and the store. Import `createWorker` from `agentic-notify/worker`.
|
|
105
|
+
|
|
106
|
+
### Migrating from `NOTIFY_TOKENS`
|
|
107
|
+
|
|
108
|
+
Before 0.4.0, the Worker read a static `NOTIFY_TOKENS` secret: a map of token to `{ kind, id, canSend }`. The tokens had no scopes. The Worker no longer reads it. Steps:
|
|
109
|
+
|
|
110
|
+
1. Delete the `NOTIFY_TOKENS` secret (`npx wrangler secret delete NOTIFY_TOKENS`).
|
|
111
|
+
2. Make each caller a principal in the D1 database, and issue it a key with `agentic-identity`. The old `{ "kind": "human" }` becomes kind `human`, and `{ "kind": "agent" }` becomes kind `agent`.
|
|
112
|
+
3. Give each principal scopes. An old token could read, change and erase its own inbox. To keep that, use `notify:admin`. For less, use `notify:write` (it covers `notify:read`) or `notify:read`. For the old `canSend: true`, add `notify-send:write`. It is a separate resource, so it does not cover `notify:read`: a caller that sends and reads needs both.
|
|
113
|
+
4. Give the new key to the CLI, SDK and MCP server as `NOTIFY_TOKEN`.
|
|
114
|
+
|
|
115
|
+
Library users: `createWorker` takes `auth` in place of `resolver`. `authorizeSend` still works as an extra check after the scope. Its first argument is now a `PrincipalContext` (`principalId` in place of `id`, no `canSend`). Its default changed: it was "only `canSend: true`", and now every caller with `notify-send:write` may send unless you pass your own.
|
|
91
116
|
|
|
92
117
|
## Privacy
|
|
93
118
|
|
|
@@ -97,6 +122,24 @@ Auth is a port: `PrincipalResolver` turns a request into `{ kind: "human" | "age
|
|
|
97
122
|
- Logs hold ids, channel names and error names only. They never hold bodies or addresses.
|
|
98
123
|
- Erase removes a recipient's own notifications and preferences. Notifications that name the person only as actor stay with their recipients.
|
|
99
124
|
|
|
125
|
+
## Testing
|
|
126
|
+
|
|
127
|
+
`agentic-notify/testing` helps you test a store adapter and your own code.
|
|
128
|
+
|
|
129
|
+
`runStoreContract(make)` runs the store contract suite. Call it at the top level of a vitest test
|
|
130
|
+
file, and install `vitest` 3 or later. The factory makes a new store for each call. A store made
|
|
131
|
+
without `shared` must start empty. Stores made with the same `shared` value must see the same data.
|
|
132
|
+
So the factory passes `options` to the store:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { createMemoryStore } from "agentic-notify";
|
|
136
|
+
import { runStoreContract } from "agentic-notify/testing";
|
|
137
|
+
|
|
138
|
+
runStoreContract((options) => createMemoryStore(options));
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`TestEmailAdapter` records each message in memory and can fail a set number of sends.
|
|
142
|
+
|
|
100
143
|
## Limits
|
|
101
144
|
|
|
102
145
|
- The default Worker serves the inbox. To fan out to webhook and email, compose `createApp` with `createDispatcher` in your own Worker.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// package.json
|
|
2
2
|
var package_default = {
|
|
3
3
|
name: "agentic-notify",
|
|
4
|
-
version: "0.
|
|
4
|
+
version: "0.4.1",
|
|
5
5
|
description: "Notifications for humans and agents: in-app inbox, webhook and email delivery, with SDK, CLI, MCP server and Worker API.",
|
|
6
6
|
keywords: [
|
|
7
7
|
"notifications",
|
|
@@ -66,10 +66,10 @@ var package_default = {
|
|
|
66
66
|
"check:worker": "esbuild src/worker.ts --bundle --platform=neutral --format=esm --log-level=warning --outfile=node_modules/.cache/worker-check.js"
|
|
67
67
|
},
|
|
68
68
|
dependencies: {
|
|
69
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
70
|
-
"agentic-identity": "^0.
|
|
69
|
+
"@modelcontextprotocol/sdk": "^1.23.0",
|
|
70
|
+
"agentic-identity": "^0.7.0",
|
|
71
71
|
hono: "^4.13.14",
|
|
72
|
-
zod: "^
|
|
72
|
+
zod: "^4.6.7"
|
|
73
73
|
},
|
|
74
74
|
devDependencies: {
|
|
75
75
|
"@types/node": "^22.0.0",
|
package/dist/cli.js
CHANGED
|
@@ -10,7 +10,7 @@ import "./chunk-KJKM56FT.js";
|
|
|
10
10
|
import "./chunk-ARL7FN6Y.js";
|
|
11
11
|
import {
|
|
12
12
|
VERSION
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-O2W4ELN4.js";
|
|
14
14
|
|
|
15
15
|
// src/cli.ts
|
|
16
16
|
import { realpathSync } from "fs";
|
|
@@ -43,7 +43,7 @@ function helpText() {
|
|
|
43
43
|
" mcp Start the MCP server on stdio.",
|
|
44
44
|
"",
|
|
45
45
|
"Environment: NOTIFY_URL (server base url), NOTIFY_TOKEN (bearer token).",
|
|
46
|
-
"Flags: --help, -h; --version, -V."
|
|
46
|
+
"Flags: --help, -h; --version, -V. mcp also takes -v for --version."
|
|
47
47
|
].join("\n");
|
|
48
48
|
}
|
|
49
49
|
function flags(args, known) {
|
|
@@ -84,6 +84,14 @@ async function runCli(argv, io = defaultIo()) {
|
|
|
84
84
|
io.out(VERSION);
|
|
85
85
|
return 0;
|
|
86
86
|
}
|
|
87
|
+
if (cmd === "mcp" && args.some((a) => a === "--help" || a === "-h")) {
|
|
88
|
+
io.out(helpText());
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
|
91
|
+
if (cmd === "mcp" && args.some((a) => a === "--version" || a === "-V" || a === "-v")) {
|
|
92
|
+
io.out(VERSION);
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
87
95
|
try {
|
|
88
96
|
if (cmd === "mcp") {
|
|
89
97
|
const { startMcp } = await import("./mcp.js");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { R as RecipientExport } from './gdpr-
|
|
1
|
+
import { R as RecipientExport } from './gdpr-C3YxbZp-.js';
|
|
2
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-
|
|
4
|
-
import { D as DeliveryChannel, L as Logger } from './types-
|
|
3
|
+
import { S as SendInput, N as Notification, C as Channel, R as Recipient, D as Digest, P as Preferences } from './types-BAG4ZSoy.js';
|
|
4
|
+
import { D as DeliveryChannel, L as Logger } from './types-DhgcIImw.js';
|
|
5
5
|
|
|
6
6
|
interface NotifierOptions {
|
|
7
7
|
store: Store;
|
|
@@ -74,4 +74,4 @@ declare function createDispatcher(options: DispatcherOptions): {
|
|
|
74
74
|
notify(input: SendInput): Promise<DispatchResult>;
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
-
export { type DispatchResult as D, type ListOptions as L,
|
|
77
|
+
export { type DispatchResult as D, type ListOptions as L, type Notifier as N, type SendResult as S, type DispatcherOptions as a, type ListResult as b, createDispatcher as c, NotFoundError as d, type NotifierOptions as e, createNotifier as f };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export { D as DispatchResult, a as DispatcherOptions, L as ListOptions, b as ListResult,
|
|
1
|
+
export { D as DispatchResult, a as DispatcherOptions, L as ListOptions, b as ListResult, d as NotFoundError, N as Notifier, e as NotifierOptions, S as SendResult, c as createDispatcher, f as createNotifier } from './dispatch-CH4Ju-_1.js';
|
|
2
2
|
export { Doc, Page, Query, Scalar, Store, StoreOps, createMemoryStore } from 'agentic-identity';
|
|
3
|
-
import { R as Recipient } from './types-
|
|
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-
|
|
5
|
-
import { D as DeliveryChannel } from './types-
|
|
6
|
-
export { a as DeliveryError, L as Logger } from './types-
|
|
7
|
-
export { E as EmailChannelOptions, a as EmailMessage, b as EmailPort, c as createEmailChannel } from './testing-
|
|
3
|
+
import { R as Recipient } from './types-BAG4ZSoy.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-BAG4ZSoy.js';
|
|
5
|
+
import { D as DeliveryChannel } from './types-DhgcIImw.js';
|
|
6
|
+
export { a as DeliveryError, L as Logger } from './types-DhgcIImw.js';
|
|
7
|
+
export { E as EmailChannelOptions, a as EmailMessage, b as EmailPort, c as createEmailChannel } from './testing-DEBqTQFK.js';
|
|
8
8
|
export { D1Like, D1_SCHEMA, createD1Store } from 'agentic-identity/cloudflare';
|
|
9
|
-
export { R as RecipientExport } from './gdpr-
|
|
9
|
+
export { R as RecipientExport } from './gdpr-C3YxbZp-.js';
|
|
10
10
|
import 'zod';
|
|
11
11
|
import 'agentic-identity/testing';
|
|
12
12
|
|
package/dist/index.js
CHANGED
package/dist/mcp-bin.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
VERSION
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-O2W4ELN4.js";
|
|
5
5
|
|
|
6
6
|
// src/mcp-bin.ts
|
|
7
7
|
var HELP = `agentic-notify-mcp ${VERSION}
|
|
8
|
-
Usage: agentic-notify-mcp [--help | --version]
|
|
8
|
+
Usage: agentic-notify-mcp [--help | -h | --version | -V]
|
|
9
9
|
|
|
10
10
|
Runs the MCP server on stdio. An MCP client starts it.
|
|
11
11
|
`;
|
package/dist/mcp.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { Client } from './sdk.js';
|
|
3
|
-
import './types-
|
|
3
|
+
import './types-BAG4ZSoy.js';
|
|
4
4
|
import 'zod';
|
|
5
|
-
import './gdpr-
|
|
5
|
+
import './gdpr-C3YxbZp-.js';
|
|
6
6
|
|
|
7
7
|
/** Without a client, only `ping` works and the other tools report that setup is missing. */
|
|
8
8
|
declare function createMcpServer(client?: Client): McpServer;
|
package/dist/mcp.js
CHANGED
package/dist/sdk.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { N as Notification, D as Digest, P as Preferences, R as Recipient, a as ResourceRef } from './types-
|
|
2
|
-
import { R as RecipientExport } from './gdpr-
|
|
1
|
+
import { N as Notification, D as Digest, P as Preferences, R as Recipient, a as ResourceRef } from './types-BAG4ZSoy.js';
|
|
2
|
+
import { R as RecipientExport } from './gdpr-C3YxbZp-.js';
|
|
3
3
|
import 'zod';
|
|
4
4
|
|
|
5
5
|
declare class ApiError extends Error {
|
|
@@ -43,40 +43,40 @@ declare function createClient(options: ClientOptions): {
|
|
|
43
43
|
cursor?: string;
|
|
44
44
|
}) => Promise<NotificationPage>;
|
|
45
45
|
get: (id: string) => Promise<{
|
|
46
|
-
type: string;
|
|
47
46
|
id: string;
|
|
48
47
|
recipient: {
|
|
49
|
-
id: string;
|
|
50
48
|
kind: "human" | "agent";
|
|
49
|
+
id: string;
|
|
51
50
|
};
|
|
51
|
+
type: string;
|
|
52
52
|
resource: {
|
|
53
|
-
id: string;
|
|
54
53
|
kind: string;
|
|
54
|
+
id: string;
|
|
55
55
|
url?: string | undefined;
|
|
56
56
|
};
|
|
57
57
|
actor: {
|
|
58
|
-
id: string;
|
|
59
58
|
kind: "human" | "agent";
|
|
59
|
+
id: string;
|
|
60
60
|
};
|
|
61
61
|
body: string;
|
|
62
62
|
createdAt: number;
|
|
63
63
|
readAt: number | null;
|
|
64
64
|
}>;
|
|
65
65
|
markRead: (id: string) => Promise<{
|
|
66
|
-
type: string;
|
|
67
66
|
id: string;
|
|
68
67
|
recipient: {
|
|
69
|
-
id: string;
|
|
70
68
|
kind: "human" | "agent";
|
|
69
|
+
id: string;
|
|
71
70
|
};
|
|
71
|
+
type: string;
|
|
72
72
|
resource: {
|
|
73
|
-
id: string;
|
|
74
73
|
kind: string;
|
|
74
|
+
id: string;
|
|
75
75
|
url?: string | undefined;
|
|
76
76
|
};
|
|
77
77
|
actor: {
|
|
78
|
-
id: string;
|
|
79
78
|
kind: "human" | "agent";
|
|
79
|
+
id: string;
|
|
80
80
|
};
|
|
81
81
|
body: string;
|
|
82
82
|
createdAt: number;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import 'agentic-identity/testing';
|
|
2
|
-
import { R as Recipient } from './types-
|
|
3
|
-
import { D as DeliveryChannel } from './types-
|
|
2
|
+
import { R as Recipient } from './types-BAG4ZSoy.js';
|
|
3
|
+
import { D as DeliveryChannel } from './types-DhgcIImw.js';
|
|
4
4
|
|
|
5
5
|
interface EmailMessage {
|
|
6
6
|
to: string;
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { runStoreContract } from 'agentic-identity/testing';
|
|
2
|
-
export { T as TestEmailAdapter } from './testing-
|
|
3
|
-
import './types-
|
|
2
|
+
export { T as TestEmailAdapter } from './testing-DEBqTQFK.js';
|
|
3
|
+
import './types-BAG4ZSoy.js';
|
|
4
4
|
import 'zod';
|
|
5
|
-
import './types-
|
|
5
|
+
import './types-DhgcIImw.js';
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
declare const CHANNELS: readonly ["inbox", "webhook", "email"];
|
|
4
|
+
type Channel = (typeof CHANNELS)[number];
|
|
5
|
+
declare const recipientSchema: z.ZodObject<{
|
|
6
|
+
kind: z.ZodEnum<{
|
|
7
|
+
human: "human";
|
|
8
|
+
agent: "agent";
|
|
9
|
+
}>;
|
|
10
|
+
id: z.ZodString;
|
|
11
|
+
}, z.core.$strict>;
|
|
12
|
+
type Recipient = z.infer<typeof recipientSchema>;
|
|
13
|
+
declare const resourceRefSchema: z.ZodObject<{
|
|
14
|
+
kind: z.ZodString;
|
|
15
|
+
id: z.ZodString;
|
|
16
|
+
url: z.ZodOptional<z.ZodString>;
|
|
17
|
+
}, z.core.$strict>;
|
|
18
|
+
type ResourceRef = z.infer<typeof resourceRefSchema>;
|
|
19
|
+
declare const actorSchema: z.ZodObject<{
|
|
20
|
+
kind: z.ZodEnum<{
|
|
21
|
+
human: "human";
|
|
22
|
+
agent: "agent";
|
|
23
|
+
}>;
|
|
24
|
+
id: z.ZodString;
|
|
25
|
+
}, z.core.$strict>;
|
|
26
|
+
type Actor = z.infer<typeof actorSchema>;
|
|
27
|
+
declare const notificationSchema: z.ZodObject<{
|
|
28
|
+
id: z.ZodString;
|
|
29
|
+
recipient: z.ZodObject<{
|
|
30
|
+
kind: z.ZodEnum<{
|
|
31
|
+
human: "human";
|
|
32
|
+
agent: "agent";
|
|
33
|
+
}>;
|
|
34
|
+
id: z.ZodString;
|
|
35
|
+
}, z.core.$strict>;
|
|
36
|
+
type: z.ZodString;
|
|
37
|
+
resource: z.ZodObject<{
|
|
38
|
+
kind: z.ZodString;
|
|
39
|
+
id: z.ZodString;
|
|
40
|
+
url: z.ZodOptional<z.ZodString>;
|
|
41
|
+
}, z.core.$strict>;
|
|
42
|
+
actor: z.ZodObject<{
|
|
43
|
+
kind: z.ZodEnum<{
|
|
44
|
+
human: "human";
|
|
45
|
+
agent: "agent";
|
|
46
|
+
}>;
|
|
47
|
+
id: z.ZodString;
|
|
48
|
+
}, z.core.$strict>;
|
|
49
|
+
body: z.ZodString;
|
|
50
|
+
createdAt: z.ZodNumber;
|
|
51
|
+
readAt: z.ZodNullable<z.ZodNumber>;
|
|
52
|
+
}, z.core.$strict>;
|
|
53
|
+
type Notification = z.infer<typeof notificationSchema>;
|
|
54
|
+
declare const sendInputSchema: z.ZodObject<{
|
|
55
|
+
recipient: z.ZodObject<{
|
|
56
|
+
kind: z.ZodEnum<{
|
|
57
|
+
human: "human";
|
|
58
|
+
agent: "agent";
|
|
59
|
+
}>;
|
|
60
|
+
id: z.ZodString;
|
|
61
|
+
}, z.core.$strict>;
|
|
62
|
+
type: z.ZodString;
|
|
63
|
+
resource: z.ZodObject<{
|
|
64
|
+
kind: z.ZodString;
|
|
65
|
+
id: z.ZodString;
|
|
66
|
+
url: z.ZodOptional<z.ZodString>;
|
|
67
|
+
}, z.core.$strict>;
|
|
68
|
+
actor: z.ZodObject<{
|
|
69
|
+
kind: z.ZodEnum<{
|
|
70
|
+
human: "human";
|
|
71
|
+
agent: "agent";
|
|
72
|
+
}>;
|
|
73
|
+
id: z.ZodString;
|
|
74
|
+
}, z.core.$strict>;
|
|
75
|
+
body: z.ZodString;
|
|
76
|
+
}, z.core.$strict>;
|
|
77
|
+
type SendInput = z.infer<typeof sendInputSchema>;
|
|
78
|
+
declare const preferencesSchema: z.ZodObject<{
|
|
79
|
+
channels: z.ZodRecord<z.ZodString, z.ZodArray<z.ZodEnum<{
|
|
80
|
+
inbox: "inbox";
|
|
81
|
+
webhook: "webhook";
|
|
82
|
+
email: "email";
|
|
83
|
+
}>>>;
|
|
84
|
+
muted: z.ZodBoolean;
|
|
85
|
+
mutedTypes: z.ZodArray<z.ZodString>;
|
|
86
|
+
}, z.core.$strict>;
|
|
87
|
+
type Preferences = z.infer<typeof preferencesSchema>;
|
|
88
|
+
declare const DEFAULT_CHANNELS: readonly Channel[];
|
|
89
|
+
declare function defaultPreferences(): Preferences;
|
|
90
|
+
declare function recipientKey(recipient: Recipient): string;
|
|
91
|
+
interface DigestGroup {
|
|
92
|
+
type: string;
|
|
93
|
+
count: number;
|
|
94
|
+
latest: Notification;
|
|
95
|
+
}
|
|
96
|
+
interface Digest {
|
|
97
|
+
total: number;
|
|
98
|
+
groups: DigestGroup[];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export { type Actor as A, type Channel as C, type Digest as D, type Notification as N, type Preferences as P, type Recipient as R, type SendInput as S, type ResourceRef as a, CHANNELS as b, DEFAULT_CHANNELS as c, type DigestGroup as d, defaultPreferences as e, recipientKey as r };
|
package/dist/worker.d.ts
CHANGED
|
@@ -1,56 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { R as Recipient } from './types-
|
|
1
|
+
import { Auth, PrincipalContext, Store } from 'agentic-identity';
|
|
2
|
+
import { N as Notifier, c as createDispatcher } from './dispatch-CH4Ju-_1.js';
|
|
3
|
+
import { R as Recipient } from './types-BAG4ZSoy.js';
|
|
4
4
|
import { D1Like } from 'agentic-identity/cloudflare';
|
|
5
|
-
import './gdpr-
|
|
6
|
-
import '
|
|
7
|
-
import '
|
|
8
|
-
|
|
9
|
-
/** Who is calling. `kind` has no default: a missing kind is an error. */
|
|
10
|
-
declare const principalSchema: z.ZodObject<{
|
|
11
|
-
kind: z.ZodEnum<["human", "agent"]>;
|
|
12
|
-
id: z.ZodString;
|
|
13
|
-
/** Allowed to send notifications to others. */
|
|
14
|
-
canSend: z.ZodOptional<z.ZodBoolean>;
|
|
15
|
-
}, "strict", z.ZodTypeAny, {
|
|
16
|
-
kind: "human" | "agent";
|
|
17
|
-
id: string;
|
|
18
|
-
canSend?: boolean | undefined;
|
|
19
|
-
}, {
|
|
20
|
-
kind: "human" | "agent";
|
|
21
|
-
id: string;
|
|
22
|
-
canSend?: boolean | undefined;
|
|
23
|
-
}>;
|
|
24
|
-
type Principal = z.infer<typeof principalSchema>;
|
|
25
|
-
/** Port: turn a request into a principal, or null for "not signed in". Plug in any identity system. */
|
|
26
|
-
type PrincipalResolver = (request: Request) => Promise<Principal | null> | Principal | null;
|
|
5
|
+
import './gdpr-C3YxbZp-.js';
|
|
6
|
+
import './types-DhgcIImw.js';
|
|
7
|
+
import 'zod';
|
|
27
8
|
|
|
28
9
|
interface AppOptions {
|
|
29
10
|
notifier: Notifier;
|
|
30
11
|
/** When set, sends also go to webhook and email channels. */
|
|
31
12
|
dispatcher?: ReturnType<typeof createDispatcher>;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
13
|
+
/** Reads the credential on a request. Each route then checks one scope. */
|
|
14
|
+
auth: Auth;
|
|
15
|
+
/** Extra check on a send, after the `notify-send:write` scope. Default: allow. */
|
|
16
|
+
authorizeSend?: (principal: PrincipalContext, recipient: Recipient) => Promise<boolean> | boolean;
|
|
35
17
|
}
|
|
36
18
|
|
|
37
19
|
interface WorkerEnv {
|
|
38
20
|
NOTIFY_NAME?: string;
|
|
39
21
|
/** D1 binding. */
|
|
40
22
|
DB?: D1Like;
|
|
41
|
-
/** Secret. JSON map of bearer token (32 bytes or more) to principal. */
|
|
42
|
-
NOTIFY_TOKENS?: string;
|
|
43
23
|
/** Data region of the store: "eu", "us" or "unknown". Default "eu". */
|
|
44
24
|
NOTIFY_REGION?: string;
|
|
45
25
|
/** Retention window in days. Unset keeps notifications. */
|
|
46
26
|
NOTIFY_RETENTION_DAYS?: string;
|
|
47
27
|
}
|
|
48
28
|
interface WorkerConfig {
|
|
49
|
-
/**
|
|
50
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Build the `Auth` port. Default: `createStoreAuth` over the same store, so keys that
|
|
31
|
+
* agentic-identity issues into the database work here. Each route checks a scope.
|
|
32
|
+
*/
|
|
33
|
+
auth?(env: WorkerEnv, store: Store): Auth;
|
|
51
34
|
authorizeSend?: AppOptions["authorizeSend"];
|
|
52
35
|
}
|
|
53
|
-
/** Compose the Worker. Bring your own identity system through `
|
|
36
|
+
/** Compose the Worker. Bring your own identity system through `auth`. */
|
|
54
37
|
declare function createWorker(config: WorkerConfig): {
|
|
55
38
|
fetch(request: Request, env: WorkerEnv): Promise<Response>;
|
|
56
39
|
/** Delete notifications past the retention window. Wire to a cron trigger. */
|
package/dist/worker.js
CHANGED
|
@@ -9,76 +9,81 @@ import {
|
|
|
9
9
|
} from "./chunk-ARL7FN6Y.js";
|
|
10
10
|
import {
|
|
11
11
|
VERSION
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-O2W4ELN4.js";
|
|
13
13
|
|
|
14
14
|
// src/api.ts
|
|
15
15
|
import { Hono } from "hono";
|
|
16
16
|
import { bodyLimit } from "hono/body-limit";
|
|
17
|
-
import { ZodError, z
|
|
17
|
+
import { ZodError, z } from "zod";
|
|
18
|
+
import { requirePrincipal } from "agentic-identity/http";
|
|
18
19
|
|
|
19
20
|
// src/auth.ts
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
21
|
+
var SCOPES = {
|
|
22
|
+
/** List, read, count, digest, read preferences, export. */
|
|
23
|
+
read: "notify:read",
|
|
24
|
+
/** Mark read, change preferences. */
|
|
25
|
+
write: "notify:write",
|
|
26
|
+
/** Erase all data held about the caller. */
|
|
27
|
+
erase: "notify:admin",
|
|
28
|
+
/** Notify someone else. */
|
|
29
|
+
send: "notify-send:write"
|
|
30
|
+
};
|
|
31
|
+
function recipientOf(context) {
|
|
32
|
+
switch (context.kind) {
|
|
33
|
+
case "human":
|
|
34
|
+
return { kind: "human", id: context.principalId };
|
|
35
|
+
case "user_token": {
|
|
36
|
+
const root = context.chain[0];
|
|
37
|
+
if (!root || root.kind !== "human") throw new RangeError("a user token needs a person at the root of its chain");
|
|
38
|
+
return { kind: "human", id: root.id };
|
|
39
|
+
}
|
|
40
|
+
case "agent":
|
|
41
|
+
case "agent_of_human":
|
|
42
|
+
case "agent_of_agent":
|
|
43
|
+
return { kind: "agent", id: context.principalId };
|
|
44
|
+
default:
|
|
45
|
+
throw new RangeError("unknown principal kind");
|
|
38
46
|
}
|
|
39
|
-
if (byDigest.size === 0) throw new Error("no tokens configured");
|
|
40
|
-
return async (request) => {
|
|
41
|
-
const m = /^Bearer ([^\s]+)$/.exec(request.headers.get("authorization") ?? "");
|
|
42
|
-
return m ? byDigest.get(await digest(m[1])) ?? null : null;
|
|
43
|
-
};
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
// src/api.ts
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
function invalidInput(path, message) {
|
|
51
|
+
return z.string().refine(() => false, { message, path }).safeParse("").error;
|
|
52
|
+
}
|
|
53
|
+
var sendBody = z.object({ recipient: recipientSchema, type: typeNameSchema, resource: resourceRefSchema, body: z.string().max(2e3) }).strict();
|
|
54
|
+
var num = z.coerce.number().int().nonnegative();
|
|
49
55
|
function createApp(options) {
|
|
50
56
|
const { notifier } = options;
|
|
51
|
-
const authorizeSend = options.authorizeSend ?? ((
|
|
57
|
+
const authorizeSend = options.authorizeSend ?? (() => true);
|
|
52
58
|
const app = new Hono();
|
|
53
59
|
app.get("/health", (c) => c.json({ ok: true }));
|
|
54
60
|
const api = new Hono();
|
|
55
61
|
api.use("*", bodyLimit({ maxSize: 64 * 1024, onError: (c) => c.json({ error: "too_large" }, 413) }));
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
c.set("
|
|
61
|
-
c.set("me", { kind: parsed.data.kind, id: parsed.data.id });
|
|
62
|
+
const guard = (scope) => async (c, next) => {
|
|
63
|
+
const who = await requirePrincipal(c.req.raw, options.auth, { scope });
|
|
64
|
+
if (who instanceof Response) return who;
|
|
65
|
+
c.set("principal", who);
|
|
66
|
+
c.set("me", recipientOf(who));
|
|
62
67
|
await next();
|
|
63
|
-
}
|
|
68
|
+
};
|
|
64
69
|
async function json2(c) {
|
|
65
70
|
try {
|
|
66
71
|
return await c.req.json();
|
|
67
72
|
} catch {
|
|
68
|
-
throw
|
|
73
|
+
throw invalidInput([], "body must be JSON");
|
|
69
74
|
}
|
|
70
75
|
}
|
|
71
|
-
api.get("/notifications", async (c) => {
|
|
76
|
+
api.get("/notifications", guard(SCOPES.read), async (c) => {
|
|
72
77
|
const q = c.req.query();
|
|
73
|
-
const limit = q.limit === void 0 ? void 0 :
|
|
78
|
+
const limit = q.limit === void 0 ? void 0 : z.coerce.number().int().min(1).parse(q.limit);
|
|
74
79
|
try {
|
|
75
80
|
return c.json(await notifier.list(c.var.me, { unreadOnly: q.unread === "1" || q.unread === "true", limit, cursor: q.cursor }));
|
|
76
81
|
} catch (error) {
|
|
77
|
-
if (error instanceof RangeError) throw
|
|
82
|
+
if (error instanceof RangeError) throw invalidInput(["cursor"], "bad cursor");
|
|
78
83
|
throw error;
|
|
79
84
|
}
|
|
80
85
|
});
|
|
81
|
-
api.post("/notifications", async (c) => {
|
|
86
|
+
api.post("/notifications", guard(SCOPES.send), async (c) => {
|
|
82
87
|
const input = sendBody.parse(await json2(c));
|
|
83
88
|
if (!await authorizeSend(c.var.principal, input.recipient)) return c.json({ error: "forbidden" }, 403);
|
|
84
89
|
const full = { ...input, actor: c.var.me };
|
|
@@ -87,18 +92,22 @@ function createApp(options) {
|
|
|
87
92
|
const deliveries = sent.channels.filter((channel) => channel !== "inbox").map((channel) => ({ channel, ok: false, skipped: "no_channel" }));
|
|
88
93
|
return c.json({ ...sent, deliveries }, 201);
|
|
89
94
|
});
|
|
90
|
-
api.post("/notifications/read-all", async (c) => c.json({ marked: await notifier.markAllRead(c.var.me) }));
|
|
91
|
-
api.get("/notifications/:id", async (c) => c.json(await notifier.get(c.var.me, c.req.param("id"))));
|
|
92
|
-
api.post("/notifications/:id/read", async (c) => c.json(await notifier.markRead(c.var.me, c.req.param("id"))));
|
|
93
|
-
api.get("/unread-count", async (c) => c.json({ count: await notifier.unreadCount(c.var.me) }));
|
|
94
|
-
api.get("/digest", async (c) => {
|
|
95
|
+
api.post("/notifications/read-all", guard(SCOPES.write), async (c) => c.json({ marked: await notifier.markAllRead(c.var.me) }));
|
|
96
|
+
api.get("/notifications/:id", guard(SCOPES.read), async (c) => c.json(await notifier.get(c.var.me, c.req.param("id"))));
|
|
97
|
+
api.post("/notifications/:id/read", guard(SCOPES.write), async (c) => c.json(await notifier.markRead(c.var.me, c.req.param("id"))));
|
|
98
|
+
api.get("/unread-count", guard(SCOPES.read), async (c) => c.json({ count: await notifier.unreadCount(c.var.me) }));
|
|
99
|
+
api.get("/digest", guard(SCOPES.read), async (c) => {
|
|
95
100
|
const since = c.req.query("since");
|
|
96
101
|
return c.json(await notifier.digest(c.var.me, since === void 0 ? 0 : num.parse(since)));
|
|
97
102
|
});
|
|
98
|
-
api.get("/preferences", async (c) => c.json(await notifier.getPreferences(c.var.me)));
|
|
99
|
-
api.put("/preferences", async (c) => c.json(await notifier.setPreferences(c.var.me, preferencesSchema.parse(await json2(c)))));
|
|
100
|
-
api.get("/me/export", async (c) => c.json(await notifier.exportData(c.var.me)));
|
|
101
|
-
api.delete("/me", async (c) => c.json(await notifier.erase(c.var.me)));
|
|
103
|
+
api.get("/preferences", guard(SCOPES.read), async (c) => c.json(await notifier.getPreferences(c.var.me)));
|
|
104
|
+
api.put("/preferences", guard(SCOPES.write), async (c) => c.json(await notifier.setPreferences(c.var.me, preferencesSchema.parse(await json2(c)))));
|
|
105
|
+
api.get("/me/export", guard(SCOPES.read), async (c) => c.json(await notifier.exportData(c.var.me)));
|
|
106
|
+
api.delete("/me", guard(SCOPES.erase), async (c) => c.json(await notifier.erase(c.var.me)));
|
|
107
|
+
api.all("*", async (c) => {
|
|
108
|
+
const who = await requirePrincipal(c.req.raw, options.auth);
|
|
109
|
+
return who instanceof Response ? who : c.json({ error: "not_found" }, 404);
|
|
110
|
+
});
|
|
102
111
|
app.route("/api/v1", api);
|
|
103
112
|
app.notFound((c) => c.json({ error: "not_found" }, 404));
|
|
104
113
|
app.onError((error, c) => {
|
|
@@ -113,7 +122,7 @@ function createApp(options) {
|
|
|
113
122
|
}
|
|
114
123
|
|
|
115
124
|
// src/worker.ts
|
|
116
|
-
import { parseRegion } from "agentic-identity";
|
|
125
|
+
import { createStoreAuth, parseRegion } from "agentic-identity";
|
|
117
126
|
import { createD1Store, D1_SCHEMA } from "agentic-identity/cloudflare";
|
|
118
127
|
function json(value, status = 200) {
|
|
119
128
|
return new Response(JSON.stringify(value), { status, headers: { "content-type": "application/json" } });
|
|
@@ -132,16 +141,17 @@ function createWorker(config) {
|
|
|
132
141
|
const days = env.NOTIFY_RETENTION_DAYS === void 0 ? void 0 : Number(env.NOTIFY_RETENTION_DAYS);
|
|
133
142
|
const store = createD1Store(env.DB, { region: parseRegion(env.NOTIFY_REGION ?? "eu") });
|
|
134
143
|
await store.query(NOTES, { limit: 1 });
|
|
135
|
-
|
|
144
|
+
const notifier = createNotifier({
|
|
136
145
|
store,
|
|
137
146
|
retentionMs: days === void 0 ? void 0 : days * 864e5
|
|
138
147
|
});
|
|
148
|
+
return { notifier, store };
|
|
139
149
|
}
|
|
140
150
|
async function build(env) {
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return createApp({ notifier,
|
|
151
|
+
const built = await buildNotifier(env);
|
|
152
|
+
if (!built) return null;
|
|
153
|
+
const auth = config.auth ? config.auth(env, built.store) : createStoreAuth(built.store);
|
|
154
|
+
return createApp({ notifier: built.notifier, auth, authorizeSend: config.authorizeSend });
|
|
145
155
|
}
|
|
146
156
|
return {
|
|
147
157
|
async fetch(request, env) {
|
|
@@ -164,16 +174,11 @@ function createWorker(config) {
|
|
|
164
174
|
},
|
|
165
175
|
/** Delete notifications past the retention window. Wire to a cron trigger. */
|
|
166
176
|
async scheduled(_event, env) {
|
|
167
|
-
await (await buildNotifier(env))?.sweep();
|
|
177
|
+
await (await buildNotifier(env))?.notifier.sweep();
|
|
168
178
|
}
|
|
169
179
|
};
|
|
170
180
|
}
|
|
171
|
-
var worker_default = createWorker({
|
|
172
|
-
async resolver(env) {
|
|
173
|
-
if (!env.NOTIFY_TOKENS) return null;
|
|
174
|
-
return createStaticTokenResolver(JSON.parse(env.NOTIFY_TOKENS));
|
|
175
|
-
}
|
|
176
|
-
});
|
|
181
|
+
var worker_default = createWorker({});
|
|
177
182
|
export {
|
|
178
183
|
createWorker,
|
|
179
184
|
worker_default as default
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-notify",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.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",
|
|
@@ -65,10 +65,10 @@
|
|
|
65
65
|
"check:worker": "esbuild src/worker.ts --bundle --platform=neutral --format=esm --log-level=warning --outfile=node_modules/.cache/worker-check.js"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
69
|
-
"agentic-identity": "^0.
|
|
68
|
+
"@modelcontextprotocol/sdk": "^1.23.0",
|
|
69
|
+
"agentic-identity": "^0.7.0",
|
|
70
70
|
"hono": "^4.13.14",
|
|
71
|
-
"zod": "^
|
|
71
|
+
"zod": "^4.6.7"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@types/node": "^22.0.0",
|
package/dist/types-C842YAMe.d.ts
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
declare const CHANNELS: readonly ["inbox", "webhook", "email"];
|
|
4
|
-
type Channel = (typeof CHANNELS)[number];
|
|
5
|
-
declare const recipientSchema: z.ZodObject<{
|
|
6
|
-
kind: z.ZodEnum<["human", "agent"]>;
|
|
7
|
-
id: z.ZodString;
|
|
8
|
-
}, "strict", z.ZodTypeAny, {
|
|
9
|
-
id: string;
|
|
10
|
-
kind: "human" | "agent";
|
|
11
|
-
}, {
|
|
12
|
-
id: string;
|
|
13
|
-
kind: "human" | "agent";
|
|
14
|
-
}>;
|
|
15
|
-
type Recipient = z.infer<typeof recipientSchema>;
|
|
16
|
-
declare const resourceRefSchema: z.ZodObject<{
|
|
17
|
-
kind: z.ZodString;
|
|
18
|
-
id: z.ZodString;
|
|
19
|
-
url: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
20
|
-
}, "strict", z.ZodTypeAny, {
|
|
21
|
-
id: string;
|
|
22
|
-
kind: string;
|
|
23
|
-
url?: string | undefined;
|
|
24
|
-
}, {
|
|
25
|
-
id: string;
|
|
26
|
-
kind: string;
|
|
27
|
-
url?: string | undefined;
|
|
28
|
-
}>;
|
|
29
|
-
type ResourceRef = z.infer<typeof resourceRefSchema>;
|
|
30
|
-
declare const actorSchema: z.ZodObject<{
|
|
31
|
-
kind: z.ZodEnum<["human", "agent"]>;
|
|
32
|
-
id: z.ZodString;
|
|
33
|
-
}, "strict", z.ZodTypeAny, {
|
|
34
|
-
id: string;
|
|
35
|
-
kind: "human" | "agent";
|
|
36
|
-
}, {
|
|
37
|
-
id: string;
|
|
38
|
-
kind: "human" | "agent";
|
|
39
|
-
}>;
|
|
40
|
-
type Actor = z.infer<typeof actorSchema>;
|
|
41
|
-
declare const notificationSchema: z.ZodObject<{
|
|
42
|
-
id: z.ZodString;
|
|
43
|
-
recipient: z.ZodObject<{
|
|
44
|
-
kind: z.ZodEnum<["human", "agent"]>;
|
|
45
|
-
id: z.ZodString;
|
|
46
|
-
}, "strict", z.ZodTypeAny, {
|
|
47
|
-
id: string;
|
|
48
|
-
kind: "human" | "agent";
|
|
49
|
-
}, {
|
|
50
|
-
id: string;
|
|
51
|
-
kind: "human" | "agent";
|
|
52
|
-
}>;
|
|
53
|
-
type: z.ZodString;
|
|
54
|
-
resource: z.ZodObject<{
|
|
55
|
-
kind: z.ZodString;
|
|
56
|
-
id: z.ZodString;
|
|
57
|
-
url: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
58
|
-
}, "strict", z.ZodTypeAny, {
|
|
59
|
-
id: string;
|
|
60
|
-
kind: string;
|
|
61
|
-
url?: string | undefined;
|
|
62
|
-
}, {
|
|
63
|
-
id: string;
|
|
64
|
-
kind: string;
|
|
65
|
-
url?: string | undefined;
|
|
66
|
-
}>;
|
|
67
|
-
actor: z.ZodObject<{
|
|
68
|
-
kind: z.ZodEnum<["human", "agent"]>;
|
|
69
|
-
id: z.ZodString;
|
|
70
|
-
}, "strict", z.ZodTypeAny, {
|
|
71
|
-
id: string;
|
|
72
|
-
kind: "human" | "agent";
|
|
73
|
-
}, {
|
|
74
|
-
id: string;
|
|
75
|
-
kind: "human" | "agent";
|
|
76
|
-
}>;
|
|
77
|
-
body: z.ZodString;
|
|
78
|
-
createdAt: z.ZodNumber;
|
|
79
|
-
readAt: z.ZodNullable<z.ZodNumber>;
|
|
80
|
-
}, "strict", z.ZodTypeAny, {
|
|
81
|
-
type: string;
|
|
82
|
-
id: string;
|
|
83
|
-
recipient: {
|
|
84
|
-
id: string;
|
|
85
|
-
kind: "human" | "agent";
|
|
86
|
-
};
|
|
87
|
-
resource: {
|
|
88
|
-
id: string;
|
|
89
|
-
kind: string;
|
|
90
|
-
url?: string | undefined;
|
|
91
|
-
};
|
|
92
|
-
actor: {
|
|
93
|
-
id: string;
|
|
94
|
-
kind: "human" | "agent";
|
|
95
|
-
};
|
|
96
|
-
body: string;
|
|
97
|
-
createdAt: number;
|
|
98
|
-
readAt: number | null;
|
|
99
|
-
}, {
|
|
100
|
-
type: string;
|
|
101
|
-
id: string;
|
|
102
|
-
recipient: {
|
|
103
|
-
id: string;
|
|
104
|
-
kind: "human" | "agent";
|
|
105
|
-
};
|
|
106
|
-
resource: {
|
|
107
|
-
id: string;
|
|
108
|
-
kind: string;
|
|
109
|
-
url?: string | undefined;
|
|
110
|
-
};
|
|
111
|
-
actor: {
|
|
112
|
-
id: string;
|
|
113
|
-
kind: "human" | "agent";
|
|
114
|
-
};
|
|
115
|
-
body: string;
|
|
116
|
-
createdAt: number;
|
|
117
|
-
readAt: number | null;
|
|
118
|
-
}>;
|
|
119
|
-
type Notification = z.infer<typeof notificationSchema>;
|
|
120
|
-
declare const sendInputSchema: z.ZodObject<{
|
|
121
|
-
recipient: z.ZodObject<{
|
|
122
|
-
kind: z.ZodEnum<["human", "agent"]>;
|
|
123
|
-
id: z.ZodString;
|
|
124
|
-
}, "strict", z.ZodTypeAny, {
|
|
125
|
-
id: string;
|
|
126
|
-
kind: "human" | "agent";
|
|
127
|
-
}, {
|
|
128
|
-
id: string;
|
|
129
|
-
kind: "human" | "agent";
|
|
130
|
-
}>;
|
|
131
|
-
type: z.ZodString;
|
|
132
|
-
resource: z.ZodObject<{
|
|
133
|
-
kind: z.ZodString;
|
|
134
|
-
id: z.ZodString;
|
|
135
|
-
url: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
136
|
-
}, "strict", z.ZodTypeAny, {
|
|
137
|
-
id: string;
|
|
138
|
-
kind: string;
|
|
139
|
-
url?: string | undefined;
|
|
140
|
-
}, {
|
|
141
|
-
id: string;
|
|
142
|
-
kind: string;
|
|
143
|
-
url?: string | undefined;
|
|
144
|
-
}>;
|
|
145
|
-
actor: z.ZodObject<{
|
|
146
|
-
kind: z.ZodEnum<["human", "agent"]>;
|
|
147
|
-
id: z.ZodString;
|
|
148
|
-
}, "strict", z.ZodTypeAny, {
|
|
149
|
-
id: string;
|
|
150
|
-
kind: "human" | "agent";
|
|
151
|
-
}, {
|
|
152
|
-
id: string;
|
|
153
|
-
kind: "human" | "agent";
|
|
154
|
-
}>;
|
|
155
|
-
body: z.ZodString;
|
|
156
|
-
}, "strict", z.ZodTypeAny, {
|
|
157
|
-
type: string;
|
|
158
|
-
recipient: {
|
|
159
|
-
id: string;
|
|
160
|
-
kind: "human" | "agent";
|
|
161
|
-
};
|
|
162
|
-
resource: {
|
|
163
|
-
id: string;
|
|
164
|
-
kind: string;
|
|
165
|
-
url?: string | undefined;
|
|
166
|
-
};
|
|
167
|
-
actor: {
|
|
168
|
-
id: string;
|
|
169
|
-
kind: "human" | "agent";
|
|
170
|
-
};
|
|
171
|
-
body: string;
|
|
172
|
-
}, {
|
|
173
|
-
type: string;
|
|
174
|
-
recipient: {
|
|
175
|
-
id: string;
|
|
176
|
-
kind: "human" | "agent";
|
|
177
|
-
};
|
|
178
|
-
resource: {
|
|
179
|
-
id: string;
|
|
180
|
-
kind: string;
|
|
181
|
-
url?: string | undefined;
|
|
182
|
-
};
|
|
183
|
-
actor: {
|
|
184
|
-
id: string;
|
|
185
|
-
kind: "human" | "agent";
|
|
186
|
-
};
|
|
187
|
-
body: string;
|
|
188
|
-
}>;
|
|
189
|
-
type SendInput = z.infer<typeof sendInputSchema>;
|
|
190
|
-
declare const preferencesSchema: z.ZodObject<{
|
|
191
|
-
channels: z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodArray<z.ZodEnum<["inbox", "webhook", "email"]>, "many">, ("inbox" | "webhook" | "email")[], ("inbox" | "webhook" | "email")[]>>;
|
|
192
|
-
muted: z.ZodBoolean;
|
|
193
|
-
mutedTypes: z.ZodArray<z.ZodString, "many">;
|
|
194
|
-
}, "strict", z.ZodTypeAny, {
|
|
195
|
-
channels: Record<string, ("inbox" | "webhook" | "email")[]>;
|
|
196
|
-
muted: boolean;
|
|
197
|
-
mutedTypes: string[];
|
|
198
|
-
}, {
|
|
199
|
-
channels: Record<string, ("inbox" | "webhook" | "email")[]>;
|
|
200
|
-
muted: boolean;
|
|
201
|
-
mutedTypes: string[];
|
|
202
|
-
}>;
|
|
203
|
-
type Preferences = z.infer<typeof preferencesSchema>;
|
|
204
|
-
declare const DEFAULT_CHANNELS: readonly Channel[];
|
|
205
|
-
declare function defaultPreferences(): Preferences;
|
|
206
|
-
declare function recipientKey(recipient: Recipient): string;
|
|
207
|
-
interface DigestGroup {
|
|
208
|
-
type: string;
|
|
209
|
-
count: number;
|
|
210
|
-
latest: Notification;
|
|
211
|
-
}
|
|
212
|
-
interface Digest {
|
|
213
|
-
total: number;
|
|
214
|
-
groups: DigestGroup[];
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
export { type Actor as A, type Channel as C, type Digest as D, type Notification as N, type Preferences as P, type Recipient as R, type SendInput as S, type ResourceRef as a, CHANNELS as b, DEFAULT_CHANNELS as c, type DigestGroup as d, defaultPreferences as e, recipientKey as r };
|