botnote 0.1.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 (79) hide show
  1. package/README.md +277 -0
  2. package/dist/bin.d.ts +2 -0
  3. package/dist/bin.js +320 -0
  4. package/dist/bin.js.map +1 -0
  5. package/dist/cli.d.ts +1 -0
  6. package/dist/cli.js +61 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/db/client.d.ts +10 -0
  9. package/dist/db/client.js +16 -0
  10. package/dist/db/client.js.map +1 -0
  11. package/dist/db/migrate.d.ts +1 -0
  12. package/dist/db/migrate.js +57 -0
  13. package/dist/db/migrate.js.map +1 -0
  14. package/dist/db/migrations/0001_init.sql +89 -0
  15. package/dist/db/migrations/0002_tasks_due_at.sql +16 -0
  16. package/dist/db/migrations/0003_task_priority_and_sequence.sql +45 -0
  17. package/dist/db/migrations/0004_pinned.sql +8 -0
  18. package/dist/db/migrations/0005_nullable_title_and_parent.sql +5 -0
  19. package/dist/db/migrations/0006_project_color_icon.sql +3 -0
  20. package/dist/db/migrations/0007_tokens.sql +14 -0
  21. package/dist/db/migrations/0008_simplify_kinds_drop_actors.sql +21 -0
  22. package/dist/db/migrations/0009_sessions.sql +14 -0
  23. package/dist/db/migrations/0010_completed_at.sql +17 -0
  24. package/dist/db/migrations/0011_completed_at_backfill_fix.sql +14 -0
  25. package/dist/db/migrations/0012_completed_at_backfill_due.sql +16 -0
  26. package/dist/db/migrations/0013_due_at_noon_utc.sql +13 -0
  27. package/dist/db/schema.d.ts +811 -0
  28. package/dist/db/schema.js +112 -0
  29. package/dist/db/schema.js.map +1 -0
  30. package/dist/mcp/http-client.d.ts +154 -0
  31. package/dist/mcp/http-client.js +113 -0
  32. package/dist/mcp/http-client.js.map +1 -0
  33. package/dist/mcp/server.d.ts +7 -0
  34. package/dist/mcp/server.js +492 -0
  35. package/dist/mcp/server.js.map +1 -0
  36. package/dist/rest/routes.d.ts +3 -0
  37. package/dist/rest/routes.js +320 -0
  38. package/dist/rest/routes.js.map +1 -0
  39. package/dist/rest/server.d.ts +12 -0
  40. package/dist/rest/server.js +282 -0
  41. package/dist/rest/server.js.map +1 -0
  42. package/dist/service/embedding.d.ts +25 -0
  43. package/dist/service/embedding.js +112 -0
  44. package/dist/service/embedding.js.map +1 -0
  45. package/dist/service/entities.d.ts +22 -0
  46. package/dist/service/entities.js +174 -0
  47. package/dist/service/entities.js.map +1 -0
  48. package/dist/service/index.d.ts +8 -0
  49. package/dist/service/index.js +8 -0
  50. package/dist/service/index.js.map +1 -0
  51. package/dist/service/opening_brief.d.ts +14 -0
  52. package/dist/service/opening_brief.js +104 -0
  53. package/dist/service/opening_brief.js.map +1 -0
  54. package/dist/service/projects.d.ts +8 -0
  55. package/dist/service/projects.js +36 -0
  56. package/dist/service/projects.js.map +1 -0
  57. package/dist/service/search.d.ts +15 -0
  58. package/dist/service/search.js +101 -0
  59. package/dist/service/search.js.map +1 -0
  60. package/dist/service/sessions.d.ts +25 -0
  61. package/dist/service/sessions.js +89 -0
  62. package/dist/service/sessions.js.map +1 -0
  63. package/dist/service/tasks.d.ts +23 -0
  64. package/dist/service/tasks.js +130 -0
  65. package/dist/service/tasks.js.map +1 -0
  66. package/dist/service/tokens.d.ts +18 -0
  67. package/dist/service/tokens.js +41 -0
  68. package/dist/service/tokens.js.map +1 -0
  69. package/dist/service/types.d.ts +294 -0
  70. package/dist/service/types.js +132 -0
  71. package/dist/service/types.js.map +1 -0
  72. package/dist/version.d.ts +1 -0
  73. package/dist/version.js +13 -0
  74. package/dist/version.js.map +1 -0
  75. package/package.json +73 -0
  76. package/web/dist/assets/index-Bddg7h_x.css +1 -0
  77. package/web/dist/assets/index-DYW6stVx.js +542 -0
  78. package/web/dist/favicon.svg +13 -0
  79. package/web/dist/index.html +17 -0
@@ -0,0 +1,320 @@
1
+ import { z } from "zod";
2
+ import { get, getByKey, link, listRelated, recent, remove, update, write } from "../service/entities.js";
3
+ import { formatOpeningBrief, openingBrief } from "../service/opening_brief.js";
4
+ import { createProject, getProject, getProjectByKey, listProjects, updateProject } from "../service/projects.js";
5
+ import { search } from "../service/search.js";
6
+ import { createSession, revokeSession, verifyMasterPassword } from "../service/sessions.js";
7
+ import { tasksRange } from "../service/tasks.js";
8
+ import { createToken, listTokens, revokeToken } from "../service/tokens.js";
9
+ import { CreateNoteInput, CreateProjectInput, CreateTaskInput, CreateTokenInput, LinkInput, OpeningBriefInput, RecentInput, SearchInput, TasksRangeInput, UpdateInput, UpdateProjectInput, Uuid } from "../service/types.js";
10
+ import { VERSION } from "../version.js";
11
+ const IdParams = z.object({ id: Uuid });
12
+ const KeyParams = z.object({ key: z.string() });
13
+ const KeySeqParams = z.object({
14
+ key: z.string().regex(/^[A-Z][A-Z0-9_]*$/),
15
+ seq: z.coerce.number().int().positive()
16
+ });
17
+ const OpeningBriefBody = OpeningBriefInput.omit({ projectId: true }).optional();
18
+ const LinkBody = LinkInput.omit({ fromId: true });
19
+ function publicToken(t) {
20
+ return {
21
+ id: t.id,
22
+ name: t.name,
23
+ prefix: t.prefix,
24
+ lastUsedAt: t.lastUsedAt,
25
+ createdAt: t.createdAt
26
+ };
27
+ }
28
+ export async function registerRoutes(rawApp, ctx) {
29
+ const app = rawApp.withTypeProvider();
30
+ app.get("/health", async () => ({ ok: true, version: VERSION }));
31
+ // ----- projects -----
32
+ app.post("/v1/projects", { schema: { tags: ["projects"], summary: "Create a project", body: CreateProjectInput } }, async (req) => createProject(ctx.db, CreateProjectInput.parse(req.body)));
33
+ app.get("/v1/projects", { schema: { tags: ["projects"], summary: "List projects" } }, async () => listProjects(ctx.db));
34
+ app.get("/v1/projects/:id", { schema: { tags: ["projects"], summary: "Fetch a project by id (includes AGENTS.md)", params: IdParams } }, async (req, reply) => {
35
+ const { id } = IdParams.parse(req.params);
36
+ const p = await getProject(ctx.db, id);
37
+ if (!p)
38
+ return reply.code(404).send({ error: "not_found" });
39
+ return p;
40
+ });
41
+ app.patch("/v1/projects/:id", {
42
+ schema: {
43
+ tags: ["projects"],
44
+ summary: "Update project (name, color, icon, agents_md)",
45
+ params: IdParams,
46
+ body: UpdateProjectInput
47
+ }
48
+ }, async (req) => {
49
+ const { id } = IdParams.parse(req.params);
50
+ const body = UpdateProjectInput.parse(req.body);
51
+ return updateProject(ctx.db, id, body);
52
+ });
53
+ app.get("/v1/projects/by-key/:key", { schema: { tags: ["projects"], summary: "Fetch a project by key", params: KeyParams } }, async (req, reply) => {
54
+ const { key } = KeyParams.parse(req.params);
55
+ const p = await getProjectByKey(ctx.db, key);
56
+ if (!p)
57
+ return reply.code(404).send({ error: "not_found" });
58
+ return p;
59
+ });
60
+ app.post("/v1/projects/:id/opening-brief", {
61
+ schema: {
62
+ tags: ["brief"],
63
+ summary: "Opening brief for a project",
64
+ description: "Returns the agent context bundle: AGENTS.md, pinned notes, open tasks, pending decisions, recent activity. Also returns a markdown-formatted version.",
65
+ params: IdParams,
66
+ body: OpeningBriefBody
67
+ }
68
+ }, async (req) => {
69
+ const { id } = IdParams.parse(req.params);
70
+ const bodyOpts = OpeningBriefBody.parse(req.body);
71
+ const input = OpeningBriefInput.parse({ projectId: id, recentLimit: bodyOpts?.recentLimit });
72
+ const brief = await openingBrief(ctx.db, input);
73
+ return { ...brief, markdown: formatOpeningBrief(brief) };
74
+ });
75
+ // Workspace-or-project opening brief. The path-param variant above is kept
76
+ // for clients that already integrate against it; the MCP HTTP client and
77
+ // new plugin code uses this single entry point and passes projectId in the
78
+ // body (or omits it for a workspace-wide brief).
79
+ app.post("/v1/opening-brief", {
80
+ schema: {
81
+ tags: ["brief"],
82
+ summary: "Opening brief (project-scoped or workspace-wide)",
83
+ body: OpeningBriefInput.partial().optional()
84
+ }
85
+ }, async (req) => {
86
+ const input = OpeningBriefInput.parse(req.body ?? {});
87
+ const brief = await openingBrief(ctx.db, input);
88
+ return { ...brief, markdown: formatOpeningBrief(brief) };
89
+ });
90
+ // ----- entities (read) -----
91
+ app.get("/v1/entities/:id", { schema: { tags: ["entities"], summary: "Fetch an entity by id", params: IdParams } }, async (req, reply) => {
92
+ const { id } = IdParams.parse(req.params);
93
+ const e = await get(ctx.db, id);
94
+ if (!e)
95
+ return reply.code(404).send({ error: "not_found" });
96
+ return e;
97
+ });
98
+ app.get("/v1/projects/by-key/:key/entities/by-seq/:seq", {
99
+ schema: {
100
+ tags: ["entities"],
101
+ summary: "Fetch an entity by its human-readable identifier (e.g. BOT-12)",
102
+ params: KeySeqParams
103
+ }
104
+ }, async (req, reply) => {
105
+ const { key, seq } = KeySeqParams.parse(req.params);
106
+ const e = await getByKey(ctx.db, key, seq);
107
+ if (!e)
108
+ return reply.code(404).send({ error: "not_found" });
109
+ return e;
110
+ });
111
+ app.get("/v1/entities/:id/related", {
112
+ schema: {
113
+ tags: ["entities"],
114
+ summary: "List entities whose parent_id is this id (e.g. notes linked to a task)",
115
+ params: IdParams
116
+ }
117
+ }, async (req) => {
118
+ const { id } = IdParams.parse(req.params);
119
+ return listRelated(ctx.db, id);
120
+ });
121
+ app.post("/v1/recent", {
122
+ schema: {
123
+ tags: ["entities"],
124
+ summary: "Recent entities (filterable by project, kinds, since)",
125
+ body: RecentInput.optional()
126
+ }
127
+ }, async (req) => recent(ctx.db, RecentInput.parse(req.body ?? {})));
128
+ app.post("/v1/search", {
129
+ schema: {
130
+ tags: ["search"],
131
+ summary: "Hybrid retrieval (BM25 + cosine + time decay, RRF merged)",
132
+ description: "If OPENAI_API_KEY is set, the query is embedded and cosine similarity is merged in via RRF. Otherwise BM25-only.",
133
+ body: SearchInput
134
+ }
135
+ }, async (req) => {
136
+ const body = SearchInput.parse(req.body);
137
+ const queryEmbedding = await ctx.embedding.embedQuery(body.query);
138
+ const hits = await search(ctx.db, body, queryEmbedding ? { queryEmbedding } : {});
139
+ return { hits, embeddingUsed: queryEmbedding != null };
140
+ });
141
+ app.post("/v1/tasks/range", {
142
+ schema: {
143
+ tags: ["tasks"],
144
+ summary: "Tasks in a date range + overdue + backlog (no due_at)",
145
+ description: "Returns three buckets: scheduled (due_at in [from, to)), overdue (due_at before now, only when not includeDone), backlog (no due_at, only when includeBacklog).",
146
+ body: TasksRangeInput
147
+ }
148
+ }, async (req) => tasksRange(ctx.db, TasksRangeInput.parse(req.body)));
149
+ // ----- entities (write) -----
150
+ app.post("/v1/tasks", {
151
+ schema: {
152
+ tags: ["entities"],
153
+ summary: "Create a task",
154
+ body: CreateTaskInput
155
+ }
156
+ }, async (req) => {
157
+ const body = CreateTaskInput.parse(req.body);
158
+ const entity = await write(ctx.db, { ...body, kind: "task", pinned: false });
159
+ if (ctx.embedding.isEnabled()) {
160
+ ctx.embedding.enqueue(entity.id, `${entity.title ?? ""}\n${entity.body}`);
161
+ }
162
+ return entity;
163
+ });
164
+ app.post("/v1/notes", {
165
+ schema: {
166
+ tags: ["entities"],
167
+ summary: "Create a note (title optional; body's first line acts as the label)",
168
+ body: CreateNoteInput
169
+ }
170
+ }, async (req) => {
171
+ const body = CreateNoteInput.parse(req.body);
172
+ const entity = await write(ctx.db, {
173
+ ...body,
174
+ kind: "note",
175
+ status: "open",
176
+ priority: "none",
177
+ dueAt: null
178
+ });
179
+ if (ctx.embedding.isEnabled()) {
180
+ ctx.embedding.enqueue(entity.id, `${entity.title ?? ""}\n${entity.body}`);
181
+ }
182
+ return entity;
183
+ });
184
+ app.patch("/v1/entities/:id", {
185
+ schema: {
186
+ tags: ["entities"],
187
+ summary: "Update an entity (task or note)",
188
+ params: IdParams,
189
+ body: UpdateInput
190
+ }
191
+ }, async (req) => {
192
+ const { id } = IdParams.parse(req.params);
193
+ const fields = UpdateInput.parse(req.body);
194
+ const updated = await update(ctx.db, id, fields);
195
+ if (ctx.embedding.isEnabled() &&
196
+ (fields.body !== undefined || fields.title !== undefined)) {
197
+ ctx.embedding.enqueue(updated.id, `${updated.title ?? ""}\n${updated.body}`);
198
+ }
199
+ return updated;
200
+ });
201
+ app.delete("/v1/entities/:id", {
202
+ schema: {
203
+ tags: ["entities"],
204
+ summary: "Delete an entity",
205
+ params: IdParams
206
+ }
207
+ }, async (req, reply) => {
208
+ const { id } = IdParams.parse(req.params);
209
+ const ok = await remove(ctx.db, id);
210
+ if (!ok)
211
+ return reply.code(404).send({ error: "not_found" });
212
+ return reply.code(204).send();
213
+ });
214
+ app.post("/v1/entities/:id/links", {
215
+ schema: {
216
+ tags: ["entities"],
217
+ summary: "Link this entity to another (blocks / references / parent_of)",
218
+ params: IdParams,
219
+ body: LinkBody
220
+ }
221
+ }, async (req) => {
222
+ const { id } = IdParams.parse(req.params);
223
+ const body = LinkBody.parse(req.body);
224
+ return link(ctx.db, { fromId: id, toId: body.toId, kind: body.kind });
225
+ });
226
+ // ----- auth (browser session cookie) -----
227
+ const LoginBody = z.object({
228
+ password: z.string().min(1).max(500)
229
+ });
230
+ app.post("/v1/auth/login", {
231
+ // Tight cap — this is the brute-force surface.
232
+ config: { rateLimit: { max: 10, timeWindow: "1 minute" } },
233
+ schema: {
234
+ tags: ["auth"],
235
+ summary: "Master-password login. Sets httpOnly session cookie.",
236
+ body: LoginBody
237
+ }
238
+ }, async (req, reply) => {
239
+ const { password } = LoginBody.parse(req.body);
240
+ const ok = verifyMasterPassword(password);
241
+ if (!ok) {
242
+ // Add a small constant-time penalty so timing attacks against the
243
+ // env-lookup branch aren't easier than the rate limit makes them.
244
+ await new Promise((r) => setTimeout(r, 300));
245
+ return reply.code(401).send({ error: "invalid_password" });
246
+ }
247
+ const ua = req.headers["user-agent"] ?? null;
248
+ const { plaintext, session } = await createSession(ctx.db, { userAgent: ua });
249
+ reply.setCookie("botnote_session", plaintext, {
250
+ httpOnly: true,
251
+ secure: process.env.NODE_ENV === "production",
252
+ sameSite: "lax",
253
+ path: "/",
254
+ maxAge: 60 * 60 * 24 * 30 // 30 days
255
+ });
256
+ return { ok: true, expiresAt: session.expiresAt };
257
+ });
258
+ app.post("/v1/auth/logout", {
259
+ schema: {
260
+ tags: ["auth"],
261
+ summary: "Clear session cookie and revoke the server-side row."
262
+ }
263
+ }, async (req, reply) => {
264
+ const plaintext = req.cookies?.botnote_session;
265
+ if (plaintext)
266
+ await revokeSession(ctx.db, plaintext);
267
+ reply.clearCookie("botnote_session", { path: "/" });
268
+ return { ok: true };
269
+ });
270
+ app.get("/v1/auth/whoami", {
271
+ schema: {
272
+ tags: ["auth"],
273
+ summary: "Confirm authentication state + how the caller got in."
274
+ }
275
+ }, async (req) => {
276
+ // If the request reached this handler, the auth gate already passed —
277
+ // either via cookie, bearer, or trusted tailnet origin.
278
+ const hasCookie = !!req.cookies?.botnote_session;
279
+ const hasBearer = !!req.headers.authorization;
280
+ const viaProxy = !!req.headers["cf-connecting-ip"] || !!req.headers["x-forwarded-for"];
281
+ return {
282
+ authenticated: true,
283
+ via: hasCookie
284
+ ? "cookie"
285
+ : hasBearer
286
+ ? "bearer"
287
+ : viaProxy
288
+ ? "unknown"
289
+ : "trusted_origin"
290
+ };
291
+ });
292
+ // ----- tokens -----
293
+ app.get("/v1/tokens", { schema: { tags: ["tokens"], summary: "List API tokens (no hash, no plaintext)" } }, async () => (await listTokens(ctx.db)).map(publicToken));
294
+ // Token write endpoints get a much tighter cap (30/hour per IP). These are
295
+ // low-frequency operations — bumping them limits the blast radius if a token
296
+ // leaks or someone hammers the create endpoint.
297
+ app.post("/v1/tokens", {
298
+ config: { rateLimit: { max: 30, timeWindow: "1 hour" } },
299
+ schema: {
300
+ tags: ["tokens"],
301
+ summary: "Create a new API token (plaintext returned once)",
302
+ body: CreateTokenInput
303
+ }
304
+ }, async (req) => {
305
+ const body = CreateTokenInput.parse(req.body);
306
+ const { token, plaintext } = await createToken(ctx.db, body);
307
+ return { ...publicToken(token), plaintext };
308
+ });
309
+ app.delete("/v1/tokens/:id", {
310
+ config: { rateLimit: { max: 30, timeWindow: "1 hour" } },
311
+ schema: { tags: ["tokens"], summary: "Revoke an API token", params: IdParams }
312
+ }, async (req, reply) => {
313
+ const { id } = IdParams.parse(req.params);
314
+ const ok = await revokeToken(ctx.db, id);
315
+ if (!ok)
316
+ return reply.code(404).send({ error: "not_found" });
317
+ return reply.code(204).send();
318
+ });
319
+ }
320
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/rest/routes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EACL,GAAG,EACH,QAAQ,EACR,IAAI,EACJ,WAAW,EACX,MAAM,EACN,MAAM,EACN,MAAM,EACN,KAAK,EACN,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC/E,OAAO,EACL,aAAa,EACb,UAAU,EACV,eAAe,EACf,YAAY,EACZ,aAAa,EACd,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EACL,aAAa,EACb,aAAa,EACb,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,SAAS,EACT,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,IAAI,EACL,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxC,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;AACxC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAChD,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC;IAC1C,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CACxC,CAAC,CAAC;AACH,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;AAChF,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAElD,SAAS,WAAW,CAAC,CAAQ;IAC3B,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,SAAS,EAAE,CAAC,CAAC,SAAS;KACvB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAuB,EACvB,GAAkB;IAElB,MAAM,GAAG,GAAG,MAAM,CAAC,gBAAgB,EAAmB,CAAC;IAEvD,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IAEjE,uBAAuB;IAEvB,GAAG,CAAC,IAAI,CACN,cAAc,EACd,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,kBAAkB,EAAE,EAAE,EACzF,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CACzE,CAAC;IAEF,GAAG,CAAC,GAAG,CACL,cAAc,EACd,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAC5D,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CACjC,CAAC;IAEF,GAAG,CAAC,GAAG,CACL,kBAAkB,EAClB,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,4CAA4C,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAC3G,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACnB,MAAM,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACvC,IAAI,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,CAAC;IACX,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,KAAK,CACP,kBAAkB,EAClB;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,UAAU,CAAC;YAClB,OAAO,EAAE,+CAA+C;YACxD,MAAM,EAAE,QAAQ;YAChB,IAAI,EAAE,kBAAkB;SACzB;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChD,OAAO,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,GAAG,CACL,0BAA0B,EAC1B,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,wBAAwB,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EACxF,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACnB,MAAM,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC7C,IAAI,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,CAAC;IACX,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,gCAAgC,EAChC;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,OAAO,CAAC;YACf,OAAO,EAAE,6BAA6B;YACtC,WAAW,EACT,uJAAuJ;YACzJ,MAAM,EAAE,QAAQ;YAChB,IAAI,EAAE,gBAAgB;SACvB;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC;QAC7F,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAChD,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;IAC3D,CAAC,CACF,CAAC;IAEF,2EAA2E;IAC3E,yEAAyE;IACzE,2EAA2E;IAC3E,iDAAiD;IACjD,GAAG,CAAC,IAAI,CACN,mBAAmB,EACnB;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,OAAO,CAAC;YACf,OAAO,EAAE,kDAAkD;YAC3D,IAAI,EAAE,iBAAiB,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;SAC7C;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAChD,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;IAC3D,CAAC,CACF,CAAC;IAEF,8BAA8B;IAE9B,GAAG,CAAC,GAAG,CACL,kBAAkB,EAClB,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,uBAAuB,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EACtF,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACnB,MAAM,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,CAAC;IACX,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,GAAG,CACL,+CAA+C,EAC/C;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,UAAU,CAAC;YAClB,OAAO,EAAE,gEAAgE;YACzE,MAAM,EAAE,YAAY;SACrB;KACF,EACD,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACnB,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpD,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,CAAC;IACX,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,GAAG,CACL,0BAA0B,EAC1B;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,UAAU,CAAC;YAClB,OAAO,EAAE,wEAAwE;YACjF,MAAM,EAAE,QAAQ;SACjB;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,OAAO,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACjC,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,YAAY,EACZ;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,UAAU,CAAC;YAClB,OAAO,EAAE,uDAAuD;YAChE,IAAI,EAAE,WAAW,CAAC,QAAQ,EAAE;SAC7B;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CACjE,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,YAAY,EACZ;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,QAAQ,CAAC;YAChB,OAAO,EAAE,2DAA2D;YACpE,WAAW,EACT,kHAAkH;YACpH,IAAI,EAAE,WAAW;SAClB;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,cAAc,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClE,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAClF,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,cAAc,IAAI,IAAI,EAAE,CAAC;IACzD,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,iBAAiB,EACjB;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,OAAO,CAAC;YACf,OAAO,EAAE,uDAAuD;YAChE,WAAW,EACT,iKAAiK;YACnK,IAAI,EAAE,eAAe;SACtB;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CACnE,CAAC;IAEF,+BAA+B;IAE/B,GAAG,CAAC,IAAI,CACN,WAAW,EACX;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,UAAU,CAAC;YAClB,OAAO,EAAE,eAAe;YACxB,IAAI,EAAE,eAAe;SACtB;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7E,IAAI,GAAG,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,CAAC;YAC9B,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5E,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,WAAW,EACX;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,UAAU,CAAC;YAClB,OAAO,EAAE,qEAAqE;YAC9E,IAAI,EAAE,eAAe;SACtB;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE;YACjC,GAAG,IAAI;YACP,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,MAAM;YACd,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QACH,IAAI,GAAG,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,CAAC;YAC9B,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5E,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,KAAK,CACP,kBAAkB,EAClB;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,UAAU,CAAC;YAClB,OAAO,EAAE,iCAAiC;YAC1C,MAAM,EAAE,QAAQ;YAChB,IAAI,EAAE,WAAW;SAClB;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QACjD,IACE,GAAG,CAAC,SAAS,CAAC,SAAS,EAAE;YACzB,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,EACzD,CAAC;YACD,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,IAAI,EAAE,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,MAAM,CACR,kBAAkB,EAClB;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,UAAU,CAAC;YAClB,OAAO,EAAE,kBAAkB;YAC3B,MAAM,EAAE,QAAQ;SACjB;KACF,EACD,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACnB,MAAM,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,EAAE;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QAC7D,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAChC,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,wBAAwB,EACxB;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,UAAU,CAAC;YAClB,OAAO,EAAE,+DAA+D;YACxE,MAAM,EAAE,QAAQ;YAChB,IAAI,EAAE,QAAQ;SACf;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtC,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACxE,CAAC,CACF,CAAC;IAEF,4CAA4C;IAE5C,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;QACzB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;KACrC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CACN,gBAAgB,EAChB;QACE,+CAA+C;QAC/C,MAAM,EAAE,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE;QAC1D,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,MAAM,CAAC;YACd,OAAO,EAAE,sDAAsD;YAC/D,IAAI,EAAE,SAAS;SAChB;KACF,EACD,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACnB,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/C,MAAM,EAAE,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,kEAAkE;YAClE,kEAAkE;YAClE,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YAC7C,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,MAAM,EAAE,GAAI,GAAG,CAAC,OAAO,CAAC,YAAY,CAAwB,IAAI,IAAI,CAAC;QACrE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9E,KAAK,CAAC,SAAS,CAAC,iBAAiB,EAAE,SAAS,EAAE;YAC5C,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;YAC7C,QAAQ,EAAE,KAAK;YACf,IAAI,EAAE,GAAG;YACT,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,UAAU;SACrC,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC;IACpD,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,IAAI,CACN,iBAAiB,EACjB;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,MAAM,CAAC;YACd,OAAO,EAAE,sDAAsD;SAChE;KACF,EACD,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACnB,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,EAAE,eAAe,CAAC;QAC/C,IAAI,SAAS;YAAE,MAAM,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QACtD,KAAK,CAAC,WAAW,CAAC,iBAAiB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACpD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,GAAG,CACL,iBAAiB,EACjB;QACE,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,MAAM,CAAC;YACd,OAAO,EAAE,uDAAuD;SACjE;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,sEAAsE;QACtE,wDAAwD;QACxD,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,eAAe,CAAC;QACjD,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;QAC9C,MAAM,QAAQ,GACZ,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACxE,OAAO;YACL,aAAa,EAAE,IAAI;YACnB,GAAG,EAAE,SAAS;gBACZ,CAAC,CAAC,QAAQ;gBACV,CAAC,CAAC,SAAS;oBACT,CAAC,CAAC,QAAQ;oBACV,CAAC,CAAC,QAAQ;wBACR,CAAC,CAAC,SAAS;wBACX,CAAC,CAAC,gBAAgB;SACzB,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,qBAAqB;IAErB,GAAG,CAAC,GAAG,CACL,YAAY,EACZ,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,yCAAyC,EAAE,EAAE,EACpF,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CACxD,CAAC;IAEF,2EAA2E;IAC3E,6EAA6E;IAC7E,gDAAgD;IAChD,GAAG,CAAC,IAAI,CACN,YAAY,EACZ;QACE,MAAM,EAAE,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE;QACxD,MAAM,EAAE;YACN,IAAI,EAAE,CAAC,QAAQ,CAAC;YAChB,OAAO,EAAE,kDAAkD;YAC3D,IAAI,EAAE,gBAAgB;SACvB;KACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC7D,OAAO,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;IAC9C,CAAC,CACF,CAAC;IAEF,GAAG,CAAC,MAAM,CACR,gBAAgB,EAChB;QACE,MAAM,EAAE,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE;QACxD,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,QAAQ,EAAE;KAC/E,EACD,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACnB,MAAM,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,EAAE,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,EAAE;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QAC7D,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAChC,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { type FastifyInstance } from "fastify";
2
+ import type { Database } from "../db/client.js";
3
+ import type { EmbeddingService } from "../service/embedding.js";
4
+ export interface ServerContext {
5
+ db: Database["db"];
6
+ embedding: EmbeddingService;
7
+ }
8
+ export interface BuildServerOpts extends ServerContext {
9
+ logLevel?: string;
10
+ webDist?: string;
11
+ }
12
+ export declare function buildServer(opts: BuildServerOpts): Promise<FastifyInstance>;
@@ -0,0 +1,282 @@
1
+ import cookie from "@fastify/cookie";
2
+ import cors from "@fastify/cors";
3
+ import rateLimit from "@fastify/rate-limit";
4
+ import fastifyStatic from "@fastify/static";
5
+ import swagger from "@fastify/swagger";
6
+ import swaggerUi from "@fastify/swagger-ui";
7
+ import { existsSync, readFileSync } from "node:fs";
8
+ import path from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ import Fastify from "fastify";
11
+ import { hasZodFastifySchemaValidationErrors, isResponseSerializationError, jsonSchemaTransform, serializerCompiler, validatorCompiler } from "fastify-type-provider-zod";
12
+ import { consumeSession } from "../service/sessions.js";
13
+ import { consumeToken } from "../service/tokens.js";
14
+ import { VERSION } from "../version.js";
15
+ import { registerRoutes } from "./routes.js";
16
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
+ function resolveWebDist(explicit) {
18
+ const envPath = process.env.BOTNOTE_WEB_DIST;
19
+ const candidates = [
20
+ explicit,
21
+ envPath,
22
+ path.resolve(__dirname, "../../web/dist"),
23
+ path.resolve(__dirname, "../../../web/dist")
24
+ ].filter(Boolean);
25
+ for (const c of candidates) {
26
+ if (existsSync(path.join(c, "index.html")))
27
+ return c;
28
+ }
29
+ return null;
30
+ }
31
+ /** Default CORS allowlist. Add public origins via BOTNOTE_CORS_ORIGINS
32
+ * (comma-separated). The tailnet + localhost entries stay for ops access. */
33
+ function defaultCorsOrigins() {
34
+ const built = [
35
+ "http://127.0.0.1:4280",
36
+ "http://localhost:4280",
37
+ "http://100.68.185.53:4280",
38
+ "https://botnote.net"
39
+ ];
40
+ const extra = process.env.BOTNOTE_CORS_ORIGINS;
41
+ if (extra) {
42
+ for (const o of extra.split(",").map((s) => s.trim()).filter(Boolean)) {
43
+ if (!built.includes(o))
44
+ built.push(o);
45
+ }
46
+ }
47
+ return built;
48
+ }
49
+ /** Read the caller's real IP. cf-connecting-ip is set by Cloudflare for every
50
+ * request that goes through CF Tunnel — without it, rate-limit would key on
51
+ * the tunnel's loopback address and the whole world would share one bucket. */
52
+ function clientIp(req) {
53
+ const cf = req.headers["cf-connecting-ip"];
54
+ if (typeof cf === "string" && cf)
55
+ return cf;
56
+ const xff = req.headers["x-forwarded-for"];
57
+ if (typeof xff === "string" && xff)
58
+ return xff.split(",")[0].trim();
59
+ return req.ip;
60
+ }
61
+ export async function buildServer(opts) {
62
+ const isProduction = process.env.NODE_ENV === "production";
63
+ const app = Fastify({
64
+ logger: { level: opts.logLevel ?? "info" },
65
+ // We're behind CF Tunnel (or tailscale serve). Trust the immediate proxy so
66
+ // req.ip is sensible, but rely on clientIp() above for rate-limit keying.
67
+ trustProxy: true
68
+ }).withTypeProvider();
69
+ app.setValidatorCompiler(validatorCompiler);
70
+ app.setSerializerCompiler(serializerCompiler);
71
+ await app.register(cookie, {
72
+ // No global secret/sign — session cookies carry an opaque random token
73
+ // that maps to a row in `sessions`; tamper-detection isn't useful since
74
+ // we already validate every value against the DB.
75
+ hook: "onRequest"
76
+ });
77
+ await app.register(cors, {
78
+ origin: defaultCorsOrigins(),
79
+ // credentials: true so cookies can be sent across origins (browser will
80
+ // refuse to attach cookies on a fetch to a different origin otherwise).
81
+ credentials: true,
82
+ methods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
83
+ allowedHeaders: ["content-type", "authorization"],
84
+ maxAge: 86400
85
+ });
86
+ await app.register(rateLimit, {
87
+ // 1000 req/min per IP — generous enough that a Claude Code session burst
88
+ // and the Web UI's 30s polling combined don't trip it; tight enough that a
89
+ // leaked token can't quietly exfil thousands of entities per second.
90
+ max: 1000,
91
+ timeWindow: "1 minute",
92
+ keyGenerator: (req) => clientIp(req),
93
+ // /health is a probe; /assets/* are dozens of static files per page load.
94
+ // Counting them would cap real API headroom for no benefit.
95
+ allowList: (req) => {
96
+ const u = req.url;
97
+ return u === "/health" || u.startsWith("/health?") || u.startsWith("/assets/");
98
+ },
99
+ errorResponseBuilder: (_req, ctx) => ({
100
+ error: "rate_limited",
101
+ message: `Too many requests. Try again in ${Math.ceil(ctx.ttl / 1000)}s.`,
102
+ retryAfter: Math.ceil(ctx.ttl / 1000)
103
+ })
104
+ });
105
+ if (!isProduction) {
106
+ await app.register(swagger, {
107
+ openapi: {
108
+ info: {
109
+ title: "botnote",
110
+ version: VERSION,
111
+ description: "Notion for bots. A lightweight, agent-first project + notes + memory store."
112
+ },
113
+ servers: [
114
+ {
115
+ url: `http://localhost:${process.env.BOTNOTE_PORT ?? 4280}`,
116
+ description: "local"
117
+ }
118
+ ],
119
+ tags: [
120
+ { name: "projects", description: "Project lifecycle and AGENTS.md." },
121
+ { name: "entities", description: "Tasks and notes." },
122
+ { name: "tasks", description: "Task calendar queries (range + backlog)." },
123
+ { name: "search", description: "Hybrid retrieval." },
124
+ { name: "brief", description: "Opening brief — agent context bundle." },
125
+ { name: "tokens", description: "API token management." }
126
+ ]
127
+ },
128
+ transform: jsonSchemaTransform
129
+ });
130
+ await app.register(swaggerUi, {
131
+ routePrefix: "/docs",
132
+ uiConfig: {
133
+ docExpansion: "list",
134
+ deepLinking: false
135
+ }
136
+ });
137
+ app.log.info("swagger UI mounted at /docs (dev mode)");
138
+ }
139
+ else {
140
+ app.log.info("swagger UI disabled (production)");
141
+ }
142
+ // ----- error handler -----
143
+ // Strip Node stack traces from all responses. Zod validation errors return
144
+ // field-level info but no schema dump; Fastify's own errors get a safe
145
+ // summary.
146
+ app.setErrorHandler((error, req, reply) => {
147
+ const err = error;
148
+ if (hasZodFastifySchemaValidationErrors(err)) {
149
+ return reply.code(400).send({
150
+ error: "validation_error",
151
+ message: "Request body or params failed validation.",
152
+ details: err.validation.map((v) => ({
153
+ path: v.instancePath || v.schemaPath || "",
154
+ message: v.message ?? ""
155
+ }))
156
+ });
157
+ }
158
+ if (isResponseSerializationError(err)) {
159
+ req.log.error({ err }, "response serialization failed");
160
+ return reply.code(500).send({ error: "server_error" });
161
+ }
162
+ // fastify-rate-limit's errorResponseBuilder result lands here without a
163
+ // statusCode prop, so it would otherwise fall through to the 500 bucket
164
+ // and lose the retryAfter signal. Surface it explicitly.
165
+ const errAny = err;
166
+ if (errAny.error === "rate_limited") {
167
+ return reply.code(429).send({
168
+ error: "rate_limited",
169
+ message: err.message,
170
+ retryAfter: errAny.retryAfter
171
+ });
172
+ }
173
+ const sc = err.statusCode;
174
+ if (typeof sc === "number" && sc >= 400 && sc < 500) {
175
+ return reply.code(sc).send({ error: err.code ?? "client_error", message: err.message });
176
+ }
177
+ req.log.error({ err }, "unhandled error");
178
+ return reply.code(500).send({ error: "server_error" });
179
+ });
180
+ // ----- auth -----
181
+ // Trust direct connections (tailnet IP, 127.0.0.1, the macmini-local Web UI)
182
+ // and only enforce bearer tokens on requests that came through Cloudflare
183
+ // Tunnel (or any reverse proxy that sets cf-connecting-ip / x-forwarded-for).
184
+ // This lets Boss browse the local tailnet URL without a login flow while
185
+ // keeping the public botnote.net surface fully token-gated.
186
+ const requireAuth = process.env.BOTNOTE_REQUIRE_AUTH === "1";
187
+ if (requireAuth) {
188
+ // IMPORTANT: register at onRequest, not preHandler. fastify-type-provider-zod
189
+ // runs schema validation at preValidation, which is BEFORE preHandler — so
190
+ // a preHandler auth gate lets an unauthenticated POST get a 400 zod error
191
+ // back, leaking the request schema. onRequest fires first; no body has been
192
+ // parsed yet, but headers and cookies are all we need.
193
+ app.addHook("onRequest", async (req, reply) => {
194
+ if (!req.url.startsWith("/v1/"))
195
+ return;
196
+ // The login endpoint is the entry point — gating it would be a
197
+ // chicken-and-egg loop. Logout is fine to leave open too (it's a noop
198
+ // when no cookie is present).
199
+ if (req.url.startsWith("/v1/auth/login") ||
200
+ req.url.startsWith("/v1/auth/logout")) {
201
+ return;
202
+ }
203
+ const viaProxy = !!req.headers["cf-connecting-ip"] || !!req.headers["x-forwarded-for"];
204
+ if (!viaProxy)
205
+ return; // direct tailnet/localhost — trusted
206
+ // Browser path: session cookie set by /v1/auth/login.
207
+ const cookieToken = req.cookies?.botnote_session;
208
+ if (cookieToken) {
209
+ const session = await consumeSession(opts.db, cookieToken);
210
+ if (session)
211
+ return;
212
+ }
213
+ // CLI / MCP path: bearer token.
214
+ const auth = req.headers.authorization;
215
+ if (auth && auth.startsWith("Bearer ")) {
216
+ const plaintext = auth.slice("Bearer ".length).trim();
217
+ const tok = await consumeToken(opts.db, plaintext);
218
+ if (tok)
219
+ return;
220
+ }
221
+ return reply.code(401).send({ error: "unauthenticated" });
222
+ });
223
+ app.log.info("auth: required for /v1/* via reverse proxy (cookie or bearer; direct tailnet trusted)");
224
+ }
225
+ else {
226
+ app.log.info("auth: disabled (set BOTNOTE_REQUIRE_AUTH=1 to enforce)");
227
+ }
228
+ await registerRoutes(app, { db: opts.db, embedding: opts.embedding });
229
+ const webDist = resolveWebDist(opts.webDist);
230
+ if (webDist) {
231
+ await app.register(fastifyStatic, {
232
+ root: webDist,
233
+ prefix: "/",
234
+ // wildcard: true lets fastify-static answer for every file under root
235
+ // (notably /assets/<hash>.js / .css). Without it, those paths fall
236
+ // through to the not-found handler and the SPA fallback sends back
237
+ // index.html — the browser then tries to parse HTML as a JS module and
238
+ // the page renders blank.
239
+ wildcard: true,
240
+ decorateReply: true,
241
+ cacheControl: true,
242
+ maxAge: "1d",
243
+ immutable: false
244
+ });
245
+ const indexHtmlPath = path.join(webDist, "index.html");
246
+ // Re-read on each request. The file is ~700 bytes so the cost is trivial,
247
+ // and this guarantees we never serve a stale HTML that points to an old
248
+ // asset hash after `pnpm build` overwrites the bundle — that's how the
249
+ // page goes blank when the daemon outlives the previous build.
250
+ const readIndex = () => readFileSync(indexHtmlPath, "utf8");
251
+ // Explicit `/` route wins over fastify-static's wildcard so the homepage
252
+ // always serves fresh HTML with no-cache, sidestepping the long max-age
253
+ // applied to /assets/*.
254
+ app.get("/", async (_req, reply) => {
255
+ reply.type("text/html; charset=utf-8");
256
+ reply.header("cache-control", "no-cache");
257
+ return readIndex();
258
+ });
259
+ app.setNotFoundHandler(async (req, reply) => {
260
+ const url = req.url;
261
+ if (url.startsWith("/v1") ||
262
+ url.startsWith("/docs") ||
263
+ url === "/health" ||
264
+ url.startsWith("/health?") ||
265
+ url.startsWith("/assets/")) {
266
+ return reply.code(404).send({ error: "not_found", path: url });
267
+ }
268
+ // SPA fallback for client-side routes (/today, /p/:key, etc.). Send the
269
+ // file fresh from disk with no-cache so the browser never pins it to
270
+ // an old asset hash after a redeploy.
271
+ reply.type("text/html; charset=utf-8");
272
+ reply.header("cache-control", "no-cache");
273
+ return readIndex();
274
+ });
275
+ app.log.info(`web UI served from ${webDist}`);
276
+ }
277
+ else {
278
+ app.log.warn("web/dist not found; UI not served (BOTNOTE_WEB_DIST or build required)");
279
+ }
280
+ return app;
281
+ }
282
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/rest/server.ts"],"names":[],"mappings":"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"}