@loom-framework/core 0.1.0-alpha.150 → 0.1.0-alpha.152

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 (165) hide show
  1. package/builtin-skills/app-skill/SKILL.md +16 -5
  2. package/builtin-skills/app-skill/references/auth.md +23 -19
  3. package/builtin-skills/app-skill/references/events.md +119 -0
  4. package/builtin-skills/app-skill/references/evolution.md +90 -0
  5. package/builtin-skills/app-skill/references/process-builder.md +140 -0
  6. package/builtin-skills/app-skill/references/process-metrics.md +93 -0
  7. package/builtin-skills/app-skill/references/process.md +222 -0
  8. package/builtin-skills/loom/SKILL.md +9 -7
  9. package/dist/backend/auth/request-context.d.ts +15 -0
  10. package/dist/backend/auth/request-context.d.ts.map +1 -0
  11. package/dist/backend/auth/request-context.js +17 -0
  12. package/dist/backend/auth/request-context.js.map +1 -0
  13. package/dist/backend/events/event-bus.d.ts +39 -0
  14. package/dist/backend/events/event-bus.d.ts.map +1 -0
  15. package/dist/backend/events/event-bus.js +182 -0
  16. package/dist/backend/events/event-bus.js.map +1 -0
  17. package/dist/backend/events/event-emitting-adapter.d.ts +31 -0
  18. package/dist/backend/events/event-emitting-adapter.d.ts.map +1 -0
  19. package/dist/backend/events/event-emitting-adapter.js +70 -0
  20. package/dist/backend/events/event-emitting-adapter.js.map +1 -0
  21. package/dist/backend/events/event-registry.d.ts +24 -0
  22. package/dist/backend/events/event-registry.d.ts.map +1 -0
  23. package/dist/backend/events/event-registry.js +22 -0
  24. package/dist/backend/events/event-registry.js.map +1 -0
  25. package/dist/backend/events/index.d.ts +7 -0
  26. package/dist/backend/events/index.d.ts.map +1 -0
  27. package/dist/backend/events/index.js +7 -0
  28. package/dist/backend/events/index.js.map +1 -0
  29. package/dist/backend/index.d.ts +12 -0
  30. package/dist/backend/index.d.ts.map +1 -1
  31. package/dist/backend/index.js +143 -3
  32. package/dist/backend/index.js.map +1 -1
  33. package/dist/backend/process/engine.d.ts +84 -0
  34. package/dist/backend/process/engine.d.ts.map +1 -0
  35. package/dist/backend/process/engine.js +511 -0
  36. package/dist/backend/process/engine.js.map +1 -0
  37. package/dist/backend/process/index.d.ts +7 -0
  38. package/dist/backend/process/index.d.ts.map +1 -0
  39. package/dist/backend/process/index.js +6 -0
  40. package/dist/backend/process/index.js.map +1 -0
  41. package/dist/backend/process/logger.d.ts +30 -0
  42. package/dist/backend/process/logger.d.ts.map +1 -0
  43. package/dist/backend/process/logger.js +132 -0
  44. package/dist/backend/process/logger.js.map +1 -0
  45. package/dist/backend/process/queue.d.ts +31 -0
  46. package/dist/backend/process/queue.d.ts.map +1 -0
  47. package/dist/backend/process/queue.js +80 -0
  48. package/dist/backend/process/queue.js.map +1 -0
  49. package/dist/backend/process/registry.d.ts +25 -0
  50. package/dist/backend/process/registry.d.ts.map +1 -0
  51. package/dist/backend/process/registry.js +98 -0
  52. package/dist/backend/process/registry.js.map +1 -0
  53. package/dist/backend/process/trigger.d.ts +29 -0
  54. package/dist/backend/process/trigger.d.ts.map +1 -0
  55. package/dist/backend/process/trigger.js +108 -0
  56. package/dist/backend/process/trigger.js.map +1 -0
  57. package/dist/backend/routes/ai-config.d.ts +2 -0
  58. package/dist/backend/routes/ai-config.d.ts.map +1 -1
  59. package/dist/backend/routes/ai-config.js +2 -1
  60. package/dist/backend/routes/ai-config.js.map +1 -1
  61. package/dist/backend/routes/auth-routes.d.ts +7 -0
  62. package/dist/backend/routes/auth-routes.d.ts.map +1 -1
  63. package/dist/backend/routes/auth-routes.js +228 -1
  64. package/dist/backend/routes/auth-routes.js.map +1 -1
  65. package/dist/backend/routes/chat.d.ts +2 -0
  66. package/dist/backend/routes/chat.d.ts.map +1 -1
  67. package/dist/backend/routes/chat.js +3 -2
  68. package/dist/backend/routes/chat.js.map +1 -1
  69. package/dist/backend/routes/data.d.ts +2 -1
  70. package/dist/backend/routes/data.d.ts.map +1 -1
  71. package/dist/backend/routes/data.js +7 -1
  72. package/dist/backend/routes/data.js.map +1 -1
  73. package/dist/backend/routes/event-routes.d.ts +15 -0
  74. package/dist/backend/routes/event-routes.d.ts.map +1 -0
  75. package/dist/backend/routes/event-routes.js +35 -0
  76. package/dist/backend/routes/event-routes.js.map +1 -0
  77. package/dist/backend/routes/index.d.ts +4 -0
  78. package/dist/backend/routes/index.d.ts.map +1 -1
  79. package/dist/backend/routes/index.js +2 -0
  80. package/dist/backend/routes/index.js.map +1 -1
  81. package/dist/backend/routes/process-routes.d.ts +15 -0
  82. package/dist/backend/routes/process-routes.d.ts.map +1 -0
  83. package/dist/backend/routes/process-routes.js +237 -0
  84. package/dist/backend/routes/process-routes.js.map +1 -0
  85. package/dist/backend/routes/session-routes.d.ts +2 -0
  86. package/dist/backend/routes/session-routes.d.ts.map +1 -1
  87. package/dist/backend/routes/session-routes.js +4 -1
  88. package/dist/backend/routes/session-routes.js.map +1 -1
  89. package/dist/backend/routes/skills.d.ts +2 -0
  90. package/dist/backend/routes/skills.d.ts.map +1 -1
  91. package/dist/backend/routes/skills.js +4 -0
  92. package/dist/backend/routes/skills.js.map +1 -1
  93. package/dist/cli/commands/auth.d.ts.map +1 -1
  94. package/dist/cli/commands/auth.js +30 -22
  95. package/dist/cli/commands/auth.js.map +1 -1
  96. package/dist/cli/commands/data.d.ts.map +1 -1
  97. package/dist/cli/commands/data.js +47 -44
  98. package/dist/cli/commands/data.js.map +1 -1
  99. package/dist/cli/commands/generate-system-settings.d.ts +3 -2
  100. package/dist/cli/commands/generate-system-settings.d.ts.map +1 -1
  101. package/dist/cli/commands/generate-system-settings.js +50 -7
  102. package/dist/cli/commands/generate-system-settings.js.map +1 -1
  103. package/dist/cli/commands/init.js +1 -1
  104. package/dist/cli/commands/init.js.map +1 -1
  105. package/dist/cli/commands/process.d.ts +8 -0
  106. package/dist/cli/commands/process.d.ts.map +1 -0
  107. package/dist/cli/commands/process.js +444 -0
  108. package/dist/cli/commands/process.js.map +1 -0
  109. package/dist/cli/commands/role.d.ts +5 -2
  110. package/dist/cli/commands/role.d.ts.map +1 -1
  111. package/dist/cli/commands/role.js +145 -18
  112. package/dist/cli/commands/role.js.map +1 -1
  113. package/dist/cli/commands/user-cmd.d.ts.map +1 -1
  114. package/dist/cli/commands/user-cmd.js +41 -50
  115. package/dist/cli/commands/user-cmd.js.map +1 -1
  116. package/dist/cli/generators/capability-generator.d.ts.map +1 -1
  117. package/dist/cli/generators/capability-generator.js +131 -5
  118. package/dist/cli/generators/capability-generator.js.map +1 -1
  119. package/dist/cli/helpers/app-tsx-wiring.d.ts.map +1 -1
  120. package/dist/cli/helpers/app-tsx-wiring.js +21 -14
  121. package/dist/cli/helpers/app-tsx-wiring.js.map +1 -1
  122. package/dist/cli/helpers/auth-client.d.ts +19 -0
  123. package/dist/cli/helpers/auth-client.d.ts.map +1 -0
  124. package/dist/cli/helpers/auth-client.js +42 -0
  125. package/dist/cli/helpers/auth-client.js.map +1 -0
  126. package/dist/cli/index.d.ts.map +1 -1
  127. package/dist/cli/index.js +2 -0
  128. package/dist/cli/index.js.map +1 -1
  129. package/dist/cli/templates/index.d.ts +1 -0
  130. package/dist/cli/templates/index.d.ts.map +1 -1
  131. package/dist/cli/templates/index.js +1 -0
  132. package/dist/cli/templates/index.js.map +1 -1
  133. package/dist/cli/templates/process-management-page.d.ts +8 -0
  134. package/dist/cli/templates/process-management-page.d.ts.map +1 -0
  135. package/dist/cli/templates/process-management-page.js +824 -0
  136. package/dist/cli/templates/process-management-page.js.map +1 -0
  137. package/dist/cli/templates/user-management-page.d.ts +2 -1
  138. package/dist/cli/templates/user-management-page.d.ts.map +1 -1
  139. package/dist/cli/templates/user-management-page.js +321 -62
  140. package/dist/cli/templates/user-management-page.js.map +1 -1
  141. package/dist/config.d.ts +371 -35
  142. package/dist/config.d.ts.map +1 -1
  143. package/dist/config.js +31 -2
  144. package/dist/config.js.map +1 -1
  145. package/dist/index.d.ts +5 -0
  146. package/dist/index.d.ts.map +1 -1
  147. package/dist/index.js +5 -0
  148. package/dist/index.js.map +1 -1
  149. package/dist/types/auth.d.ts +0 -2
  150. package/dist/types/auth.d.ts.map +1 -1
  151. package/dist/types/config.d.ts +4 -0
  152. package/dist/types/config.d.ts.map +1 -1
  153. package/dist/types/event.d.ts +87 -0
  154. package/dist/types/event.d.ts.map +1 -0
  155. package/dist/types/event.js +38 -0
  156. package/dist/types/event.js.map +1 -0
  157. package/dist/types/index.d.ts +3 -0
  158. package/dist/types/index.d.ts.map +1 -1
  159. package/dist/types/index.js +1 -0
  160. package/dist/types/index.js.map +1 -1
  161. package/dist/types/process.d.ts +106 -0
  162. package/dist/types/process.d.ts.map +1 -0
  163. package/dist/types/process.js +5 -0
  164. package/dist/types/process.js.map +1 -0
  165. package/package.json +3 -1
@@ -0,0 +1,222 @@
1
+ # Process CLI Reference
2
+
3
+ ## Overview
4
+
5
+ Process is Loom's automation engine for scheduling and event-driven AI tasks. Each process has triggers (cron, event, or manual) and executes AI prompts via the Claude Code engine.
6
+
7
+ ## Commands
8
+
9
+ ### `loom process add`
10
+
11
+ Create a new process definition.
12
+
13
+ ```bash
14
+ # Lightweight process (inline prompt)
15
+ loom process add --name "daily-summary" \
16
+ --cron "0 9 * * 1-5" \
17
+ --prompt "Summarize yesterday's data and email the team" \
18
+ --owner admin
19
+
20
+ # Full process (with PROCESS.md)
21
+ loom process add --name "weekly-report" \
22
+ --cron "0 9 * * 1" \
23
+ --process "weekly-report" \
24
+ --owner admin \
25
+ --description "Weekly analytics report"
26
+
27
+ # Event-triggered process
28
+ loom process add --name "on-task-create" \
29
+ --on-event "data:create:tasks" \
30
+ --prompt "Analyze the new task and suggest priorities" \
31
+ --owner admin \
32
+ --event-debounce 2000
33
+
34
+ # With metrics config
35
+ loom process add --name "health-check" \
36
+ --cron "*/30 * * * *" \
37
+ --prompt "Check system health" \
38
+ --metrics-config ./metrics-config.json \
39
+ --owner bot
40
+ ```
41
+
42
+ **Options:**
43
+ | Flag | Required | Description |
44
+ |------|----------|-------------|
45
+ | `--name` | Yes | Process name (^[a-zA-Z][a-zA-Z0-9_-]*$) |
46
+ | `--prompt` | One of | Inline prompt for lightweight process |
47
+ | `--process` | One of | Full process name (expects .claude/processes/{name}/PROCESS.md) |
48
+ | `--cron` | No | Cron schedule expression |
49
+ | `--cron-timezone` | No | Timezone for cron (e.g., "America/New_York") |
50
+ | `--on-event` | No | EventBus pattern (e.g., "data:create:tasks") |
51
+ | `--event-filter` | No | JSON filter on event payload fields |
52
+ | `--event-debounce` | No | Debounce window in ms (default: 1000) |
53
+ | `--description` | No | Process description |
54
+ | `--owner` | No | Owner username (default: from processes config) |
55
+ | `--owner-token` | No | Direct JWT token (bypasses runtime resolution) |
56
+ | `--metrics-config` | No | Path to metrics DashboardWidget config JSON |
57
+ | `--token` | No | Auth token (or set LOOM_TOKEN) |
58
+ | `--server` | No | Server URL (or set LOOM_SERVER, default: http://localhost:3000) |
59
+
60
+ ### `loom process list`
61
+
62
+ List all processes.
63
+
64
+ ```bash
65
+ loom process list
66
+ loom process list --status active
67
+ loom process list --status paused
68
+ ```
69
+
70
+ ### `loom process status <name>`
71
+
72
+ Show detailed process status.
73
+
74
+ ```bash
75
+ loom process status daily-summary
76
+ ```
77
+
78
+ ### `loom process run <name>`
79
+
80
+ Manually trigger a process execution.
81
+
82
+ ```bash
83
+ loom process run daily-summary
84
+ loom process run on-task-create --payload '{"model":"tasks","id":"task_123"}'
85
+ ```
86
+
87
+ ### `loom process pause <name>`
88
+
89
+ Pause a process (stops triggers, manual run still works).
90
+
91
+ ```bash
92
+ loom process pause daily-summary
93
+ ```
94
+
95
+ ### `loom process resume <name>`
96
+
97
+ Resume a paused process.
98
+
99
+ ```bash
100
+ loom process resume daily-summary
101
+ ```
102
+
103
+ ### `loom process update <name>`
104
+
105
+ Update an existing process definition.
106
+
107
+ ```bash
108
+ loom process update daily-summary --cron "0 10 * * 1-5"
109
+ loom process update on-task-create --prompt "Updated prompt text"
110
+ loom process update daily-summary --description "Updated description" --cron "0 8 * * 1-5"
111
+ ```
112
+
113
+ **Options:**
114
+ | Flag | Required | Description |
115
+ |------|----------|-------------|
116
+ | `--cron` | No | Update cron schedule expression |
117
+ | `--cron-timezone` | No | Update cron timezone |
118
+ | `--on-event` | No | Update event trigger pattern |
119
+ | `--event-filter` | No | Update event payload filter as JSON |
120
+ | `--event-debounce` | No | Update debounce window in ms |
121
+ | `--prompt` | No | Update inline prompt |
122
+ | `--description` | No | Update description |
123
+ | `--token` | No | Auth token (or set LOOM_TOKEN) |
124
+ | `--server` | No | Server URL (or set LOOM_SERVER, default: http://localhost:3000) |
125
+
126
+ ### `loom process remove <name>`
127
+
128
+ Remove a process definition. Logs are preserved.
129
+
130
+ ```bash
131
+ loom process remove daily-summary
132
+ ```
133
+
134
+ ### `loom process logs <name> [runId]`
135
+
136
+ View execution logs. When `runId` is provided, shows details for a single run.
137
+
138
+ ```bash
139
+ # List recent logs
140
+ loom process logs daily-summary
141
+ loom process logs daily-summary --limit 50
142
+ loom process logs daily-summary --offset 10
143
+
144
+ # View a specific run
145
+ loom process logs daily-summary run_abc123
146
+ ```
147
+
148
+ ### `loom process generate <name>`
149
+
150
+ Create PROCESS.md scaffold directory (for full process mode). Called by AI, not directly by users.
151
+
152
+ ```bash
153
+ loom process generate daily-report --description "Daily report generator"
154
+ ```
155
+
156
+ ### `loom process export <name>`
157
+
158
+ Export process definition as JSON.
159
+
160
+ ```bash
161
+ loom process export daily-summary
162
+ ```
163
+
164
+ ## Process Modes
165
+
166
+ ### Lightweight Mode (`--prompt`)
167
+
168
+ - Inline prompt, no PROCESS.md file
169
+ - Best for simple, single-task automations
170
+ - Quick to set up and modify
171
+
172
+ ### Full Mode (`--process`)
173
+
174
+ - Has PROCESS.md at `.claude/processes/{name}/PROCESS.md`
175
+ - Can include reference files in `.claude/processes/{name}/references/`
176
+ - Best for complex, multi-step workflows
177
+ - Supports Metrics and Evolution sections
178
+
179
+ ## Trigger Types
180
+
181
+ ### Cron
182
+ Standard 5-field cron expression: `minute hour day month weekday`
183
+ ```
184
+ */5 * * * * — Every 5 minutes
185
+ 0 9 * * 1-5 — Weekdays at 9 AM
186
+ 0 0 1 * * — First of every month
187
+ ```
188
+
189
+ ### Event
190
+ EventBus pattern matching: `{category}:{action}:{target}`
191
+ ```
192
+ data:create:tasks — When a task is created
193
+ data:update:* — Any data update
194
+ user:created — When a user is created
195
+ process:completed:xxx — When process xxx completes
196
+ ```
197
+
198
+ ### Manual
199
+ `loom process run <name>` — immediate execution, works even when paused.
200
+
201
+ ## Service Token Authentication
202
+
203
+ When auth is enabled, processes need a service token to operate:
204
+ - `--owner <username>`: Runtime resolution via UserStore (recommended)
205
+ - `--owner-token <jwt>`: Direct JWT token (less secure, stored in processes.json)
206
+
207
+ ## Execution Model
208
+
209
+ 1. Trigger fires → entry enqueued
210
+ 2. Queue slot available → process starts
211
+ 3. AI prompt built (PROCESS.md + references + event context)
212
+ 4. Claude Code engine executes with timeout
213
+ 5. Result logged to `.loom/process-logs/{name}/{runId}.json`
214
+ 6. Event emitted: `process:started`, `process:completed`, or `process:failed`
215
+
216
+ ## Concurrency
217
+
218
+ Controlled by `processes.maxConcurrent` in loom.config.ts (default: 5). When max is reached, new triggers queue until a slot opens.
219
+
220
+ ## Debounce
221
+
222
+ Event triggers have `eventDebounceMs` (default: 1000ms). Rapid events within the window are collapsed — only one execution fires with the last event's payload.
@@ -103,11 +103,14 @@ loom generate dashboard <name>
103
103
  1. **询问需求**:是否需要登录功能?有哪些角色?每个角色能做什么?
104
104
  2. **编辑配置**:在 `loom.config.ts` 中添加 `auth` 字段(Schema 见上方)。至少定义一个 `admin` 角色
105
105
  3. **设置密钥**:`secret` 推荐 `env:JWT_SECRET`,不要硬编码。提醒用户设置环境变量 `export JWT_SECRET=your-secret`
106
- 4. **重启后端**:auth 配置需要重启后端生效(**必须先询问用户**)
107
- 5. **首次登录**:默认创建 admin 用户(密码 `admin123`),**提醒用户立即修改密码**
108
- 6. **生成 app-skill**:`loom generate capabilities` 更新 Skill 中的 auth.md
106
+ 4. **生成认证页面**:`loom generate system-settings user` — 自动生成用户管理页、登录页,并接入 AuthProvider 路由守卫
107
+ 5. **重启后端**:auth 配置需要重启后端生效(**必须先询问用户**)
108
+ 6. **首次登录**:默认创建 admin 用户(密码 `admin123`),**提醒用户立即修改密码**
109
+ 7. **生成 app-skill**:`loom generate capabilities` 更新 Skill 中的 auth.md
109
110
 
110
- 启用后自动获得:登录页 + 路由守卫 + RBAC 权限控制 + 用户管理页 + CLI `--token`/`LOOM_TOKEN` 鉴权。
111
+ 启用后获得:登录页 + 路由守卫 + RBAC 权限控制 + 用户管理页 + CLI `--token`/`LOOM_TOKEN` 鉴权。
112
+
113
+ > 如果 `loom init` 时配置中已包含 `auth` 字段,上述页面会在初始化时自动生成。后续添加 auth 配置时,手动执行 `loom generate system-settings user` 即可补全。
111
114
 
112
115
  ### 重启服务前必须询问用户
113
116
 
@@ -163,8 +166,8 @@ loom generate page <Name> --model <model-name> --force
163
166
  | `loom generate capabilities` | 生成应用 Skill(`references/models.md` + `references/data-semantics.md`,`SKILL.md` 仅首次创建不覆盖) |
164
167
  | `loom generate dashboard <name>` | 从 loom.config.ts dashboards 生成 Dashboard 页面 |
165
168
  | `loom generate dashboard <name> --force` | 重建 Dashboard 页面(自动备份旧文件到 `.loom/backup/`) |
166
- | `loom generate system-settings <model\|skill\|user>` | 生成系统管理页面(模型管理、技能管理或用户管理),首次调用创建子菜单,后续调用追加子页面 |
167
- | `loom generate system-settings <model\|skill\|user> --force` | 重建系统管理页面(自动备份旧文件到 `.loom/backup/`) |
169
+ | `loom generate system-settings <model\|skill\|user\|process>` | 生成系统管理页面(模型管理、技能管理、用户管理或过程管理),首次调用创建子菜单,后续调用追加子页面;`user` 类型同时生成登录页和 AuthProvider 接线 |
170
+ | `loom generate system-settings <model\|skill\|user\|process> --force` | 重建系统管理页面(自动备份旧文件到 `.loom/backup/`) |
168
171
  | `loom generate skill <name>` | 生成自定义 Skill 脚架 |
169
172
 
170
173
  ## loom.config.ts Schema(核心)
@@ -228,7 +231,6 @@ export default defineConfig({
228
231
  defaults: {
229
232
  read: 'read', // 未显式配置的模型默认读权限
230
233
  write: 'write', // 未显式配置的模型默认写权限
231
- readIncludesAiButtons: false, // read 权限是否可见 AI 按钮
232
234
  writeExcludesDelete: false, // write 权限是否排除删除操作
233
235
  },
234
236
  },
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Request-scoped context via AsyncLocalStorage
3
+ *
4
+ * Allows EventEmittingAdapter to access userId from the current
5
+ * HTTP request without coupling to the Fastify request object.
6
+ */
7
+ interface RequestContext {
8
+ userId?: string;
9
+ }
10
+ /** Get the current request context (undefined if outside a request) */
11
+ export declare function getRequestContext(): RequestContext | undefined;
12
+ /** Set context for the current async execution path */
13
+ export declare function setRequestContext(ctx: RequestContext): void;
14
+ export {};
15
+ //# sourceMappingURL=request-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../../src/backend/auth/request-context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,uEAAuE;AACvE,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D;AAED,uDAAuD;AACvD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI,CAE3D"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Request-scoped context via AsyncLocalStorage
3
+ *
4
+ * Allows EventEmittingAdapter to access userId from the current
5
+ * HTTP request without coupling to the Fastify request object.
6
+ */
7
+ import { AsyncLocalStorage } from 'async_hooks';
8
+ const asyncLocalStorage = new AsyncLocalStorage();
9
+ /** Get the current request context (undefined if outside a request) */
10
+ export function getRequestContext() {
11
+ return asyncLocalStorage.getStore();
12
+ }
13
+ /** Set context for the current async execution path */
14
+ export function setRequestContext(ctx) {
15
+ asyncLocalStorage.enterWith(ctx);
16
+ }
17
+ //# sourceMappingURL=request-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-context.js","sourceRoot":"","sources":["../../../src/backend/auth/request-context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAMhD,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,EAAkB,CAAC;AAElE,uEAAuE;AACvE,MAAM,UAAU,iBAAiB;IAC/B,OAAO,iBAAiB,CAAC,QAAQ,EAAE,CAAC;AACtC,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,iBAAiB,CAAC,GAAmB;IACnD,iBAAiB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AACnC,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * EventBus - Universal event bus with pattern matching and batch support
3
+ *
4
+ * - Pattern matching: `data:create:tasks`, `data:*:tasks`, `data:**`, `*:create:*`
5
+ * - Wildcards: `*` = single segment (`[^:]+`), `**` = any depth (`.*`)
6
+ * - Fire-and-forget emit: handler errors are caught and logged, never propagated
7
+ * - beginBatch/endBatch: suppress fine-grained events, emit aggregate only
8
+ * - Circular detection: warn when emit depth exceeds 10
9
+ */
10
+ import type { LoomEvent, EventMeta } from '../../types/event.js';
11
+ type EventHandler = (event: LoomEvent) => void | Promise<void>;
12
+ export declare class EventBus {
13
+ private handlers;
14
+ private wildcards;
15
+ private patternCache;
16
+ private batchStack;
17
+ private suppressedEvents;
18
+ private emitDepth;
19
+ /** Subscribe to an event pattern. Returns unsubscribe function. */
20
+ on(pattern: string, handler: EventHandler): () => void;
21
+ /** Unsubscribe a handler from a pattern. */
22
+ off(pattern: string, handler: EventHandler): void;
23
+ /** Emit an event — fire-and-forget. Handler errors are caught and logged. */
24
+ emit(pattern: string, payload: Record<string, unknown>, meta?: EventMeta): void;
25
+ /** Check if a pattern has any subscribers (for previousData optimization). */
26
+ hasSubscribers(pattern: string): boolean;
27
+ /** Begin a batch operation. Returns batchId. */
28
+ beginBatch(batchPattern: string): string;
29
+ /** End a batch operation. Emits aggregate event with merged payload. */
30
+ endBatch(batchId: string, payload: Record<string, unknown>, meta?: EventMeta): void;
31
+ /** Remove all handlers (for server shutdown). */
32
+ removeAllHandlers(): void;
33
+ /** Dispatch event to all matching handlers. Fire-and-forget: errors are caught, never propagated. */
34
+ private dispatch;
35
+ /** Compile a pattern string to a RegExp. Caches compiled patterns. */
36
+ private compilePattern;
37
+ }
38
+ export {};
39
+ //# sourceMappingURL=event-bus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../../src/backend/events/event-bus.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjE,KAAK,YAAY,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAQ/D,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAA0C;IAC1D,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,UAAU,CAAmD;IACrE,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,SAAS,CAAK;IAEtB,mEAAmE;IACnE,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,IAAI;IAuBtD,4CAA4C;IAC5C,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAejD,6EAA6E;IAC7E,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI;IA4B/E,8EAA8E;IAC9E,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAOxC,gDAAgD;IAChD,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAMxC,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI;IAkBnF,iDAAiD;IACjD,iBAAiB,IAAI,IAAI;IAQzB,qGAAqG;IACrG,OAAO,CAAC,QAAQ;IAkChB,sEAAsE;IACtE,OAAO,CAAC,cAAc;CAwBvB"}
@@ -0,0 +1,182 @@
1
+ /**
2
+ * EventBus - Universal event bus with pattern matching and batch support
3
+ *
4
+ * - Pattern matching: `data:create:tasks`, `data:*:tasks`, `data:**`, `*:create:*`
5
+ * - Wildcards: `*` = single segment (`[^:]+`), `**` = any depth (`.*`)
6
+ * - Fire-and-forget emit: handler errors are caught and logged, never propagated
7
+ * - beginBatch/endBatch: suppress fine-grained events, emit aggregate only
8
+ * - Circular detection: warn when emit depth exceeds 10
9
+ */
10
+ export class EventBus {
11
+ handlers = new Map();
12
+ wildcards = [];
13
+ patternCache = new Map();
14
+ batchStack = [];
15
+ suppressedEvents = [];
16
+ emitDepth = 0;
17
+ /** Subscribe to an event pattern. Returns unsubscribe function. */
18
+ on(pattern, handler) {
19
+ if (pattern.includes('*')) {
20
+ const regex = this.compilePattern(pattern);
21
+ this.wildcards.push({ pattern, regex, handler });
22
+ return () => {
23
+ const idx = this.wildcards.findIndex(w => w.pattern === pattern && w.handler === handler);
24
+ if (idx !== -1)
25
+ this.wildcards.splice(idx, 1);
26
+ };
27
+ }
28
+ const list = this.handlers.get(pattern) ?? [];
29
+ list.push(handler);
30
+ this.handlers.set(pattern, list);
31
+ return () => {
32
+ const arr = this.handlers.get(pattern);
33
+ if (arr) {
34
+ const idx = arr.indexOf(handler);
35
+ if (idx !== -1)
36
+ arr.splice(idx, 1);
37
+ if (arr.length === 0)
38
+ this.handlers.delete(pattern);
39
+ }
40
+ };
41
+ }
42
+ /** Unsubscribe a handler from a pattern. */
43
+ off(pattern, handler) {
44
+ if (pattern.includes('*')) {
45
+ const idx = this.wildcards.findIndex(w => w.pattern === pattern && w.handler === handler);
46
+ if (idx !== -1)
47
+ this.wildcards.splice(idx, 1);
48
+ return;
49
+ }
50
+ const arr = this.handlers.get(pattern);
51
+ if (arr) {
52
+ const idx = arr.indexOf(handler);
53
+ if (idx !== -1)
54
+ arr.splice(idx, 1);
55
+ if (arr.length === 0)
56
+ this.handlers.delete(pattern);
57
+ }
58
+ }
59
+ /** Emit an event — fire-and-forget. Handler errors are caught and logged. */
60
+ emit(pattern, payload, meta) {
61
+ this.emitDepth++;
62
+ if (this.emitDepth > 10) {
63
+ console.warn(`[EventBus] Circular emit detected (depth=${this.emitDepth}) for pattern: ${pattern}`);
64
+ }
65
+ try {
66
+ const event = {
67
+ id: `evt_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`,
68
+ pattern,
69
+ payload,
70
+ userId: meta?.userId,
71
+ source: meta?.source ?? 'server',
72
+ timestamp: new Date().toISOString(),
73
+ };
74
+ // If inside a batch, suppress the event
75
+ if (this.batchStack.length > 0) {
76
+ this.suppressedEvents.push(event);
77
+ return;
78
+ }
79
+ this.dispatch(event);
80
+ }
81
+ finally {
82
+ this.emitDepth--;
83
+ }
84
+ }
85
+ /** Check if a pattern has any subscribers (for previousData optimization). */
86
+ hasSubscribers(pattern) {
87
+ if (this.handlers.has(pattern) && this.handlers.get(pattern).length > 0) {
88
+ return true;
89
+ }
90
+ return this.wildcards.some(w => w.regex.test(pattern));
91
+ }
92
+ /** Begin a batch operation. Returns batchId. */
93
+ beginBatch(batchPattern) {
94
+ const batchId = `batch_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
95
+ this.batchStack.push({ batchId, pattern: batchPattern });
96
+ return batchId;
97
+ }
98
+ /** End a batch operation. Emits aggregate event with merged payload. */
99
+ endBatch(batchId, payload, meta) {
100
+ const idx = this.batchStack.findIndex(b => b.batchId === batchId);
101
+ if (idx === -1)
102
+ return;
103
+ const batch = this.batchStack[idx];
104
+ // Remove from stack
105
+ this.batchStack.splice(idx, 1);
106
+ // Clear suppressed events when batch stack is empty
107
+ if (this.batchStack.length === 0) {
108
+ this.suppressedEvents = [];
109
+ }
110
+ // Emit aggregate event using the stored pattern
111
+ this.emit(batch.pattern, payload, meta);
112
+ }
113
+ /** Remove all handlers (for server shutdown). */
114
+ removeAllHandlers() {
115
+ this.handlers.clear();
116
+ this.wildcards = [];
117
+ this.patternCache.clear();
118
+ this.batchStack = [];
119
+ this.suppressedEvents = [];
120
+ }
121
+ /** Dispatch event to all matching handlers. Fire-and-forget: errors are caught, never propagated. */
122
+ dispatch(event) {
123
+ // Exact match handlers
124
+ const exactHandlers = this.handlers.get(event.pattern) ?? [];
125
+ for (const handler of exactHandlers) {
126
+ try {
127
+ const result = handler(event);
128
+ // If handler returns a promise, catch its rejection silently
129
+ if (result instanceof Promise) {
130
+ result.catch(err => {
131
+ console.error(`[EventBus] Async handler error for ${event.pattern}:`, err);
132
+ });
133
+ }
134
+ }
135
+ catch (err) {
136
+ console.error(`[EventBus] Handler error for ${event.pattern}:`, err);
137
+ }
138
+ }
139
+ // Wildcard handlers
140
+ for (const entry of this.wildcards) {
141
+ if (entry.regex.test(event.pattern)) {
142
+ try {
143
+ const result = entry.handler(event);
144
+ if (result instanceof Promise) {
145
+ result.catch(err => {
146
+ console.error(`[EventBus] Async handler error for wildcard ${entry.pattern}:`, err);
147
+ });
148
+ }
149
+ }
150
+ catch (err) {
151
+ console.error(`[EventBus] Handler error for wildcard ${entry.pattern}:`, err);
152
+ }
153
+ }
154
+ }
155
+ }
156
+ /** Compile a pattern string to a RegExp. Caches compiled patterns. */
157
+ compilePattern(pattern) {
158
+ const cached = this.patternCache.get(pattern);
159
+ if (cached)
160
+ return cached;
161
+ // Lone `*` matches everything
162
+ if (pattern === '*') {
163
+ const regex = /^.*$/;
164
+ this.patternCache.set(pattern, regex);
165
+ return regex;
166
+ }
167
+ const regexStr = pattern
168
+ .split(':')
169
+ .map(segment => {
170
+ if (segment === '**')
171
+ return '.*';
172
+ if (segment.includes('*'))
173
+ return segment.replace(/\*/g, '[^:]+');
174
+ return segment;
175
+ })
176
+ .join(':');
177
+ const regex = new RegExp(`^${regexStr}$`);
178
+ this.patternCache.set(pattern, regex);
179
+ return regex;
180
+ }
181
+ }
182
+ //# sourceMappingURL=event-bus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../../../src/backend/events/event-bus.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * EventEmittingAdapter - Decorator that wraps DataAdapter to auto-emit events
3
+ *
4
+ * - write() → emits data:create:<model> with { model, id, data }
5
+ * - update() → emits data:update:<model> with { model, id, data, previousData, changedFields }
6
+ * - delete() → emits data:delete:<model> with { model, id, previousData }
7
+ * - hasSubscribers() optimization: skips previousData read when no subscribers
8
+ * - Events only emitted after inner operation succeeds
9
+ * - getUserId callback for injecting userId (auth-aware)
10
+ */
11
+ import type { DataAdapter, DataRecord, ReadOptions } from '../../types/adapter.js';
12
+ import type { ModelSchema } from '../../types/model.js';
13
+ import type { EventBus } from './event-bus.js';
14
+ export declare class EventEmittingAdapter implements DataAdapter {
15
+ private inner;
16
+ private eventBus;
17
+ private source;
18
+ private getUserId?;
19
+ readonly name: string;
20
+ constructor(inner: DataAdapter, eventBus: EventBus, source: 'server' | 'cli', getUserId?: (() => string | undefined) | undefined);
21
+ write(model: string, data: DataRecord): Promise<DataRecord>;
22
+ update(model: string, id: string, data: DataRecord): Promise<DataRecord>;
23
+ delete(model: string, id: string): Promise<void>;
24
+ read(model: string, options?: ReadOptions): Promise<DataRecord | DataRecord[] | null>;
25
+ count(model: string, options?: Omit<ReadOptions, 'limit' | 'offset' | 'sort'>): Promise<number>;
26
+ getSchema(model: string): Promise<ModelSchema | undefined>;
27
+ listModels(): Promise<string[]>;
28
+ initialize(): Promise<void>;
29
+ healthCheck(): Promise<boolean>;
30
+ }
31
+ //# sourceMappingURL=event-emitting-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-emitting-adapter.d.ts","sourceRoot":"","sources":["../../../src/backend/events/event-emitting-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,qBAAa,oBAAqB,YAAW,WAAW;IAIpD,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,SAAS,CAAC;IANpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAGZ,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,QAAQ,GAAG,KAAK,EACxB,SAAS,CAAC,GAAE,MAAM,MAAM,GAAG,SAAS,aAAA;IAKxC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAU3D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAiBxE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAehD,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC;IAIrF,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAI/F,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;IAI1D,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAI/B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAGtC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * EventEmittingAdapter - Decorator that wraps DataAdapter to auto-emit events
3
+ *
4
+ * - write() → emits data:create:<model> with { model, id, data }
5
+ * - update() → emits data:update:<model> with { model, id, data, previousData, changedFields }
6
+ * - delete() → emits data:delete:<model> with { model, id, previousData }
7
+ * - hasSubscribers() optimization: skips previousData read when no subscribers
8
+ * - Events only emitted after inner operation succeeds
9
+ * - getUserId callback for injecting userId (auth-aware)
10
+ */
11
+ import { EventPatterns } from '../../types/event.js';
12
+ export class EventEmittingAdapter {
13
+ inner;
14
+ eventBus;
15
+ source;
16
+ getUserId;
17
+ name;
18
+ constructor(inner, eventBus, source, getUserId) {
19
+ this.inner = inner;
20
+ this.eventBus = eventBus;
21
+ this.source = source;
22
+ this.getUserId = getUserId;
23
+ this.name = `event-emitting:${inner.name}`;
24
+ }
25
+ async write(model, data) {
26
+ const record = await this.inner.write(model, data);
27
+ void this.eventBus.emit(EventPatterns.DATA_CREATE(model), { model, id: record.id, data: record }, { userId: this.getUserId?.(), source: this.source });
28
+ return record;
29
+ }
30
+ async update(model, id, data) {
31
+ const pattern = EventPatterns.DATA_UPDATE(model);
32
+ const previous = this.eventBus.hasSubscribers(pattern)
33
+ ? await this.inner.read(model, { id }).catch(() => null)
34
+ : null;
35
+ const record = await this.inner.update(model, id, data);
36
+ const changedFields = previous
37
+ ? Object.keys(data).filter(k => data[k] !== previous?.[k])
38
+ : undefined;
39
+ void this.eventBus.emit(pattern, { model, id, data: record, previousData: previous ?? undefined, changedFields }, { userId: this.getUserId?.(), source: this.source });
40
+ return record;
41
+ }
42
+ async delete(model, id) {
43
+ const pattern = EventPatterns.DATA_DELETE(model);
44
+ const previous = this.eventBus.hasSubscribers(pattern)
45
+ ? await this.inner.read(model, { id }).catch(() => null)
46
+ : null;
47
+ await this.inner.delete(model, id);
48
+ void this.eventBus.emit(pattern, { model, id, previousData: previous ?? undefined }, { userId: this.getUserId?.(), source: this.source });
49
+ }
50
+ // ── Pure delegation (no events for read operations) ──
51
+ async read(model, options) {
52
+ return this.inner.read(model, options);
53
+ }
54
+ async count(model, options) {
55
+ return this.inner.count(model, options);
56
+ }
57
+ async getSchema(model) {
58
+ return this.inner.getSchema(model);
59
+ }
60
+ async listModels() {
61
+ return this.inner.listModels();
62
+ }
63
+ async initialize() {
64
+ return this.inner.initialize();
65
+ }
66
+ async healthCheck() {
67
+ return this.inner.healthCheck();
68
+ }
69
+ }
70
+ //# sourceMappingURL=event-emitting-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-emitting-adapter.js","sourceRoot":"","sources":["../../../src/backend/events/event-emitting-adapter.ts"],"names":[],"mappings":"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"}