botmux 2.44.0 → 2.46.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.
Files changed (192) hide show
  1. package/README.en.md +1 -2
  2. package/README.md +1 -2
  3. package/dist/cli/bots-list-output.d.ts +8 -0
  4. package/dist/cli/bots-list-output.d.ts.map +1 -1
  5. package/dist/cli/bots-list-output.js +9 -0
  6. package/dist/cli/bots-list-output.js.map +1 -1
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +6 -0
  9. package/dist/cli.js.map +1 -1
  10. package/dist/core/command-handler.d.ts.map +1 -1
  11. package/dist/core/command-handler.js +601 -50
  12. package/dist/core/command-handler.js.map +1 -1
  13. package/dist/core/dashboard-ipc-server.d.ts +2 -0
  14. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  15. package/dist/core/dashboard-ipc-server.js +170 -2
  16. package/dist/core/dashboard-ipc-server.js.map +1 -1
  17. package/dist/core/role-resolver.d.ts +17 -1
  18. package/dist/core/role-resolver.d.ts.map +1 -1
  19. package/dist/core/role-resolver.js +64 -10
  20. package/dist/core/role-resolver.js.map +1 -1
  21. package/dist/core/session-manager.d.ts +1 -1
  22. package/dist/core/session-manager.d.ts.map +1 -1
  23. package/dist/core/session-manager.js +24 -13
  24. package/dist/core/session-manager.js.map +1 -1
  25. package/dist/core/trigger-session.d.ts +9 -0
  26. package/dist/core/trigger-session.d.ts.map +1 -0
  27. package/dist/core/trigger-session.js +158 -0
  28. package/dist/core/trigger-session.js.map +1 -0
  29. package/dist/core/worker-pool.d.ts +105 -0
  30. package/dist/core/worker-pool.d.ts.map +1 -1
  31. package/dist/core/worker-pool.js +284 -4
  32. package/dist/core/worker-pool.js.map +1 -1
  33. package/dist/daemon.d.ts.map +1 -1
  34. package/dist/daemon.js +80 -45
  35. package/dist/daemon.js.map +1 -1
  36. package/dist/dashboard/connector-api.d.ts +3 -0
  37. package/dist/dashboard/connector-api.d.ts.map +1 -0
  38. package/dist/dashboard/connector-api.js +351 -0
  39. package/dist/dashboard/connector-api.js.map +1 -0
  40. package/dist/dashboard/federated-group-core.d.ts +54 -0
  41. package/dist/dashboard/federated-group-core.d.ts.map +1 -0
  42. package/dist/dashboard/federated-group-core.js +165 -0
  43. package/dist/dashboard/federated-group-core.js.map +1 -0
  44. package/dist/dashboard/federation-api.d.ts +42 -0
  45. package/dist/dashboard/federation-api.d.ts.map +1 -0
  46. package/dist/dashboard/federation-api.js +408 -0
  47. package/dist/dashboard/federation-api.js.map +1 -0
  48. package/dist/dashboard/federation-spoke-api.d.ts +76 -0
  49. package/dist/dashboard/federation-spoke-api.d.ts.map +1 -0
  50. package/dist/dashboard/federation-spoke-api.js +618 -0
  51. package/dist/dashboard/federation-spoke-api.js.map +1 -0
  52. package/dist/dashboard/team-group.d.ts +18 -0
  53. package/dist/dashboard/team-group.d.ts.map +1 -0
  54. package/dist/dashboard/team-group.js +7 -0
  55. package/dist/dashboard/team-group.js.map +1 -0
  56. package/dist/dashboard/trigger-api.d.ts +13 -0
  57. package/dist/dashboard/trigger-api.d.ts.map +1 -0
  58. package/dist/dashboard/trigger-api.js +77 -0
  59. package/dist/dashboard/trigger-api.js.map +1 -0
  60. package/dist/dashboard/web/app.js +8 -0
  61. package/dist/dashboard/web/app.js.map +1 -1
  62. package/dist/dashboard/web/connectors.d.ts +2 -0
  63. package/dist/dashboard/web/connectors.d.ts.map +1 -0
  64. package/dist/dashboard/web/connectors.js +187 -0
  65. package/dist/dashboard/web/connectors.js.map +1 -0
  66. package/dist/dashboard/web/team-federation.d.ts +3 -0
  67. package/dist/dashboard/web/team-federation.d.ts.map +1 -0
  68. package/dist/dashboard/web/team-federation.js +487 -0
  69. package/dist/dashboard/web/team-federation.js.map +1 -0
  70. package/dist/dashboard/webhook-routes.d.ts +19 -0
  71. package/dist/dashboard/webhook-routes.d.ts.map +1 -0
  72. package/dist/dashboard/webhook-routes.js +321 -0
  73. package/dist/dashboard/webhook-routes.js.map +1 -0
  74. package/dist/dashboard-web/app.js +509 -386
  75. package/dist/dashboard-web/index.html +2 -0
  76. package/dist/dashboard.js +152 -1
  77. package/dist/dashboard.js.map +1 -1
  78. package/dist/i18n/en.d.ts.map +1 -1
  79. package/dist/i18n/en.js +85 -8
  80. package/dist/i18n/en.js.map +1 -1
  81. package/dist/i18n/zh.d.ts.map +1 -1
  82. package/dist/i18n/zh.js +85 -8
  83. package/dist/i18n/zh.js.map +1 -1
  84. package/dist/im/lark/card-builder.d.ts +82 -0
  85. package/dist/im/lark/card-builder.d.ts.map +1 -1
  86. package/dist/im/lark/card-builder.js +315 -0
  87. package/dist/im/lark/card-builder.js.map +1 -1
  88. package/dist/im/lark/card-handler.d.ts.map +1 -1
  89. package/dist/im/lark/card-handler.js +195 -1
  90. package/dist/im/lark/card-handler.js.map +1 -1
  91. package/dist/im/lark/client.d.ts +45 -0
  92. package/dist/im/lark/client.d.ts.map +1 -1
  93. package/dist/im/lark/client.js +169 -18
  94. package/dist/im/lark/client.js.map +1 -1
  95. package/dist/im/lark/message-parser.d.ts.map +1 -1
  96. package/dist/im/lark/message-parser.js +1 -0
  97. package/dist/im/lark/message-parser.js.map +1 -1
  98. package/dist/services/bot-owner-store.d.ts +28 -0
  99. package/dist/services/bot-owner-store.d.ts.map +1 -0
  100. package/dist/services/bot-owner-store.js +82 -0
  101. package/dist/services/bot-owner-store.js.map +1 -0
  102. package/dist/services/bot-profile-store.d.ts +16 -0
  103. package/dist/services/bot-profile-store.d.ts.map +1 -0
  104. package/dist/services/bot-profile-store.js +98 -0
  105. package/dist/services/bot-profile-store.js.map +1 -0
  106. package/dist/services/connector-store.d.ts +58 -0
  107. package/dist/services/connector-store.d.ts.map +1 -0
  108. package/dist/services/connector-store.js +79 -0
  109. package/dist/services/connector-store.js.map +1 -0
  110. package/dist/services/deployment-identity.d.ts +22 -0
  111. package/dist/services/deployment-identity.d.ts.map +1 -0
  112. package/dist/services/deployment-identity.js +67 -0
  113. package/dist/services/deployment-identity.js.map +1 -0
  114. package/dist/services/federation-membership-store.d.ts +23 -0
  115. package/dist/services/federation-membership-store.d.ts.map +1 -0
  116. package/dist/services/federation-membership-store.js +66 -0
  117. package/dist/services/federation-membership-store.js.map +1 -0
  118. package/dist/services/federation-roster.d.ts +54 -0
  119. package/dist/services/federation-roster.d.ts.map +1 -0
  120. package/dist/services/federation-roster.js +51 -0
  121. package/dist/services/federation-roster.js.map +1 -0
  122. package/dist/services/federation-store.d.ts +76 -0
  123. package/dist/services/federation-store.d.ts.map +1 -0
  124. package/dist/services/federation-store.js +133 -0
  125. package/dist/services/federation-store.js.map +1 -0
  126. package/dist/services/group-creator.d.ts +6 -0
  127. package/dist/services/group-creator.d.ts.map +1 -1
  128. package/dist/services/group-creator.js +10 -1
  129. package/dist/services/group-creator.js.map +1 -1
  130. package/dist/services/groups-store.d.ts +11 -0
  131. package/dist/services/groups-store.d.ts.map +1 -1
  132. package/dist/services/groups-store.js +42 -0
  133. package/dist/services/groups-store.js.map +1 -1
  134. package/dist/services/invite-store.d.ts +28 -0
  135. package/dist/services/invite-store.d.ts.map +1 -0
  136. package/dist/services/invite-store.js +85 -0
  137. package/dist/services/invite-store.js.map +1 -0
  138. package/dist/services/pairing-store.d.ts +47 -0
  139. package/dist/services/pairing-store.d.ts.map +1 -0
  140. package/dist/services/pairing-store.js +132 -0
  141. package/dist/services/pairing-store.js.map +1 -0
  142. package/dist/services/relay-picker.d.ts +22 -0
  143. package/dist/services/relay-picker.d.ts.map +1 -0
  144. package/dist/services/relay-picker.js +62 -0
  145. package/dist/services/relay-picker.js.map +1 -0
  146. package/dist/services/team-roster.d.ts +38 -0
  147. package/dist/services/team-roster.d.ts.map +1 -0
  148. package/dist/services/team-roster.js +82 -0
  149. package/dist/services/team-roster.js.map +1 -0
  150. package/dist/services/team-store.d.ts +54 -0
  151. package/dist/services/team-store.d.ts.map +1 -0
  152. package/dist/services/team-store.js +156 -0
  153. package/dist/services/team-store.js.map +1 -0
  154. package/dist/services/trigger-log-store.d.ts +46 -0
  155. package/dist/services/trigger-log-store.d.ts.map +1 -0
  156. package/dist/services/trigger-log-store.js +132 -0
  157. package/dist/services/trigger-log-store.js.map +1 -0
  158. package/dist/services/trigger-types.d.ts +57 -0
  159. package/dist/services/trigger-types.d.ts.map +1 -0
  160. package/dist/services/trigger-types.js +28 -0
  161. package/dist/services/trigger-types.js.map +1 -0
  162. package/dist/services/webhook-key.d.ts +16 -0
  163. package/dist/services/webhook-key.d.ts.map +1 -0
  164. package/dist/services/webhook-key.js +123 -0
  165. package/dist/services/webhook-key.js.map +1 -0
  166. package/dist/services/webhook-lifecycle-extractors.d.ts +15 -0
  167. package/dist/services/webhook-lifecycle-extractors.d.ts.map +1 -0
  168. package/dist/services/webhook-lifecycle-extractors.js +59 -0
  169. package/dist/services/webhook-lifecycle-extractors.js.map +1 -0
  170. package/dist/services/webhook-lifecycle-store.d.ts +45 -0
  171. package/dist/services/webhook-lifecycle-store.d.ts.map +1 -0
  172. package/dist/services/webhook-lifecycle-store.js +159 -0
  173. package/dist/services/webhook-lifecycle-store.js.map +1 -0
  174. package/dist/setup/verify-permissions.d.ts.map +1 -1
  175. package/dist/setup/verify-permissions.js +4 -0
  176. package/dist/setup/verify-permissions.js.map +1 -1
  177. package/dist/skills/definitions.d.ts.map +1 -1
  178. package/dist/skills/definitions.js +64 -10
  179. package/dist/skills/definitions.js.map +1 -1
  180. package/dist/types.d.ts +14 -0
  181. package/dist/types.d.ts.map +1 -1
  182. package/dist/utils/daemon-discovery.d.ts +11 -0
  183. package/dist/utils/daemon-discovery.d.ts.map +1 -0
  184. package/dist/utils/daemon-discovery.js +59 -0
  185. package/dist/utils/daemon-discovery.js.map +1 -0
  186. package/dist/workflows/events/payloads.d.ts +2 -2
  187. package/dist/workflows/events/schema.d.ts +8 -8
  188. package/dist/workflows/trigger-from-envelope.d.ts +13 -0
  189. package/dist/workflows/trigger-from-envelope.d.ts.map +1 -0
  190. package/dist/workflows/trigger-from-envelope.js +67 -0
  191. package/dist/workflows/trigger-from-envelope.js.map +1 -0
  192. package/package.json +1 -1
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Team store: the trust boundary for multi-bot collaboration.
3
+ *
4
+ * A "team" is a set of people (members) who trust each other; within a team,
5
+ * bots collaborate freely (discover, team up, hand off) without per-action
6
+ * authorization. Team membership is what the platform login (pairing flow) and
7
+ * the team Web UI gate on.
8
+ *
9
+ * Identity: members are keyed canonically by **union_id** (stable across apps
10
+ * under the same Feishu developer/tenant — see docs/platform-design.md). We also
11
+ * keep open_id / email / name when known so membership checks can match on any
12
+ * identifier the caller has on hand.
13
+ *
14
+ * Deployment model: "one deployment = one implicit team" is the simplest case,
15
+ * so a single default team is auto-materialized on first write. Explicit
16
+ * multi-team support is the same shape, just more than one entry.
17
+ *
18
+ * Storage: `{dataDir}/teams.json`, atomic writes (unique tmp + rename).
19
+ */
20
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, renameSync } from 'node:fs';
21
+ import { join } from 'node:path';
22
+ import { randomUUID } from 'node:crypto';
23
+ export const DEFAULT_TEAM_ID = 'default';
24
+ function filePath(dataDir) {
25
+ return join(dataDir, 'teams.json');
26
+ }
27
+ function readFile(dataDir) {
28
+ const fp = filePath(dataDir);
29
+ if (!existsSync(fp))
30
+ return { version: 1, teams: [] };
31
+ try {
32
+ const parsed = JSON.parse(readFileSync(fp, 'utf-8'));
33
+ if (parsed && Array.isArray(parsed.teams))
34
+ return { version: 1, teams: parsed.teams };
35
+ }
36
+ catch { /* corrupt — fall through */ }
37
+ return { version: 1, teams: [] };
38
+ }
39
+ function writeFileAtomic(dataDir, data) {
40
+ if (!existsSync(dataDir))
41
+ mkdirSync(dataDir, { recursive: true });
42
+ const fp = filePath(dataDir);
43
+ const tmp = `${fp}.${process.pid}.${randomUUID()}.tmp`;
44
+ writeFileSync(tmp, JSON.stringify(data, null, 2) + '\n', 'utf-8');
45
+ renameSync(tmp, fp);
46
+ }
47
+ /** All teams (empty array if none materialized yet). */
48
+ export function listTeams(dataDir) {
49
+ return readFile(dataDir).teams;
50
+ }
51
+ /** A team by id, or null. */
52
+ export function getTeam(dataDir, teamId) {
53
+ return readFile(dataDir).teams.find(t => t.id === teamId) ?? null;
54
+ }
55
+ /** All teams the given identity belongs to (matches any identifier). */
56
+ export function listTeamsForMember(dataDir, id) {
57
+ if (!id.unionId && !id.openId && !id.email)
58
+ return [];
59
+ return readFile(dataDir).teams.filter(t => t.members.some(m => sameMember(m, id)));
60
+ }
61
+ /**
62
+ * The default (implicit single-deployment) team. Read-only: returns the first
63
+ * persisted team, else a synthesized empty default that is NOT written. Use
64
+ * `ensureDefaultTeam` when you intend to persist.
65
+ */
66
+ export function getDefaultTeam(dataDir) {
67
+ const teams = readFile(dataDir).teams;
68
+ const existing = teams.find(t => t.id === DEFAULT_TEAM_ID) ?? teams[0];
69
+ if (existing)
70
+ return existing;
71
+ const now = Date.now();
72
+ return { id: DEFAULT_TEAM_ID, name: '默认团队', members: [], createdAt: now, updatedAt: now };
73
+ }
74
+ /** Materialize (persist) the default team if no team exists yet; returns it. */
75
+ export function ensureDefaultTeam(dataDir, now = Date.now()) {
76
+ const data = readFile(dataDir);
77
+ if (data.teams.length > 0)
78
+ return data.teams.find(t => t.id === DEFAULT_TEAM_ID) ?? data.teams[0];
79
+ const team = { id: DEFAULT_TEAM_ID, name: '默认团队', members: [], createdAt: now, updatedAt: now };
80
+ data.teams.push(team);
81
+ writeFileAtomic(dataDir, data);
82
+ return team;
83
+ }
84
+ /** Delete a team entirely (members + the team entry). Returns true if removed.
85
+ * Bots/connectors live at the deployment level (not per-team), so they are
86
+ * unaffected — only the membership/trust boundary is dropped. */
87
+ export function deleteTeam(dataDir, teamId) {
88
+ const data = readFile(dataDir);
89
+ const before = data.teams.length;
90
+ data.teams = data.teams.filter(t => t.id !== teamId);
91
+ if (data.teams.length === before)
92
+ return false;
93
+ writeFileAtomic(dataDir, data);
94
+ return true;
95
+ }
96
+ /** Create a new explicit team. */
97
+ export function createTeam(dataDir, name, now = Date.now()) {
98
+ const data = readFile(dataDir);
99
+ const team = { id: `team_${randomUUID().slice(0, 8)}`, name: name.trim() || '未命名团队', members: [], createdAt: now, updatedAt: now };
100
+ data.teams.push(team);
101
+ writeFileAtomic(dataDir, data);
102
+ return team;
103
+ }
104
+ function sameMember(m, id) {
105
+ return (!!id.unionId && m.unionId === id.unionId)
106
+ || (!!id.openId && m.openId === id.openId)
107
+ || (!!id.email && m.email === id.email);
108
+ }
109
+ /**
110
+ * Add (or merge) a member into a team. Dedupes by any matching identifier and
111
+ * fills in newly-known fields. Returns the updated team, or null if no such team.
112
+ */
113
+ export function addMember(dataDir, teamId, member, now = Date.now()) {
114
+ const data = readFile(dataDir);
115
+ const team = data.teams.find(t => t.id === teamId);
116
+ if (!team)
117
+ return null;
118
+ const existing = team.members.find(m => sameMember(m, member));
119
+ if (existing) {
120
+ existing.unionId ??= member.unionId;
121
+ existing.openId ??= member.openId;
122
+ existing.email ??= member.email;
123
+ if (member.name)
124
+ existing.name = member.name;
125
+ }
126
+ else {
127
+ team.members.push({ ...member, addedAt: member.addedAt ?? now });
128
+ }
129
+ team.updatedAt = now;
130
+ writeFileAtomic(dataDir, data);
131
+ return team;
132
+ }
133
+ /** Remove a member matching any identifier. Returns true if removed. */
134
+ export function removeMember(dataDir, teamId, id, now = Date.now()) {
135
+ const data = readFile(dataDir);
136
+ const team = data.teams.find(t => t.id === teamId);
137
+ if (!team)
138
+ return false;
139
+ const before = team.members.length;
140
+ team.members = team.members.filter(m => !sameMember(m, id));
141
+ if (team.members.length === before)
142
+ return false;
143
+ team.updatedAt = now;
144
+ writeFileAtomic(dataDir, data);
145
+ return true;
146
+ }
147
+ /** Whether the given identity is a member of the team (matches any identifier). */
148
+ export function isMember(dataDir, teamId, id) {
149
+ if (!id.unionId && !id.openId && !id.email)
150
+ return false;
151
+ const team = getTeam(dataDir, teamId);
152
+ if (!team)
153
+ return false;
154
+ return team.members.some(m => sameMember(m, id));
155
+ }
156
+ //# sourceMappingURL=team-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-store.js","sourceRoot":"","sources":["../../src/services/team-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { TriggerAction, TriggerErrorCode } from './trigger-types.js';
2
+ export interface TriggerLogEntry {
3
+ triggerId: string;
4
+ connectorId?: string;
5
+ action: TriggerAction | 'failed';
6
+ status: 'ok' | 'error';
7
+ error?: string;
8
+ errorCode?: TriggerErrorCode;
9
+ createdAt: string;
10
+ }
11
+ export interface TriggerLogListOptions {
12
+ limit?: number;
13
+ connectorId?: string;
14
+ status?: TriggerLogEntry['status'];
15
+ errorCode?: TriggerErrorCode;
16
+ since?: string | Date;
17
+ }
18
+ export interface TriggerLogStats {
19
+ connectorId?: string;
20
+ total: number;
21
+ ok: number;
22
+ error: number;
23
+ actions: Partial<Record<TriggerLogEntry['action'], number>>;
24
+ errorCodes: Partial<Record<TriggerErrorCode, number>>;
25
+ lastTriggeredAt?: string;
26
+ lastOkAt?: string;
27
+ lastErrorAt?: string;
28
+ lastError?: string;
29
+ lastErrorCode?: TriggerErrorCode;
30
+ }
31
+ export interface TriggerLogPruneResult {
32
+ before: number;
33
+ after: number;
34
+ deleted: number;
35
+ }
36
+ export declare function appendTriggerLog(entry: Omit<TriggerLogEntry, 'createdAt'> & {
37
+ createdAt?: string;
38
+ }, dataDir?: string): TriggerLogEntry;
39
+ export declare function listTriggerLogs(opts?: TriggerLogListOptions, dataDir?: string): TriggerLogEntry[];
40
+ export declare function summarizeTriggerLogs(opts?: Pick<TriggerLogListOptions, 'connectorId' | 'since'>, dataDir?: string): TriggerLogStats[];
41
+ export declare function pruneTriggerLogs(opts?: {
42
+ retentionDays?: number;
43
+ maxEntries?: number;
44
+ now?: Date | string | number;
45
+ }, dataDir?: string): TriggerLogPruneResult;
46
+ //# sourceMappingURL=trigger-log-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trigger-log-store.d.ts","sourceRoot":"","sources":["../../src/services/trigger-log-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE1E,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,QAAQ,CAAC;IACjC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;IACnC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5D,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAClC;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AA2CD,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,EAClE,OAAO,GAAE,MAA+B,GACvC,eAAe,CAMjB;AAED,wBAAgB,eAAe,CAC7B,IAAI,GAAE,qBAA0B,EAChC,OAAO,GAAE,MAA+B,GACvC,eAAe,EAAE,CAQnB;AAED,wBAAgB,oBAAoB,CAClC,IAAI,GAAE,IAAI,CAAC,qBAAqB,EAAE,aAAa,GAAG,OAAO,CAAM,EAC/D,OAAO,GAAE,MAA+B,GACvC,eAAe,EAAE,CAgCnB;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAA;CAAO,EACxF,OAAO,GAAE,MAA+B,GACvC,qBAAqB,CAiCvB"}
@@ -0,0 +1,132 @@
1
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { dirname, join } from 'node:path';
4
+ import { config } from '../config.js';
5
+ function logPath(dataDir = config.session.dataDir) {
6
+ return join(dataDir, 'trigger-logs.jsonl');
7
+ }
8
+ function normalizeLimit(limit, fallback = 100, max = 1000) {
9
+ const n = typeof limit === 'number' ? limit : Number(limit);
10
+ if (!Number.isFinite(n))
11
+ return fallback;
12
+ return Math.max(1, Math.min(Math.floor(n), max));
13
+ }
14
+ function sinceMs(since) {
15
+ if (!since)
16
+ return undefined;
17
+ const ms = since instanceof Date ? since.getTime() : Date.parse(since);
18
+ return Number.isFinite(ms) ? ms : undefined;
19
+ }
20
+ function readTriggerLogEntries(dataDir = config.session.dataDir) {
21
+ const fp = logPath(dataDir);
22
+ if (!existsSync(fp))
23
+ return [];
24
+ const out = [];
25
+ const lines = readFileSync(fp, 'utf-8').split(/\r?\n/).filter(Boolean);
26
+ for (const line of lines) {
27
+ try {
28
+ out.push(JSON.parse(line));
29
+ }
30
+ catch { /* ignore corrupt line */ }
31
+ }
32
+ return out;
33
+ }
34
+ function matchesFilter(entry, opts) {
35
+ if (opts.connectorId && entry.connectorId !== opts.connectorId)
36
+ return false;
37
+ if (opts.status && entry.status !== opts.status)
38
+ return false;
39
+ if (opts.errorCode && entry.errorCode !== opts.errorCode)
40
+ return false;
41
+ const minMs = sinceMs(opts.since);
42
+ if (minMs !== undefined) {
43
+ const createdMs = Date.parse(entry.createdAt);
44
+ if (!Number.isFinite(createdMs) || createdMs < minMs)
45
+ return false;
46
+ }
47
+ return true;
48
+ }
49
+ export function appendTriggerLog(entry, dataDir = config.session.dataDir) {
50
+ const full = { ...entry, createdAt: entry.createdAt ?? new Date().toISOString() };
51
+ const fp = logPath(dataDir);
52
+ mkdirSync(dirname(fp), { recursive: true });
53
+ appendFileSync(fp, JSON.stringify(full) + '\n', 'utf-8');
54
+ return full;
55
+ }
56
+ export function listTriggerLogs(opts = {}, dataDir = config.session.dataDir) {
57
+ const limit = normalizeLimit(opts.limit);
58
+ const out = [];
59
+ const entries = readTriggerLogEntries(dataDir);
60
+ for (let i = entries.length - 1; i >= 0 && out.length < limit; i--) {
61
+ if (matchesFilter(entries[i], opts))
62
+ out.push(entries[i]);
63
+ }
64
+ return out;
65
+ }
66
+ export function summarizeTriggerLogs(opts = {}, dataDir = config.session.dataDir) {
67
+ const groups = new Map();
68
+ for (const entry of readTriggerLogEntries(dataDir)) {
69
+ if (!matchesFilter(entry, opts))
70
+ continue;
71
+ const key = entry.connectorId ?? '';
72
+ let stat = groups.get(key);
73
+ if (!stat) {
74
+ stat = {
75
+ ...(entry.connectorId ? { connectorId: entry.connectorId } : {}),
76
+ total: 0,
77
+ ok: 0,
78
+ error: 0,
79
+ actions: {},
80
+ errorCodes: {},
81
+ };
82
+ groups.set(key, stat);
83
+ }
84
+ stat.total += 1;
85
+ stat[entry.status] += 1;
86
+ stat.actions[entry.action] = (stat.actions[entry.action] ?? 0) + 1;
87
+ stat.lastTriggeredAt = entry.createdAt;
88
+ if (entry.status === 'ok')
89
+ stat.lastOkAt = entry.createdAt;
90
+ if (entry.status === 'error') {
91
+ stat.lastErrorAt = entry.createdAt;
92
+ stat.lastError = entry.error;
93
+ if (entry.errorCode) {
94
+ stat.lastErrorCode = entry.errorCode;
95
+ stat.errorCodes[entry.errorCode] = (stat.errorCodes[entry.errorCode] ?? 0) + 1;
96
+ }
97
+ }
98
+ }
99
+ return [...groups.values()];
100
+ }
101
+ export function pruneTriggerLogs(opts = {}, dataDir = config.session.dataDir) {
102
+ const entries = readTriggerLogEntries(dataDir);
103
+ const before = entries.length;
104
+ const retentionDays = opts.retentionDays === undefined ? undefined : normalizeLimit(opts.retentionDays, 1, 3650);
105
+ const maxEntries = opts.maxEntries === undefined ? undefined : normalizeLimit(opts.maxEntries, before || 1, 1_000_000);
106
+ const nowMs = opts.now instanceof Date ? opts.now.getTime()
107
+ : typeof opts.now === 'string' ? Date.parse(opts.now)
108
+ : typeof opts.now === 'number' ? opts.now
109
+ : Date.now();
110
+ const cutoffMs = retentionDays === undefined || !Number.isFinite(nowMs)
111
+ ? undefined
112
+ : nowMs - retentionDays * 24 * 60 * 60 * 1000;
113
+ let kept = cutoffMs === undefined
114
+ ? entries
115
+ : entries.filter(entry => {
116
+ const createdMs = Date.parse(entry.createdAt);
117
+ return !Number.isFinite(createdMs) || createdMs >= cutoffMs;
118
+ });
119
+ if (maxEntries !== undefined && kept.length > maxEntries) {
120
+ kept = kept.slice(kept.length - maxEntries);
121
+ }
122
+ const fp = logPath(dataDir);
123
+ mkdirSync(dirname(fp), { recursive: true });
124
+ const tmp = `${fp}.${process.pid}.${randomUUID()}.tmp`;
125
+ writeFileSync(tmp, kept.map(entry => JSON.stringify(entry)).join('\n') + (kept.length ? '\n' : ''), {
126
+ encoding: 'utf-8',
127
+ mode: 0o600,
128
+ });
129
+ renameSync(tmp, fp);
130
+ return { before, after: kept.length, deleted: before - kept.length };
131
+ }
132
+ //# sourceMappingURL=trigger-log-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trigger-log-store.js","sourceRoot":"","sources":["../../src/services/trigger-log-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ export type TriggerSourceType = 'webhook' | 'ui' | 'workflow' | 'schedule';
2
+ export type TriggerTargetKind = 'turn' | 'workflow';
3
+ export type TriggerAction = 'queued' | 'delivered' | 'dry_run' | 'ignored';
4
+ export interface TriggerRequest {
5
+ source: {
6
+ type: TriggerSourceType;
7
+ connectorId?: string;
8
+ requestId?: string;
9
+ receivedAt?: string;
10
+ };
11
+ target: {
12
+ kind: TriggerTargetKind;
13
+ botId?: string;
14
+ chatId?: string;
15
+ sessionId?: string;
16
+ workflowId?: string;
17
+ };
18
+ envelope: {
19
+ format: string;
20
+ sourceName: string;
21
+ trusted: false;
22
+ headers?: Record<string, unknown>;
23
+ payload?: unknown;
24
+ rawText?: string;
25
+ };
26
+ options?: {
27
+ dryRun?: boolean;
28
+ dedupKey?: string;
29
+ status?: 'firing' | 'resolved' | string;
30
+ };
31
+ }
32
+ export type TriggerErrorCode = 'bad_json' | 'bad_request' | 'bot_not_found' | 'bot_not_in_chat' | 'daemon_offline' | 'dry_run' | 'invalid_signature' | 'chat_not_allowed' | 'group_create_failed' | 'lifecycle_extract_failed' | 'rate_limited' | 'replay' | 'session_not_found' | 'target_required' | 'trigger_failed' | 'workflow_trigger_not_implemented';
33
+ export interface TriggerResponse {
34
+ ok: boolean;
35
+ triggerId?: string;
36
+ action?: TriggerAction;
37
+ target?: {
38
+ kind: TriggerTargetKind;
39
+ sessionId?: string;
40
+ workflowRunId?: string;
41
+ chatId?: string;
42
+ };
43
+ message?: string;
44
+ errorCode?: TriggerErrorCode;
45
+ error?: string;
46
+ promptPreview?: string;
47
+ }
48
+ export declare function isRecord(v: unknown): v is Record<string, unknown>;
49
+ export declare function validateTriggerRequest(raw: unknown): {
50
+ ok: true;
51
+ request: TriggerRequest;
52
+ } | {
53
+ ok: false;
54
+ status: number;
55
+ body: TriggerResponse;
56
+ };
57
+ //# sourceMappingURL=trigger-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trigger-types.d.ts","sourceRoot":"","sources":["../../src/services/trigger-types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,IAAI,GAAG,UAAU,GAAG,UAAU,CAAC;AAC3E,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,UAAU,CAAC;AACpD,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;AAE3E,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE;QACN,IAAI,EAAE,iBAAiB,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,MAAM,EAAE;QACN,IAAI,EAAE,iBAAiB,CAAC;QACxB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,KAAK,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAClC,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;KACzC,CAAC;CACH;AAED,MAAM,MAAM,gBAAgB,GACxB,UAAU,GACV,aAAa,GACb,eAAe,GACf,iBAAiB,GACjB,gBAAgB,GAChB,SAAS,GACT,mBAAmB,GACnB,kBAAkB,GAClB,qBAAqB,GACrB,0BAA0B,GAC1B,cAAc,GACd,QAAQ,GACR,mBAAmB,GACnB,iBAAiB,GACjB,gBAAgB,GAChB,kCAAkC,CAAC;AAEvC,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,iBAAiB,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEjE;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,CAuBjJ"}
@@ -0,0 +1,28 @@
1
+ export function isRecord(v) {
2
+ return !!v && typeof v === 'object' && !Array.isArray(v);
3
+ }
4
+ export function validateTriggerRequest(raw) {
5
+ if (!isRecord(raw)) {
6
+ return { ok: false, status: 400, body: { ok: false, errorCode: 'bad_request', error: 'request body must be an object' } };
7
+ }
8
+ const source = raw.source;
9
+ const target = raw.target;
10
+ const envelope = raw.envelope;
11
+ if (!isRecord(source) || !isRecord(target) || !isRecord(envelope)) {
12
+ return { ok: false, status: 400, body: { ok: false, errorCode: 'bad_request', error: 'source, target, and envelope are required objects' } };
13
+ }
14
+ if (target.kind !== 'turn' && target.kind !== 'workflow') {
15
+ return { ok: false, status: 400, body: { ok: false, errorCode: 'target_required', error: 'target.kind must be turn or workflow' } };
16
+ }
17
+ if (target.kind === 'turn' && typeof target.chatId !== 'string' && typeof target.sessionId !== 'string') {
18
+ return { ok: false, status: 400, body: { ok: false, errorCode: 'target_required', error: 'turn target requires chatId or sessionId' } };
19
+ }
20
+ if (target.kind === 'workflow' && typeof target.workflowId !== 'string') {
21
+ return { ok: false, status: 400, body: { ok: false, errorCode: 'target_required', error: 'workflow target requires workflowId' } };
22
+ }
23
+ if (typeof envelope.sourceName !== 'string' || envelope.trusted !== false) {
24
+ return { ok: false, status: 400, body: { ok: false, errorCode: 'bad_request', error: 'envelope.sourceName is required and envelope.trusted must be false' } };
25
+ }
26
+ return { ok: true, request: raw };
27
+ }
28
+ //# sourceMappingURL=trigger-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trigger-types.js","sourceRoot":"","sources":["../../src/services/trigger-types.ts"],"names":[],"mappings":"AAmEA,MAAM,UAAU,QAAQ,CAAC,CAAU;IACjC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,GAAY;IACjD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,gCAAgC,EAAE,EAAE,CAAC;IAC5H,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAC1B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAC1B,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IAC9B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,mDAAmD,EAAE,EAAE,CAAC;IAC/I,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACzD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,KAAK,EAAE,sCAAsC,EAAE,EAAE,CAAC;IACtI,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QACxG,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,KAAK,EAAE,0CAA0C,EAAE,EAAE,CAAC;IAC1I,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;QACxE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,KAAK,EAAE,qCAAqC,EAAE,EAAE,CAAC;IACrI,CAAC;IACD,IAAI,OAAO,QAAQ,CAAC,UAAU,KAAK,QAAQ,IAAI,QAAQ,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC1E,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,oEAAoE,EAAE,EAAE,CAAC;IAChK,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAgC,EAAE,CAAC;AACjE,CAAC"}
@@ -0,0 +1,16 @@
1
+ export interface WebhookSecretRecord {
2
+ ref: string;
3
+ alg: 'aes-256-gcm';
4
+ iv: string;
5
+ tag: string;
6
+ ciphertext: string;
7
+ createdAt: string;
8
+ updatedAt: string;
9
+ }
10
+ export declare function createWebhookSecret(plaintext: string, dataDir?: string): WebhookSecretRecord;
11
+ export declare function generateWebhookSecretPlaintext(): string;
12
+ export declare function setWebhookSecret(ref: string, plaintext: string, dataDir?: string): WebhookSecretRecord;
13
+ export declare function getWebhookSecret(ref: string, dataDir?: string): string | null;
14
+ export declare function deleteWebhookSecret(ref: string, dataDir?: string): boolean;
15
+ export declare function listWebhookSecretRefs(dataDir?: string): Array<Omit<WebhookSecretRecord, 'iv' | 'tag' | 'ciphertext'>>;
16
+ //# sourceMappingURL=webhook-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-key.d.ts","sourceRoot":"","sources":["../../src/services/webhook-key.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,aAAa,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAiFD,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,MAA+B,GACvC,mBAAmB,CAGrB;AAED,wBAAgB,8BAA8B,IAAI,MAAM,CAEvD;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,MAA+B,GACvC,mBAAmB,CAgBrB;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,MAA+B,GACvC,MAAM,GAAG,IAAI,CAKf;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,MAA+B,GAAG,OAAO,CAMlG;AAED,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,MAA+B,GAAG,KAAK,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,GAAG,KAAK,GAAG,YAAY,CAAC,CAAC,CAG7I"}
@@ -0,0 +1,123 @@
1
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { createCipheriv, createDecipheriv, randomBytes, randomUUID } from 'node:crypto';
4
+ import { config } from '../config.js';
5
+ const MASTER_KEY_FILE = 'webhook-master.key';
6
+ const SECRETS_FILE = 'webhook-secrets.json';
7
+ function masterKeyPath(dataDir) {
8
+ return join(dataDir, MASTER_KEY_FILE);
9
+ }
10
+ function secretStorePath(dataDir) {
11
+ return join(dataDir, SECRETS_FILE);
12
+ }
13
+ function readOrCreateMasterKey(dataDir) {
14
+ const fp = masterKeyPath(dataDir);
15
+ if (existsSync(fp)) {
16
+ const raw = readFileSync(fp, 'utf-8').trim();
17
+ const key = Buffer.from(raw, 'base64url');
18
+ if (key.length !== 32)
19
+ throw new Error(`invalid webhook master key length at ${fp}`);
20
+ return key;
21
+ }
22
+ mkdirSync(dirname(fp), { recursive: true });
23
+ const key = randomBytes(32);
24
+ writeFileSync(fp, key.toString('base64url') + '\n', { encoding: 'utf-8', mode: 0o600 });
25
+ chmodSync(fp, 0o600);
26
+ return key;
27
+ }
28
+ function emptyStore() {
29
+ return { version: 1, secrets: {} };
30
+ }
31
+ function readStore(dataDir) {
32
+ const fp = secretStorePath(dataDir);
33
+ if (!existsSync(fp))
34
+ return emptyStore();
35
+ try {
36
+ const parsed = JSON.parse(readFileSync(fp, 'utf-8'));
37
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
38
+ const secrets = parsed.secrets;
39
+ return {
40
+ version: 1,
41
+ secrets: secrets && typeof secrets === 'object' && !Array.isArray(secrets) ? secrets : {},
42
+ };
43
+ }
44
+ }
45
+ catch { /* corrupt store falls through to empty */ }
46
+ return emptyStore();
47
+ }
48
+ function writeStore(dataDir, store) {
49
+ const fp = secretStorePath(dataDir);
50
+ mkdirSync(dirname(fp), { recursive: true });
51
+ const tmp = `${fp}.${process.pid}.${randomUUID()}.tmp`;
52
+ writeFileSync(tmp, JSON.stringify({ version: 1, secrets: store.secrets }, null, 2) + '\n', { encoding: 'utf-8', mode: 0o600 });
53
+ renameSync(tmp, fp);
54
+ }
55
+ function encryptSecret(plaintext, key) {
56
+ const iv = randomBytes(12);
57
+ const cipher = createCipheriv('aes-256-gcm', key, iv);
58
+ const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf-8'), cipher.final()]);
59
+ const tag = cipher.getAuthTag();
60
+ return {
61
+ alg: 'aes-256-gcm',
62
+ iv: iv.toString('base64url'),
63
+ tag: tag.toString('base64url'),
64
+ ciphertext: ciphertext.toString('base64url'),
65
+ };
66
+ }
67
+ function decryptSecret(record, key) {
68
+ if (record.alg !== 'aes-256-gcm')
69
+ throw new Error(`unsupported webhook secret alg: ${record.alg}`);
70
+ const decipher = createDecipheriv('aes-256-gcm', key, Buffer.from(record.iv, 'base64url'));
71
+ decipher.setAuthTag(Buffer.from(record.tag, 'base64url'));
72
+ return Buffer.concat([
73
+ decipher.update(Buffer.from(record.ciphertext, 'base64url')),
74
+ decipher.final(),
75
+ ]).toString('utf-8');
76
+ }
77
+ export function createWebhookSecret(plaintext, dataDir = config.session.dataDir) {
78
+ const ref = `whsec_${randomUUID()}`;
79
+ return setWebhookSecret(ref, plaintext, dataDir);
80
+ }
81
+ export function generateWebhookSecretPlaintext() {
82
+ return randomBytes(32).toString('base64url');
83
+ }
84
+ export function setWebhookSecret(ref, plaintext, dataDir = config.session.dataDir) {
85
+ if (!ref)
86
+ throw new Error('secret ref is required');
87
+ if (!plaintext)
88
+ throw new Error('secret plaintext is required');
89
+ const key = readOrCreateMasterKey(dataDir);
90
+ const store = readStore(dataDir);
91
+ const now = new Date().toISOString();
92
+ const prior = store.secrets[ref];
93
+ const record = {
94
+ ref,
95
+ ...encryptSecret(plaintext, key),
96
+ createdAt: prior?.createdAt ?? now,
97
+ updatedAt: now,
98
+ };
99
+ store.secrets[ref] = record;
100
+ writeStore(dataDir, store);
101
+ return record;
102
+ }
103
+ export function getWebhookSecret(ref, dataDir = config.session.dataDir) {
104
+ if (!ref)
105
+ return null;
106
+ const record = readStore(dataDir).secrets[ref];
107
+ if (!record)
108
+ return null;
109
+ return decryptSecret(record, readOrCreateMasterKey(dataDir));
110
+ }
111
+ export function deleteWebhookSecret(ref, dataDir = config.session.dataDir) {
112
+ const store = readStore(dataDir);
113
+ if (!store.secrets[ref])
114
+ return false;
115
+ delete store.secrets[ref];
116
+ writeStore(dataDir, store);
117
+ return true;
118
+ }
119
+ export function listWebhookSecretRefs(dataDir = config.session.dataDir) {
120
+ return Object.values(readStore(dataDir).secrets)
121
+ .map(({ iv: _iv, tag: _tag, ciphertext: _ciphertext, ...meta }) => meta);
122
+ }
123
+ //# sourceMappingURL=webhook-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-key.js","sourceRoot":"","sources":["../../src/services/webhook-key.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,UAAU,EACV,SAAS,EACT,YAAY,EACZ,UAAU,EACV,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAC7C,MAAM,YAAY,GAAG,sBAAsB,CAAC;AAiB5C,SAAS,aAAa,CAAC,OAAe;IACpC,OAAO,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,eAAe,CAAC,OAAe;IACtC,OAAO,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAe;IAC5C,MAAM,EAAE,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC1C,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,EAAE,EAAE,CAAC,CAAC;QACrF,OAAO,GAAG,CAAC;IACb,CAAC;IACD,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAC5B,aAAa,CAAC,EAAE,EAAE,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACxF,SAAS,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IACrB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AACrC,CAAC;AAED,SAAS,SAAS,CAAC,OAAe;IAChC,MAAM,EAAE,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAAE,OAAO,UAAU,EAAE,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;QACrD,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,MAAM,OAAO,GAAI,MAAc,CAAC,OAAO,CAAC;YACxC,OAAO;gBACL,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;aAC1F,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,0CAA0C,CAAC,CAAC;IACtD,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,UAAU,CAAC,OAAe,EAAE,KAAsB;IACzD,MAAM,EAAE,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACpC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,GAAG,EAAE,IAAI,OAAO,CAAC,GAAG,IAAI,UAAU,EAAE,MAAM,CAAC;IACvD,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/H,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AACtB,CAAC;AAED,SAAS,aAAa,CAAC,SAAiB,EAAE,GAAW;IACnD,MAAM,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAC3B,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACtF,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IAChC,OAAO;QACL,GAAG,EAAE,aAAa;QAClB,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;QAC5B,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC;QAC9B,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,WAAW,CAAC;KAC7C,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,MAA2B,EAAE,GAAW;IAC7D,IAAI,MAAM,CAAC,GAAG,KAAK,aAAa;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IACnG,MAAM,QAAQ,GAAG,gBAAgB,CAAC,aAAa,EAAE,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;IAC3F,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;IAC1D,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QAC5D,QAAQ,CAAC,KAAK,EAAE;KACjB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,SAAiB,EACjB,UAAkB,MAAM,CAAC,OAAO,CAAC,OAAO;IAExC,MAAM,GAAG,GAAG,SAAS,UAAU,EAAE,EAAE,CAAC;IACpC,OAAO,gBAAgB,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,8BAA8B;IAC5C,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,GAAW,EACX,SAAiB,EACjB,UAAkB,MAAM,CAAC,OAAO,CAAC,OAAO;IAExC,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IACpD,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAChE,MAAM,GAAG,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IACjC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,MAAM,GAAwB;QAClC,GAAG;QACH,GAAG,aAAa,CAAC,SAAS,EAAE,GAAG,CAAC;QAChC,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,GAAG;QAClC,SAAS,EAAE,GAAG;KACf,CAAC;IACF,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;IAC5B,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC3B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,GAAW,EACX,UAAkB,MAAM,CAAC,OAAO,CAAC,OAAO;IAExC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,OAAO,aAAa,CAAC,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAE,UAAkB,MAAM,CAAC,OAAO,CAAC,OAAO;IACvF,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1B,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC3B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,UAAkB,MAAM,CAAC,OAAO,CAAC,OAAO;IAC5E,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;SAC7C,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AAC7E,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { ConnectorDefinition } from './connector-store.js';
2
+ export type ExtractedLifecycleStatus = 'firing' | 'resolved';
3
+ export interface ExtractedWebhookLifecycle {
4
+ dedupKey: string;
5
+ status: ExtractedLifecycleStatus;
6
+ }
7
+ export declare function getJsonPathValue(input: unknown, path: string): unknown;
8
+ export declare function extractWebhookLifecycle(payload: unknown, extractors: ConnectorDefinition['lifecycleExtractors']): {
9
+ ok: true;
10
+ lifecycle: ExtractedWebhookLifecycle;
11
+ } | {
12
+ ok: false;
13
+ error: string;
14
+ };
15
+ //# sourceMappingURL=webhook-lifecycle-extractors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-lifecycle-extractors.d.ts","sourceRoot":"","sources":["../../src/services/webhook-lifecycle-extractors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,MAAM,MAAM,wBAAwB,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE7D,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,wBAAwB,CAAC;CAClC;AAeD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAStE;AAiBD,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,mBAAmB,CAAC,qBAAqB,CAAC,GACrD;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,yBAAyB,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CASnF"}