@nacre.work/core 0.33.0 → 0.35.0

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/index.js CHANGED
@@ -1,11 +1,12 @@
1
1
  export * from './types.js';
2
2
  export * from './authz/index.js';
3
3
  export { parseFilters, parseMetadata, MetadataError, MAX_METADATA_KEYS, MAX_METADATA_KEY_LENGTH, MAX_METADATA_LIST, MAX_METADATA_VALUE_LENGTH, } from './metadata.js';
4
- export { loadConfig, loadJwtKeys, loadJwtVerification, loadMailConfig, loadSecondFactorKey, keyFingerprint, ConfigError } from './config.js';
4
+ export { loadConfig, loadJwtKeys, loadJwtVerification, loadMailConfig, mailConfigured, loadSecondFactorKey, keyFingerprint, ConfigError } from './config.js';
5
5
  export { ADMIN_MCP_PATH, ADMIN_PROTECTED_RESOURCE_PATH, adminAudience, adminResourceMetadata, JWKS_PATH, namesAdminResource, protectedResourceMetadata, PROTECTED_RESOURCE_PATH, } from './oauth.js';
6
+ export { packageVersion } from './version.js';
6
7
  export { allowedRequestHeaders, corsHeaders, isPreflight, mcpWalkHeaders, preflightHeaders } from './cors.js';
7
8
  export { AUTHORIZATION_SERVER_PATH, AUTHORIZE_PATH, CODE_TTL_MS, REGISTER_PATH, TOKEN_PATH, authorizationServerMetadata, consentRedirect, generateClientId, generateCode, hashCode, redirectAllowed, verifierMatches, } from './authserver.js';
8
- export { activeResolver, admitIngest, admitSignIn, ADMIN_PREFIX, adminRoutes, auditSinks, authProviders, loadModules, loadedExtensions, mountAdminRoutes, registerAuditSink, registerAuthProvider, registerAuthzResolver, registerIngestGate, registerSignInGate, resetExtensionsForTests, withAuditSinks, withLoadingModuleForTests, } from './extensions.js';
9
+ export { activeResolver, admitIngest, admitSignIn, ADMIN_PREFIX, adminRoutes, auditSinks, authProviders, loadModules, loadedExtensions, mcpTools, McpToolRefusal, mountAdminRoutes, registerAuditSink, registerAuthProvider, registerAuthzResolver, registerIngestGate, registerMcpTools, registerSignInGate, resetExtensionsForTests, withAuditSinks, withLoadingModuleForTests, } from './extensions.js';
9
10
  export { acrossOrganizations, createPool, whileAuthenticating, withOrg } from './db/client.js';
10
11
  export { migrate, loadMigrations, migrationNames, pendingMigrations } from './db/migrate.js';
11
12
  export { looksLikeEmail, organizationSlugError, provisionInPostgres, provisionOrganization } from './provision.js';
@@ -35,4 +36,5 @@ export { Redis, RedisError } from './redis.js';
35
36
  export { reindexProgress, toStateJson, toCheckJson, fromStateJson } from './reindex.js';
36
37
  export { generatePassword, hashingLoad, hashPassword, needsRehash, PASSWORD_ENTROPY_BITS, PASSWORD_WORD_COUNT, PASSWORD_WORDS, spendVerificationTime, TooBusy, verifyPassword, } from './passwords.js';
37
38
  export { installGuards, onListenError } from './lifecycle.js';
39
+ export { ALERT_KINDS, ALERT_WINDOW, isAlertKind, NOTIFY_BODY_MAX, NOTIFY_MAX_RECIPIENTS, NOTIFY_PER_HOUR, NOTIFY_SUBJECT_MAX, notificationMessage, notificationText, plainName, ruleSentence, } from './notifications.js';
38
40
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"mail.d.ts","sourceRoot":"","sources":["../mail.ts"],"names":[],"mappings":"AAqIA;;;;;;;GAOG;AACH,MAAM,MAAM,KAAK,GACb;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAEvD;;;;;;;GAOG;AACH,OAAO,CAAC,MAAM,QAAQ,EAAE,OAAO,MAAM,CAAA;AAErC,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAA;CAC1B;AAsJD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,KAAK,EAAE,GAAG,OAAO,CAOpF;AAED;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACtC;AAED,MAAM,WAAW,UAAU;IACzB,wEAAwE;IACxE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,KAAG,MACoB,CAAA;AAwB5E;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAoB/E"}
1
+ {"version":3,"file":"mail.d.ts","sourceRoot":"","sources":["../mail.ts"],"names":[],"mappings":"AAqIA;;;;;;;GAOG;AACH,MAAM,MAAM,KAAK,GACb;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAEvD;;;;;;;GAOG;AACH,OAAO,CAAC,MAAM,QAAQ,EAAE,OAAO,MAAM,CAAA;AAErC,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAA;CAC1B;AAiKD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,KAAK,EAAE,GAAG,OAAO,CAOpF;AAED;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACtC;AAED,MAAM,WAAW,UAAU;IACzB,wEAAwE;IACxE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,KAAG,MACoB,CAAA;AAwB5E;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAoB/E"}
package/dist/mail.js CHANGED
@@ -167,11 +167,20 @@ function wrap(text, width = 72) {
167
167
  lines.push(line);
168
168
  return lines.join('\n');
169
169
  }
170
+ /**
171
+ * A line break inside a paragraph is kept, in both parts. The messages written
172
+ * here have none; a notification's body is somebody's prose, and a list of
173
+ * five layers run together into one line reads as a sentence that lost its
174
+ * punctuation.
175
+ */
176
+ const linesOf = (text) => text.split('\n');
170
177
  function renderText(body) {
171
178
  return body
172
- .map((block) => (block.kind === 'link' ? block.url : wrap(block.text)))
179
+ .map((block) => (block.kind === 'link' ? block.url : linesOf(block.text).map((line) => wrap(line)).join('\n')))
173
180
  .join('\n\n');
174
181
  }
182
+ /** Escaped, with each kept line break as a `<br>`. */
183
+ const paragraph = (text) => linesOf(text).map(escape).join('<br>');
175
184
  /**
176
185
  * The same blocks as a message a client will render.
177
186
  *
@@ -209,7 +218,7 @@ function renderHtml(subject, body) {
209
218
  // preheader they show the wordmark — which tells a reader nothing at the one
210
219
  // moment they are deciding whether this message is real.
211
220
  const first = body.find((block) => block.kind === 'say');
212
- const preheader = first === undefined ? '' : escape(first.text);
221
+ const preheader = first === undefined ? '' : escape(first.text.replace(/\s+/gu, ' '));
213
222
  const blocks = body.map((block) => {
214
223
  if (block.kind === 'link') {
215
224
  const url = escape(checkedUrl(block.url));
@@ -228,13 +237,13 @@ function renderHtml(subject, body) {
228
237
  <table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%">
229
238
  <tr>
230
239
  <td width="3" style="background:${PALETTE.caution};width:3px;font-size:0;line-height:0">&nbsp;</td>
231
- <td style="padding-left:12px;font-family:${FONTS.body};font-size:14px;line-height:1.55;color:${PALETTE.text}">${escape(block.text)}</td>
240
+ <td style="padding-left:12px;font-family:${FONTS.body};font-size:14px;line-height:1.55;color:${PALETTE.text}">${paragraph(block.text)}</td>
232
241
  </tr>
233
242
  </table>
234
243
  </td></tr>`;
235
244
  }
236
245
  return `
237
- <tr><td style="padding:0 0 16px;font-family:${FONTS.body};font-size:15.5px;line-height:1.55;color:${PALETTE.text}">${escape(block.text)}</td></tr>`;
246
+ <tr><td style="padding:0 0 16px;font-family:${FONTS.body};font-size:15.5px;line-height:1.55;color:${PALETTE.text}">${paragraph(block.text)}</td></tr>`;
238
247
  });
239
248
  return `<!doctype html>
240
249
  <html lang="en">
package/dist/mail.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mail.js","sourceRoot":"","sources":["../mail.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mail.js","sourceRoot":"","sources":["../mail.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ -- 0039 — a change on the administrative MCP is proposed, and a person applies it.
2
+ --
3
+ -- docs/mcp-admin.md, "A change is proposed, and a person applies it". A write
4
+ -- tool on `/mcp/admin` does not write: it stores what it would do here and
5
+ -- answers with that, and the change happens only when the person presses
6
+ -- Apply — in the panel the host renders beside the tool's result, or on the
7
+ -- console's Proposals screen, under the person's own session. A model can get a
8
+ -- change as far as a person's screen and no further, which is what makes an
9
+ -- instruction planted in somebody's document cost a refusal rather than a grant.
10
+ --
11
+ -- A table rather than a signed blob handed back to the client, because three
12
+ -- properties are the database's: single use (the UPDATE that claims a row is
13
+ -- the only way to apply it), expiry (ten minutes, compared by the database
14
+ -- clock), and a record of the ones nobody applied — a stream of proposals that
15
+ -- expired is what an injection attempt looks like from the outside, and a blob
16
+ -- the client threw away leaves nothing to count.
17
+
18
+ -- The connection a proposal is bound to, by a composite key so the database
19
+ -- refuses one naming another organization's connection rather than the code
20
+ -- that writes the insert. `oauth_consents` had no such key until now.
21
+ ALTER TABLE oauth_consents ADD CONSTRAINT oauth_consents_id_org_key UNIQUE (id, org_id);
22
+
23
+ CREATE TABLE admin_proposals (
24
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
25
+ org_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
26
+
27
+ -- The administrative connection that proposed it. Only that connection's
28
+ -- panel may apply it, and revoking the connection ends what it proposed.
29
+ consent_id uuid NOT NULL,
30
+ -- The person the connection acts for: the one whose console may apply it.
31
+ proposed_by uuid NOT NULL,
32
+
33
+ -- Which tool, and which module registered it — NULL for the core's own.
34
+ -- Applying looks the tool up by name again, so a module unloaded since
35
+ -- leaves a proposal nothing can apply rather than one applied by guesswork.
36
+ tool text NOT NULL CHECK (tool ~ '^[a-z][a-z0-9_]{0,63}$'),
37
+ module text,
38
+
39
+ -- What the person reads before pressing Apply: one sentence, and the facts
40
+ -- under it. Written by the tool from resolved names, never by the model.
41
+ summary text NOT NULL CHECK (length(summary) BETWEEN 1 AND 1000),
42
+ details jsonb NOT NULL DEFAULT '[]'::jsonb CHECK (jsonb_typeof(details) = 'array'),
43
+ -- What `apply` receives: ids, not names, resolved when it was proposed.
44
+ input jsonb NOT NULL CHECK (jsonb_typeof(input) = 'object'),
45
+
46
+ -- The hash of a key handed to the change panel in the result's `_meta`,
47
+ -- and nowhere else: not the text the model reads, not the access log. The
48
+ -- panel's Apply presents it; the console authenticates by session instead.
49
+ -- The id alone is not enough because the id is in the access log, and the
50
+ -- administrative surface reads the access log — so without this a model
51
+ -- could look its own proposal up with `query_audit` and apply it, in any
52
+ -- host that offered it the panel's tools.
53
+ panel_key_hash bytea NOT NULL CHECK (octet_length(panel_key_hash) = 32),
54
+
55
+ status text NOT NULL DEFAULT 'open'
56
+ CHECK (status IN ('open', 'applying', 'applied', 'failed', 'cancelled', 'expired')),
57
+ created_at timestamptz NOT NULL DEFAULT now(),
58
+ expires_at timestamptz NOT NULL,
59
+ decided_at timestamptz,
60
+ -- Where the person decided: the panel beside the conversation, or the
61
+ -- console. Both are the person; the column says which screen.
62
+ decided_through text CHECK (decided_through IN ('panel', 'console')),
63
+ -- Why an applied proposal did not take, in the words the tool refused with.
64
+ error text CHECK (length(error) <= 1000),
65
+
66
+ CHECK (expires_at > created_at),
67
+ FOREIGN KEY (consent_id, org_id) REFERENCES oauth_consents (id, org_id) ON DELETE CASCADE,
68
+ FOREIGN KEY (proposed_by, org_id) REFERENCES users (id, org_id) ON DELETE CASCADE
69
+ );
70
+
71
+ -- The console's question: what is waiting for me.
72
+ CREATE INDEX admin_proposals_pending_idx ON admin_proposals (org_id, proposed_by, created_at DESC) WHERE status = 'open';
73
+ -- The worker's question: what has run out, across every organization.
74
+ CREATE INDEX admin_proposals_expiry_idx ON admin_proposals (expires_at) WHERE status IN ('open', 'applying');
75
+
76
+ ALTER TABLE admin_proposals ENABLE ROW LEVEL SECURITY;
77
+ ALTER TABLE admin_proposals FORCE ROW LEVEL SECURITY;
78
+ CREATE POLICY org_isolation ON admin_proposals
79
+ USING (org_id = current_setting('app.current_org')::uuid);
80
+
81
+ -- No DELETE for either role. A proposal is a record of what an agent asked for,
82
+ -- and the ones never applied are the interesting ones; it ends in a status and
83
+ -- goes with its organization, never before.
84
+ GRANT SELECT, INSERT, UPDATE ON admin_proposals TO nacre_app;
85
+ -- The worker expires them across organizations and records that it did.
86
+ GRANT SELECT, UPDATE ON admin_proposals TO nacre_worker;
@@ -0,0 +1,139 @@
1
+ -- 0040 — notifications and alert rules on the administrative MCP.
2
+ --
3
+ -- docs/mcp-admin.md, "Notifications". Two ways a message leaves this
4
+ -- installation for somebody in an organization: an agent on the administrative
5
+ -- surface proposes one and a person applies it, or an alert rule the
6
+ -- organization keeps fires and the worker sends it. Both go through the outbox
7
+ -- below and nothing else, so the bound on who can receive one is in one place.
8
+ --
9
+ -- **A recipient is a user id, never an address.** Both tables carry `uuid[]`
10
+ -- and a flag for "every org_admin"; the address is read from `users` by the
11
+ -- worker at the moment of sending, from the notification's own organization,
12
+ -- active accounts only. There is no column an address could be written into,
13
+ -- which is the whole of T35's argument: an agent asked to send the access log
14
+ -- to somebody outside has no field in which to name them.
15
+
16
+ CREATE TABLE alert_rules (
17
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
18
+ org_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
19
+
20
+ -- What the rule watches. Each is a question the database can answer from
21
+ -- what it already records; none needs a hook in the code that does it.
22
+ kind text NOT NULL CHECK (kind IN (
23
+ 'skill_by_agent', -- a skill version written by an agent
24
+ 'skill_scripts', -- a skill version adding scripts
25
+ 'admin_connection', -- an administrative connection approved
26
+ 'denial_spike', -- one principal denied N times in a window
27
+ 'documents_failed' -- N documents failed in a window
28
+ )),
29
+ -- Narrows the kinds that happen inside one layer. NULL is every layer.
30
+ layer_id uuid,
31
+ -- The two counting kinds carry both; the others carry neither.
32
+ threshold int CHECK (threshold BETWEEN 1 AND 100000),
33
+ window_minutes int CHECK (window_minutes BETWEEN 5 AND 1440),
34
+
35
+ recipients uuid[] NOT NULL DEFAULT '{}' CHECK (cardinality(recipients) <= 20),
36
+ to_org_admins boolean NOT NULL DEFAULT false,
37
+
38
+ created_by uuid NOT NULL,
39
+ created_at timestamptz NOT NULL DEFAULT now(),
40
+ -- Removed rather than deleted: a rule is something an agent proposed and a
41
+ -- person applied, and "which rules did this organization have in May" is a
42
+ -- question the access log alone answers badly.
43
+ removed_at timestamptz,
44
+
45
+ -- Everything recorded up to here has been looked at. The worker advances it
46
+ -- only once what it found has reached the outbox, so a pass refused by the
47
+ -- rate limit is looked at again rather than lost.
48
+ checked_until timestamptz NOT NULL DEFAULT now(),
49
+ -- A counting rule fires at most once per window: a spike that lasts an hour
50
+ -- is one message, not sixty.
51
+ last_fired_at timestamptz,
52
+
53
+ CHECK (to_org_admins OR cardinality(recipients) > 0),
54
+ CHECK ((kind IN ('denial_spike', 'documents_failed')) = (threshold IS NOT NULL AND window_minutes IS NOT NULL)),
55
+ CHECK (layer_id IS NULL OR kind IN ('skill_by_agent', 'skill_scripts', 'documents_failed')),
56
+ UNIQUE (id, org_id),
57
+ FOREIGN KEY (layer_id, org_id) REFERENCES layers (id, org_id) ON DELETE CASCADE,
58
+ FOREIGN KEY (created_by, org_id) REFERENCES users (id, org_id) ON DELETE CASCADE
59
+ );
60
+
61
+ -- The worker's question, across organizations: which rules are due a look.
62
+ CREATE INDEX alert_rules_due_idx ON alert_rules (checked_until) WHERE removed_at IS NULL;
63
+ CREATE INDEX alert_rules_org_idx ON alert_rules (org_id, created_at) WHERE removed_at IS NULL;
64
+
65
+ ALTER TABLE alert_rules ENABLE ROW LEVEL SECURITY;
66
+ ALTER TABLE alert_rules FORCE ROW LEVEL SECURITY;
67
+ CREATE POLICY org_isolation ON alert_rules
68
+ USING (org_id = current_setting('app.current_org')::uuid);
69
+
70
+ CREATE TABLE notifications (
71
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
72
+ org_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
73
+
74
+ recipients uuid[] NOT NULL DEFAULT '{}' CHECK (cardinality(recipients) <= 20),
75
+ to_org_admins boolean NOT NULL DEFAULT false,
76
+
77
+ -- Plain text, bounded. No control characters but a newline or a tab in the body,
78
+ -- and none at all in the subject, which becomes a header.
79
+ subject text NOT NULL CHECK (length(subject) BETWEEN 1 AND 200 AND subject !~ '[[:cntrl:]]'),
80
+ body text NOT NULL CHECK (length(body) BETWEEN 1 AND 4000 AND body !~ '[\x01-\x08\x0b-\x1f\x7f]'),
81
+
82
+ -- What sent it. An agent's is applied by a person through a connection, and
83
+ -- the message says both; a rule's names the rule.
84
+ source text NOT NULL CHECK (source IN ('agent', 'rule')),
85
+ sent_by uuid,
86
+ consent_id uuid,
87
+ rule_id uuid,
88
+
89
+ status text NOT NULL DEFAULT 'queued'
90
+ CHECK (status IN ('queued', 'sending', 'sent', 'failed', 'dropped')),
91
+ attempts int NOT NULL DEFAULT 0,
92
+ not_before timestamptz NOT NULL DEFAULT now(),
93
+ created_at timestamptz NOT NULL DEFAULT now(),
94
+ claimed_at timestamptz,
95
+ finished_at timestamptz,
96
+ -- How many addresses it went to. Fewer than it named is somebody disabled
97
+ -- or removed since; none is `dropped`.
98
+ delivered int,
99
+ error text CHECK (length(error) <= 500),
100
+
101
+ CHECK (to_org_admins OR cardinality(recipients) > 0),
102
+ CHECK ((source = 'agent') = (sent_by IS NOT NULL AND consent_id IS NOT NULL)),
103
+ CHECK ((source = 'rule') = (rule_id IS NOT NULL)),
104
+ FOREIGN KEY (sent_by, org_id) REFERENCES users (id, org_id) ON DELETE CASCADE,
105
+ FOREIGN KEY (consent_id, org_id) REFERENCES oauth_consents (id, org_id) ON DELETE CASCADE,
106
+ FOREIGN KEY (rule_id, org_id) REFERENCES alert_rules (id, org_id) ON DELETE CASCADE
107
+ );
108
+
109
+ -- The worker's claim, across organizations.
110
+ CREATE INDEX notifications_queued_idx ON notifications (not_before) WHERE status = 'queued';
111
+ -- The rate limit: how many this organization has queued in the last hour.
112
+ CREATE INDEX notifications_org_recent_idx ON notifications (org_id, created_at);
113
+ -- Retention: finished rows past their window.
114
+ CREATE INDEX notifications_finished_idx ON notifications (finished_at) WHERE finished_at IS NOT NULL;
115
+
116
+ ALTER TABLE notifications ENABLE ROW LEVEL SECURITY;
117
+ ALTER TABLE notifications FORCE ROW LEVEL SECURITY;
118
+ CREATE POLICY org_isolation ON notifications
119
+ USING (org_id = current_setting('app.current_org')::uuid);
120
+
121
+ -- The application proposes and applies: it creates rules, removes them by
122
+ -- setting `removed_at`, and queues an agent's notification. It never sends.
123
+ GRANT SELECT, INSERT, UPDATE ON alert_rules TO nacre_app;
124
+ GRANT SELECT, INSERT ON notifications TO nacre_app;
125
+
126
+ -- The worker evaluates rules, queues what they find, sends, and forgets a
127
+ -- finished message after its retention window. DELETE on the outbox is not
128
+ -- the audit table's guarantee being given up: what was sent, to whom and why
129
+ -- is `notification.sent` in `audit_events`, which stays append-only. What goes
130
+ -- here is the body, which is exactly what should not be kept for ever.
131
+ -- (`nacre_app` is a member of `nacre_worker` since 0008 and inherits these.)
132
+ GRANT SELECT, UPDATE ON alert_rules TO nacre_worker;
133
+ GRANT SELECT, INSERT, UPDATE, DELETE ON notifications TO nacre_worker;
134
+
135
+ -- What the evaluator and the message's last line read, and only read: a skill
136
+ -- version's author and whether it carries scripts, and which application an
137
+ -- administrative connection is. The worker had no reason to see any of the
138
+ -- three until a rule could ask about them.
139
+ GRANT SELECT ON skill_versions, oauth_consents, oauth_clients TO nacre_worker;
@@ -0,0 +1,134 @@
1
+ import { type Message } from './mail.js';
2
+ /**
3
+ * Notifications and alert rules. docs/mcp-admin.md, "Notifications".
4
+ *
5
+ * The bounds, the one validation both ends run, and the two messages the
6
+ * worker sends. In the core rather than beside the API's other messages
7
+ * because the worker sends these and cannot import the API — and
8
+ * `packages/api/src/messages.ts` lists them with the rest, so the preview and
9
+ * anything else reasoning about the set still sees one list.
10
+ *
11
+ * ## Who can receive one
12
+ *
13
+ * A recipient is a **user id** in the caller's own organization, active, and
14
+ * nothing else. There is no field for an address anywhere: the tools take an
15
+ * address only to *find a person*, the outbox stores ids, and the worker reads
16
+ * the address from `users` at the moment of sending, scoped to the
17
+ * notification's organization. T35 is the refusal at the first step; the
18
+ * second and third are why the first is not the only thing standing.
19
+ *
20
+ * ## Why a notification carries no links
21
+ *
22
+ * The body is somebody's prose sent from this installation's own address, to
23
+ * everybody in an organization if the agent asked for that — which is the
24
+ * exact shape of a phishing message, and on a surface whose threat model is an
25
+ * instruction planted in a document. A person applies every one, and reads it
26
+ * first; a person also reads a message saying their password expired and
27
+ * linking somewhere convincing. So a URL in either part is refused, with the
28
+ * reason, and the only link in a message this installation sends is one the
29
+ * installation built from its own configuration.
30
+ */
31
+ /** Explicit recipients on one notification or one rule. "Every org_admin" is a flag, not a list. */
32
+ export declare const NOTIFY_MAX_RECIPIENTS = 20;
33
+ export declare const NOTIFY_SUBJECT_MAX = 200;
34
+ export declare const NOTIFY_BODY_MAX = 4000;
35
+ /**
36
+ * Notifications queued per organization in any hour, agents and rules together.
37
+ *
38
+ * A constant rather than a variable: it is the bound on how loud one tenant's
39
+ * agent can be through the installation's relay, and an operator who wants a
40
+ * louder one is asking for something nobody has argued for. Thirty is a
41
+ * person's inbox having a bad hour, not a mailing list.
42
+ */
43
+ export declare const NOTIFY_PER_HOUR = 30;
44
+ /** What an alert rule can watch. Each is answered from what the database already records. */
45
+ export declare const ALERT_KINDS: {
46
+ readonly skill_by_agent: {
47
+ readonly counts: false;
48
+ readonly layered: true;
49
+ readonly summary: "a skill version written by an agent";
50
+ };
51
+ readonly skill_scripts: {
52
+ readonly counts: false;
53
+ readonly layered: true;
54
+ readonly summary: "a skill version that adds scripts";
55
+ };
56
+ readonly admin_connection: {
57
+ readonly counts: false;
58
+ readonly layered: false;
59
+ readonly summary: "an administrative connection approved";
60
+ };
61
+ readonly denial_spike: {
62
+ readonly counts: true;
63
+ readonly layered: false;
64
+ readonly summary: "one person or service account denied at least the threshold within the window";
65
+ };
66
+ readonly documents_failed: {
67
+ readonly counts: true;
68
+ readonly layered: true;
69
+ readonly summary: "at least the threshold of documents failing to index within the window";
70
+ };
71
+ };
72
+ export type AlertKind = keyof typeof ALERT_KINDS;
73
+ export declare const isAlertKind: (value: unknown) => value is AlertKind;
74
+ /** The window a counting rule takes, in minutes. */
75
+ export declare const ALERT_WINDOW: {
76
+ readonly min: 5;
77
+ readonly max: 1440;
78
+ readonly default: 60;
79
+ };
80
+ /** The sentence a rule is read as, from what it stores. */
81
+ export declare function ruleSentence(rule: {
82
+ readonly kind: AlertKind;
83
+ readonly layerSlug: string | null;
84
+ readonly threshold: number | null;
85
+ readonly windowMinutes: number | null;
86
+ }): string;
87
+ /**
88
+ * A subject and a body, or the sentence saying why not.
89
+ *
90
+ * Both ends ask it: the tool when it proposes, so the person is never shown
91
+ * something that would be refused, and the apply, because a stored proposal is
92
+ * not trusted for having been checked ten minutes ago.
93
+ */
94
+ export declare function notificationText(subject: unknown, body: unknown): {
95
+ readonly subject: string;
96
+ readonly body: string;
97
+ } | {
98
+ readonly refused: string;
99
+ };
100
+ /**
101
+ * A name somebody outside the organization chose — an application's registered
102
+ * name — made safe to put in a message's text: one line, bounded, and broken
103
+ * where a mail client would otherwise turn it into a link. The rule above, for
104
+ * the one string in an alert that this installation did not write.
105
+ */
106
+ export declare function plainName(value: string): string;
107
+ /** What a stored notification says about where it came from, for the message's last line. */
108
+ export type NotificationOrigin = {
109
+ readonly source: 'agent';
110
+ /** The person who applied it. */
111
+ readonly appliedBy: string;
112
+ /** The application the administrative connection was approved for. */
113
+ readonly application: string;
114
+ } | {
115
+ readonly source: 'rule';
116
+ /** What the rule watches, as `ruleSentence` says it. */
117
+ readonly when: string;
118
+ /** Who created the rule, by address, or null where they are gone. */
119
+ readonly ruleBy: string | null;
120
+ };
121
+ /**
122
+ * A notification, in the brand, to one address.
123
+ *
124
+ * The body is the stored text, a paragraph per blank-line-separated block. The
125
+ * last line says where it came from — an agent, through which application, and
126
+ * who applied it; or which rule — because a message from this installation's
127
+ * address that an agent wrote has to say so, or it borrows trust it was not
128
+ * given. The one link is to the access log, built from configuration.
129
+ */
130
+ export declare function notificationMessage(to: string, consoleBase: string, stored: {
131
+ readonly subject: string;
132
+ readonly body: string;
133
+ }, origin: NotificationOrigin): Message;
134
+ //# sourceMappingURL=notifications.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../notifications.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,OAAO,EAAE,MAAM,WAAW,CAAA;AAE7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,oGAAoG;AACpG,eAAO,MAAM,qBAAqB,KAAK,CAAA;AAEvC,eAAO,MAAM,kBAAkB,MAAM,CAAA;AACrC,eAAO,MAAM,eAAe,OAAO,CAAA;AAEnC;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,KAAK,CAAA;AAEjC,6FAA6F;AAC7F,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;CA0Bd,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,WAAW,CAAA;AAEhD,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,SACiC,CAAA;AAEvF,oDAAoD;AACpD,eAAO,MAAM,YAAY;;;;CAA8C,CAAA;AAEvE,2DAA2D;AAC3D,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CACtC,GAAG,MAAM,CAcT;AAWD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,OAAO,GACZ;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAqBpF;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED,6FAA6F;AAC7F,MAAM,MAAM,kBAAkB,GAC1B;IACE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,iCAAiC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B,GACD;IACE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,qEAAqE;IACrE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B,CAAA;AAEL;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC3D,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAmBT"}