@amtp/protocol 1.0.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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +386 -0
  3. package/USAGE_GUIDE.md +722 -0
  4. package/bin/amtp.ts +387 -0
  5. package/dist/client/amtp-client.d.ts +164 -0
  6. package/dist/client/amtp-client.js +460 -0
  7. package/dist/client/amtp-client.js.map +1 -0
  8. package/dist/client/examples/basic-client.d.ts +6 -0
  9. package/dist/client/examples/basic-client.js +35 -0
  10. package/dist/client/examples/basic-client.js.map +1 -0
  11. package/dist/crawler/amtp-crawler.d.ts +125 -0
  12. package/dist/crawler/amtp-crawler.js +359 -0
  13. package/dist/crawler/amtp-crawler.js.map +1 -0
  14. package/dist/crawler/examples/basic-crawler.d.ts +6 -0
  15. package/dist/crawler/examples/basic-crawler.js +28 -0
  16. package/dist/crawler/examples/basic-crawler.js.map +1 -0
  17. package/dist/index.d.ts +15 -0
  18. package/dist/index.js +70 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/server/adapters/fastify-adapter.d.ts +86 -0
  21. package/dist/server/adapters/fastify-adapter.js +169 -0
  22. package/dist/server/adapters/fastify-adapter.js.map +1 -0
  23. package/dist/server/amtp-ql-executor.d.ts +24 -0
  24. package/dist/server/amtp-ql-executor.js +198 -0
  25. package/dist/server/amtp-ql-executor.js.map +1 -0
  26. package/dist/server/amtp-ql-parser.d.ts +30 -0
  27. package/dist/server/amtp-ql-parser.js +212 -0
  28. package/dist/server/amtp-ql-parser.js.map +1 -0
  29. package/dist/server/amtp-server.d.ts +183 -0
  30. package/dist/server/amtp-server.js +650 -0
  31. package/dist/server/amtp-server.js.map +1 -0
  32. package/dist/server/examples/basic-server.d.ts +6 -0
  33. package/dist/server/examples/basic-server.js +215 -0
  34. package/dist/server/examples/basic-server.js.map +1 -0
  35. package/dist/server/examples/saas-dashboard-server.d.ts +44 -0
  36. package/dist/server/examples/saas-dashboard-server.js +387 -0
  37. package/dist/server/examples/saas-dashboard-server.js.map +1 -0
  38. package/dist/server/markdown-parser.d.ts +31 -0
  39. package/dist/server/markdown-parser.js +463 -0
  40. package/dist/server/markdown-parser.js.map +1 -0
  41. package/dist/server/notifications.d.ts +40 -0
  42. package/dist/server/notifications.js +134 -0
  43. package/dist/server/notifications.js.map +1 -0
  44. package/dist/server/permissions.d.ts +40 -0
  45. package/dist/server/permissions.js +156 -0
  46. package/dist/server/permissions.js.map +1 -0
  47. package/dist/server/security.d.ts +127 -0
  48. package/dist/server/security.js +368 -0
  49. package/dist/server/security.js.map +1 -0
  50. package/dist/types/amtp.types.d.ts +720 -0
  51. package/dist/types/amtp.types.js +224 -0
  52. package/dist/types/amtp.types.js.map +1 -0
  53. package/package.json +89 -0
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ /**
3
+ * AMTP Notifications - Webhook + SSE Push Model (v2.0)
4
+ *
5
+ * Provides real-time push notifications to agents via:
6
+ * - Server-Sent Events (SSE) for long-lived connections
7
+ * - Webhooks for fire-and-forget delivery
8
+ *
9
+ * Security:
10
+ * - Webhooks are signed with HMAC-SHA256 using a per-subscription secret
11
+ * - Agents should verify the signature on every webhook call
12
+ */
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.notificationBus = exports.NotificationBus = void 0;
18
+ const events_1 = require("events");
19
+ const crypto_1 = __importDefault(require("crypto"));
20
+ const WEBHOOK_SIGNATURE_HEADER = "X-AMTP-Signature";
21
+ const WEBHOOK_TIMESTAMP_HEADER = "X-AMTP-Timestamp";
22
+ /**
23
+ * Simple in-memory event bus for AMTP notifications.
24
+ * In production, replace with Redis / NATS / etc.
25
+ */
26
+ class NotificationBus extends events_1.EventEmitter {
27
+ constructor() {
28
+ super(...arguments);
29
+ this.webhooks = new Map();
30
+ this.sseClients = new Map();
31
+ }
32
+ /**
33
+ * Emit an event to all subscribers (SSE + Webhooks)
34
+ */
35
+ emitEvent(event) {
36
+ // 1. Notify SSE clients
37
+ const listeners = this.sseClients.get(event.type) || new Set();
38
+ listeners.forEach((send) => {
39
+ try {
40
+ send(event);
41
+ }
42
+ catch (err) {
43
+ // client disconnected, will be cleaned up on close
44
+ }
45
+ });
46
+ // 2. Deliver to webhooks
47
+ this.deliverToWebhooks(event);
48
+ }
49
+ /**
50
+ * Register a new webhook subscription
51
+ */
52
+ registerWebhook(req) {
53
+ const id = `wh_${Date.now()}_${crypto_1.default.randomBytes(4).toString("hex")}`;
54
+ const sub = {
55
+ id,
56
+ url: req.url,
57
+ events: req.events,
58
+ secret: req.secret,
59
+ createdAt: new Date().toISOString(),
60
+ active: true,
61
+ description: req.description,
62
+ };
63
+ this.webhooks.set(id, sub);
64
+ return sub;
65
+ }
66
+ getWebhook(id) {
67
+ return this.webhooks.get(id);
68
+ }
69
+ listWebhooks() {
70
+ return Array.from(this.webhooks.values());
71
+ }
72
+ deleteWebhook(id) {
73
+ return this.webhooks.delete(id);
74
+ }
75
+ /**
76
+ * Subscribe an SSE client to specific event types
77
+ */
78
+ subscribeSSE(types, send) {
79
+ const unsubs = [];
80
+ types.forEach((type) => {
81
+ if (!this.sseClients.has(type)) {
82
+ this.sseClients.set(type, new Set());
83
+ }
84
+ const set = this.sseClients.get(type);
85
+ set.add(send);
86
+ unsubs.push(() => {
87
+ set.delete(send);
88
+ if (set.size === 0)
89
+ this.sseClients.delete(type);
90
+ });
91
+ });
92
+ return () => unsubs.forEach((fn) => fn());
93
+ }
94
+ async deliverToWebhooks(event) {
95
+ const deliveries = Array.from(this.webhooks.values())
96
+ .filter((sub) => sub.active && sub.events.some((e) => e === event.type || e === "*"))
97
+ .map(async (sub) => {
98
+ try {
99
+ const timestamp = Math.floor(Date.now() / 1000).toString();
100
+ const payload = JSON.stringify(event);
101
+ const signature = this.signPayload(payload, timestamp, sub.secret);
102
+ const res = await fetch(sub.url, {
103
+ method: "POST",
104
+ headers: {
105
+ "Content-Type": "application/json",
106
+ [WEBHOOK_SIGNATURE_HEADER]: signature,
107
+ [WEBHOOK_TIMESTAMP_HEADER]: timestamp,
108
+ "User-Agent": "AMTP-Webhook/1.1",
109
+ },
110
+ body: payload,
111
+ // In real impl: add timeout, retries, dead letter queue
112
+ });
113
+ if (!res.ok) {
114
+ console.warn(`[AMTP Webhook] Delivery failed to ${sub.url}: ${res.status}`);
115
+ }
116
+ }
117
+ catch (err) {
118
+ console.error(`[AMTP Webhook] Error delivering to ${sub.url}:`, err);
119
+ }
120
+ });
121
+ await Promise.allSettled(deliveries);
122
+ }
123
+ signPayload(payload, timestamp, secret) {
124
+ if (!secret)
125
+ return "";
126
+ const hmac = crypto_1.default.createHmac("sha256", secret);
127
+ hmac.update(`${timestamp}.${payload}`);
128
+ return `sha256=${hmac.digest("hex")}`;
129
+ }
130
+ }
131
+ exports.NotificationBus = NotificationBus;
132
+ // Singleton for the reference implementation
133
+ exports.notificationBus = new NotificationBus();
134
+ //# sourceMappingURL=notifications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../src/server/notifications.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;;;;AAEH,mCAAsC;AACtC,oDAA4B;AAG5B,MAAM,wBAAwB,GAAG,kBAAkB,CAAC;AACpD,MAAM,wBAAwB,GAAG,kBAAkB,CAAC;AAEpD;;;GAGG;AACH,MAAa,eAAgB,SAAQ,qBAAY;IAAjD;;QACU,aAAQ,GAAqC,IAAI,GAAG,EAAE,CAAC;QACvD,eAAU,GAAyD,IAAI,GAAG,EAAE,CAAC;IA8GvF,CAAC;IA5GC;;OAEG;IACH,SAAS,CAAC,KAAwB;QAChC,wBAAwB;QACxB,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;QAC/D,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI;gBACF,IAAI,CAAC,KAAK,CAAC,CAAC;aACb;YAAC,OAAO,GAAG,EAAE;gBACZ,mDAAmD;aACpD;QACH,CAAC,CAAC,CAAC;QAEH,yBAAyB;QACzB,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,eAAe,CAAC,GAA2B;QACzC,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,IAAI,gBAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACvE,MAAM,GAAG,GAAwB;YAC/B,EAAE;YACF,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,MAAM,EAAE,IAAI;YACZ,WAAW,EAAE,GAAG,CAAC,WAAW;SAC7B,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC3B,OAAO,GAAG,CAAC;IACb,CAAC;IAED,UAAU,CAAC,EAAU;QACnB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED,YAAY;QACV,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,aAAa,CAAC,EAAU;QACtB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,KAAe,EAAE,IAAwC;QACpE,MAAM,MAAM,GAAsB,EAAE,CAAC;QAErC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACrB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;gBAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;aACtC;YACD,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;YACvC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAEd,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;gBACf,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACjB,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;oBAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACnD,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5C,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,KAAwB;QACtD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;aAClD,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;aACpF,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YACjB,IAAI;gBACF,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;gBACtC,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;gBAEnE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;oBAC/B,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE;wBACP,cAAc,EAAE,kBAAkB;wBAClC,CAAC,wBAAwB,CAAC,EAAE,SAAS;wBACrC,CAAC,wBAAwB,CAAC,EAAE,SAAS;wBACrC,YAAY,EAAE,kBAAkB;qBACjC;oBACD,IAAI,EAAE,OAAO;oBACb,wDAAwD;iBACzD,CAAC,CAAC;gBAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE;oBACX,OAAO,CAAC,IAAI,CAAC,qCAAqC,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;iBAC7E;aACF;YAAC,OAAO,GAAG,EAAE;gBACZ,OAAO,CAAC,KAAK,CAAC,sCAAsC,GAAG,CAAC,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC;aACtE;QACH,CAAC,CAAC,CAAC;QAEL,MAAM,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IACvC,CAAC;IAEO,WAAW,CAAC,OAAe,EAAE,SAAiB,EAAE,MAAe;QACrE,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,gBAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACjD,IAAI,CAAC,MAAM,CAAC,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC,CAAC;QACvC,OAAO,UAAU,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IACxC,CAAC;CACF;AAhHD,0CAgHC;AAED,6CAA6C;AAChC,QAAA,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * AMTP Permission Guard — middleware for policy-based access control.
3
+ *
4
+ * Evaluates the permissions/policies declared in an AMTPDocument against
5
+ * the current session's granted permissions at action-execution time.
6
+ *
7
+ * Design:
8
+ * - Documents declare `permissions` and `policies` as first-class protocol blocks.
9
+ * - Sessions hold a flat `permissions: string[]` of granted permission IDs.
10
+ * - PermissionGuard resolves which policies apply to the current session,
11
+ * checks conditions, and denies the action if a required permission is missing.
12
+ */
13
+ import { AMTPDocument, Action, Session } from "../types/amtp.types";
14
+ export interface PermissionCheckResult {
15
+ allowed: boolean;
16
+ reason?: string;
17
+ requiredPermissions?: string[];
18
+ matchedPolicy?: string;
19
+ }
20
+ export interface PermissionGuardConfig {
21
+ /** When true, actions with no matching permission/policy are denied (default: false) */
22
+ denyByDefault?: boolean;
23
+ /** Custom error message for denied actions */
24
+ deniedMessage?: string;
25
+ }
26
+ export declare class PermissionGuard {
27
+ private config;
28
+ constructor(config?: PermissionGuardConfig);
29
+ /**
30
+ * Check whether a session is allowed to execute an action on a document
31
+ * given the document's declared permissions and policies.
32
+ */
33
+ check(action: Action, doc: AMTPDocument, session?: Session): PermissionCheckResult;
34
+ /**
35
+ * Convenience: throws AMTPError if the action is not permitted.
36
+ */
37
+ assert(action: Action, doc: AMTPDocument, session?: Session): void;
38
+ private evaluateConditions;
39
+ private resolveField;
40
+ }
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ /**
3
+ * AMTP Permission Guard — middleware for policy-based access control.
4
+ *
5
+ * Evaluates the permissions/policies declared in an AMTPDocument against
6
+ * the current session's granted permissions at action-execution time.
7
+ *
8
+ * Design:
9
+ * - Documents declare `permissions` and `policies` as first-class protocol blocks.
10
+ * - Sessions hold a flat `permissions: string[]` of granted permission IDs.
11
+ * - PermissionGuard resolves which policies apply to the current session,
12
+ * checks conditions, and denies the action if a required permission is missing.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.PermissionGuard = void 0;
16
+ const amtp_types_1 = require("../types/amtp.types");
17
+ /* ================================================================
18
+ PERMISSION GUARD
19
+ ================================================================ */
20
+ class PermissionGuard {
21
+ constructor(config) {
22
+ this.config = {
23
+ denyByDefault: config?.denyByDefault ?? false,
24
+ deniedMessage: config?.deniedMessage ?? "Action denied by policy",
25
+ };
26
+ }
27
+ /**
28
+ * Check whether a session is allowed to execute an action on a document
29
+ * given the document's declared permissions and policies.
30
+ */
31
+ check(action, doc, session) {
32
+ // If the action doesn't declare required permissions, policy is optional
33
+ const requiredPerms = action.permissions;
34
+ if (!requiredPerms || requiredPerms.length === 0) {
35
+ return { allowed: !this.config.denyByDefault };
36
+ }
37
+ const sessionPerms = session?.permissions ?? [];
38
+ // If no session but action requires auth, deny
39
+ if (!session && action.requiresAuthentication !== false) {
40
+ return {
41
+ allowed: false,
42
+ reason: "Authentication required",
43
+ requiredPermissions: requiredPerms,
44
+ };
45
+ }
46
+ // Find policies in the document that apply to the session's role
47
+ const docPolicies = doc.policies ?? [];
48
+ const sessionRole = session?.metadata?.role;
49
+ const matchingPolicies = docPolicies.filter((p) => {
50
+ // If the policy has a role restriction, the session must match
51
+ if (p.roles && p.roles.length > 0) {
52
+ if (!sessionRole || !p.roles.includes(sessionRole))
53
+ return false;
54
+ }
55
+ return true;
56
+ });
57
+ // Check conditions on matching policies
58
+ for (const policy of matchingPolicies) {
59
+ if (policy.conditions && policy.conditions.length > 0) {
60
+ const conditionsMet = this.evaluateConditions(policy.conditions, session);
61
+ if (!conditionsMet)
62
+ continue;
63
+ }
64
+ // Check if this policy covers all the action's required permissions
65
+ const hasAllPerms = requiredPerms.every((rp) => {
66
+ return policy.permissions.includes(rp) || sessionPerms.includes(rp);
67
+ });
68
+ if (hasAllPerms) {
69
+ return {
70
+ allowed: true,
71
+ matchedPolicy: policy.id,
72
+ requiredPermissions: requiredPerms,
73
+ };
74
+ }
75
+ }
76
+ // Fallback: check if session directly has the required permissions
77
+ const hasDirectPerms = requiredPerms.every((rp) => sessionPerms.includes(rp));
78
+ if (hasDirectPerms) {
79
+ return {
80
+ allowed: true,
81
+ requiredPermissions: requiredPerms,
82
+ };
83
+ }
84
+ // Deny
85
+ const missingPerms = requiredPerms.filter((rp) => !sessionPerms.includes(rp));
86
+ return {
87
+ allowed: false,
88
+ reason: `${this.config.deniedMessage}: missing permissions [${missingPerms.join(", ")}]`,
89
+ requiredPermissions: requiredPerms,
90
+ };
91
+ }
92
+ /**
93
+ * Convenience: throws AMTPError if the action is not permitted.
94
+ */
95
+ assert(action, doc, session) {
96
+ const result = this.check(action, doc, session);
97
+ if (!result.allowed) {
98
+ throw new amtp_types_1.AMTPError(amtp_types_1.ErrorCode.PERMISSION_DENIED, result.reason || this.config.deniedMessage, amtp_types_1.StatusCode.FORBIDDEN);
99
+ }
100
+ }
101
+ evaluateConditions(conditions, session) {
102
+ if (!session)
103
+ return false;
104
+ for (const cond of conditions) {
105
+ const actual = this.resolveField(cond.field, session);
106
+ const expected = cond.value;
107
+ switch (cond.operator) {
108
+ case "eq":
109
+ if (actual !== expected)
110
+ return false;
111
+ break;
112
+ case "neq":
113
+ if (actual === expected)
114
+ return false;
115
+ break;
116
+ case "in": {
117
+ if (!Array.isArray(expected) || !expected.includes(actual))
118
+ return false;
119
+ break;
120
+ }
121
+ case "gt":
122
+ if (typeof actual !== "number" || typeof expected !== "number" || actual <= expected)
123
+ return false;
124
+ break;
125
+ case "lt":
126
+ if (typeof actual !== "number" || typeof expected !== "number" || actual >= expected)
127
+ return false;
128
+ break;
129
+ case "contains":
130
+ if (typeof actual !== "string" || !actual.includes(String(expected)))
131
+ return false;
132
+ break;
133
+ case "exists":
134
+ if (actual === undefined || actual === null)
135
+ return false;
136
+ break;
137
+ }
138
+ }
139
+ return true;
140
+ }
141
+ resolveField(field, session) {
142
+ const parts = field.split(".");
143
+ let value = session;
144
+ for (const part of parts) {
145
+ if (value && typeof value === "object") {
146
+ value = value[part];
147
+ }
148
+ else {
149
+ return undefined;
150
+ }
151
+ }
152
+ return value;
153
+ }
154
+ }
155
+ exports.PermissionGuard = PermissionGuard;
156
+ //# sourceMappingURL=permissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/server/permissions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * AMTP Security Utilities
3
+ * Centralized security utilities for the AMTP protocol
4
+ */
5
+ /**
6
+ * Generate a cryptographically secure random string
7
+ * Replaces Math.random()-based session and request IDs
8
+ */
9
+ export declare function secureRandomString(length?: number): string;
10
+ /** Session ID prefix for AMTP */
11
+ export declare const AMTP_SESSION_ID_PREFIX = "sess_";
12
+ /** Generate a secure AMTP session ID */
13
+ export declare function generateSecureSessionId(): string;
14
+ /** Request ID prefix for AMTP */
15
+ export declare const AMTP_REQUEST_ID_PREFIX = "req_";
16
+ /** Generate a secure AMTP request ID */
17
+ export declare function generateSecureRequestId(): string;
18
+ /** Allowed redirect schemes — block javascript:, data:, file:, vbscript: */
19
+ export declare const ALLOWED_URL_SCHEMES: Set<string>;
20
+ /** Dangerous HTML/script patterns in markdown content */
21
+ export declare const XSS_PATTERNS: RegExp[];
22
+ /**
23
+ * Parse and validate a URL against SSRF / open-redirect patterns.
24
+ * Returns the validated URL string or throws.
25
+ */
26
+ export declare function validateUrl(value: string, baseUrl?: string): string;
27
+ /**
28
+ * Strip potentially dangerous HTML/script content from a string
29
+ * Returns the sanitized string and a boolean indicating whether
30
+ * anything was removed.
31
+ */
32
+ export declare function sanitizeHtml(input: string): string;
33
+ /**
34
+ * Validate a string field (non-empty, no control characters, max length)
35
+ */
36
+ export declare function validateTextField(value: string, options?: {
37
+ minLength?: number;
38
+ maxLength?: number;
39
+ fieldName?: string;
40
+ }): string;
41
+ /** Common security response headers for AMTP endpoints */
42
+ export declare const AMTP_SECURITY_HEADERS: Record<string, string>;
43
+ /**
44
+ * Map of IP -> { count, resetAt } used in in-memory rate limiting.
45
+ * Callers should reset expired entries periodically.
46
+ */
47
+ export declare class InMemoryRateLimiter {
48
+ private windowMs;
49
+ private maxRequests;
50
+ private map;
51
+ constructor(windowMs: number, maxRequests: number);
52
+ /**
53
+ * Returns true if the request is within the allowed rate limit,
54
+ * false if it should be rejected with 429.
55
+ */
56
+ check(ip: string): boolean;
57
+ /**
58
+ * Compute Retry-After (seconds) for a rejected IP.
59
+ */
60
+ retryAfterSeconds(ip: string): number;
61
+ /**
62
+ * Prune stale entries from the store.
63
+ */
64
+ prune(): void;
65
+ }
66
+ /** Default session timeout: 24 hours */
67
+ export declare const DEFAULT_SESSION_TIMEOUT_MS: number;
68
+ /** Absolute cap for any session lifetime regardless of extensions */
69
+ export declare const MAX_SESSION_LIFETIME_MS: number;
70
+ export declare class SecurityError extends Error {
71
+ readonly code: string;
72
+ readonly statusCode: number;
73
+ constructor(message: string, code: string, statusCode: number);
74
+ }
75
+ /** Default maximum request body size: 1 MB */
76
+ export declare const DEFAULT_MAX_BODY_SIZE: number;
77
+ /**
78
+ * Wrap a request/stream body consumer so it stops after maxBytes.
79
+ * Returns the accumulated string (truncated) and a flag indicating truncation.
80
+ * Supports: string, browser ReadableStream, Node.js Readable.
81
+ */
82
+ export declare function readBodyWithLimit(body: any, maxBytes?: number): Promise<{
83
+ body: string;
84
+ truncated: boolean;
85
+ }>;
86
+ /**
87
+ * Returns true if the string looks like a valid AMTP session ID.
88
+ */
89
+ export declare function isValidSessionId(sessionId: string | null | undefined): boolean;
90
+ /**
91
+ * Returns the CSRF token header name.
92
+ */
93
+ export declare function csrfHeaderName(): string;
94
+ /**
95
+ * Returns the value for a new CSRF token.
96
+ * Note: The actual token-to-session binding is managed externally (see SessionManager).
97
+ * This generates the token value only.
98
+ */
99
+ export declare function generateCsrfToken(_sessionId: string): string;
100
+ /**
101
+ * Validate that a CSRF token is non-empty and properly formatted.
102
+ */
103
+ export declare function isValidCsrfToken(token: string | undefined | null): boolean;
104
+ /**
105
+ * Strictly sanitize an action identifier.
106
+ * Only [A-Z0-9_] allowed, must start with letter, max 64 chars.
107
+ * This prevents injection of new actions, newlines, or control chars
108
+ * into the machine-readable action contract.
109
+ */
110
+ export declare function sanitizeActionId(raw: string): string;
111
+ /**
112
+ * Strictly sanitize an endpoint path for actions/forms.
113
+ * Only safe path characters. No query strings, fragments, or protocol.
114
+ */
115
+ export declare function sanitizeEndpoint(raw: string): string;
116
+ /**
117
+ * Strictly validate and normalize HTTP method.
118
+ */
119
+ export declare function sanitizeHttpMethod(raw: string): string;
120
+ /**
121
+ * Sanitize free-text fields (descriptions, labels, help text) that will be
122
+ * shown to or used in prompts for LLMs/agents.
123
+ *
124
+ * This is the key defense against prompt injection via action descriptions.
125
+ * We aggressively strip common jailbreak patterns while preserving useful hints.
126
+ */
127
+ export declare function sanitizeFreeText(text: string, maxLength?: number): string;