@braidhq/server 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/LICENSE +21 -0
  2. package/dist/app.d.ts +7 -0
  3. package/dist/app.d.ts.map +1 -0
  4. package/dist/app.js +71 -0
  5. package/dist/app.js.map +1 -0
  6. package/dist/composeFs.d.ts +20 -0
  7. package/dist/composeFs.d.ts.map +1 -0
  8. package/dist/composeFs.js +134 -0
  9. package/dist/composeFs.js.map +1 -0
  10. package/dist/composition.d.ts +49 -0
  11. package/dist/composition.d.ts.map +1 -0
  12. package/dist/composition.js +43 -0
  13. package/dist/composition.js.map +1 -0
  14. package/dist/index.d.ts +5 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +5 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/infrastructure/agent/ClaudeCodeAgentBinding.d.ts +8 -0
  19. package/dist/infrastructure/agent/ClaudeCodeAgentBinding.d.ts.map +1 -0
  20. package/dist/infrastructure/agent/ClaudeCodeAgentBinding.js +62 -0
  21. package/dist/infrastructure/agent/ClaudeCodeAgentBinding.js.map +1 -0
  22. package/dist/infrastructure/agent/SubprocessSkillRunner.d.ts +54 -0
  23. package/dist/infrastructure/agent/SubprocessSkillRunner.d.ts.map +1 -0
  24. package/dist/infrastructure/agent/SubprocessSkillRunner.js +240 -0
  25. package/dist/infrastructure/agent/SubprocessSkillRunner.js.map +1 -0
  26. package/dist/infrastructure/agent/asyncQueue.d.ts +22 -0
  27. package/dist/infrastructure/agent/asyncQueue.d.ts.map +1 -0
  28. package/dist/infrastructure/agent/asyncQueue.js +43 -0
  29. package/dist/infrastructure/agent/asyncQueue.js.map +1 -0
  30. package/dist/infrastructure/agent/mcpConfig.d.ts +18 -0
  31. package/dist/infrastructure/agent/mcpConfig.d.ts.map +1 -0
  32. package/dist/infrastructure/agent/mcpConfig.js +47 -0
  33. package/dist/infrastructure/agent/mcpConfig.js.map +1 -0
  34. package/dist/infrastructure/agent/streamJsonParser.d.ts +20 -0
  35. package/dist/infrastructure/agent/streamJsonParser.d.ts.map +1 -0
  36. package/dist/infrastructure/agent/streamJsonParser.js +44 -0
  37. package/dist/infrastructure/agent/streamJsonParser.js.map +1 -0
  38. package/dist/infrastructure/agent/subprocessEventStream.d.ts +26 -0
  39. package/dist/infrastructure/agent/subprocessEventStream.d.ts.map +1 -0
  40. package/dist/infrastructure/agent/subprocessEventStream.js +112 -0
  41. package/dist/infrastructure/agent/subprocessEventStream.js.map +1 -0
  42. package/dist/infrastructure/fs/FsClarifyTicketRepository.d.ts +13 -0
  43. package/dist/infrastructure/fs/FsClarifyTicketRepository.d.ts.map +1 -0
  44. package/dist/infrastructure/fs/FsClarifyTicketRepository.js +33 -0
  45. package/dist/infrastructure/fs/FsClarifyTicketRepository.js.map +1 -0
  46. package/dist/infrastructure/fs/FsDecisionRepository.d.ts +13 -0
  47. package/dist/infrastructure/fs/FsDecisionRepository.d.ts.map +1 -0
  48. package/dist/infrastructure/fs/FsDecisionRepository.js +56 -0
  49. package/dist/infrastructure/fs/FsDecisionRepository.js.map +1 -0
  50. package/dist/infrastructure/fs/FsProposalRepository.d.ts +14 -0
  51. package/dist/infrastructure/fs/FsProposalRepository.d.ts.map +1 -0
  52. package/dist/infrastructure/fs/FsProposalRepository.js +40 -0
  53. package/dist/infrastructure/fs/FsProposalRepository.js.map +1 -0
  54. package/dist/infrastructure/fs/FsRunRepository.d.ts +21 -0
  55. package/dist/infrastructure/fs/FsRunRepository.d.ts.map +1 -0
  56. package/dist/infrastructure/fs/FsRunRepository.js +88 -0
  57. package/dist/infrastructure/fs/FsRunRepository.js.map +1 -0
  58. package/dist/infrastructure/fs/FsSkillRegistry.d.ts +34 -0
  59. package/dist/infrastructure/fs/FsSkillRegistry.d.ts.map +1 -0
  60. package/dist/infrastructure/fs/FsSkillRegistry.js +143 -0
  61. package/dist/infrastructure/fs/FsSkillRegistry.js.map +1 -0
  62. package/dist/infrastructure/fs/FsStatusedJsonRepository.d.ts +35 -0
  63. package/dist/infrastructure/fs/FsStatusedJsonRepository.d.ts.map +1 -0
  64. package/dist/infrastructure/fs/FsStatusedJsonRepository.js +79 -0
  65. package/dist/infrastructure/fs/FsStatusedJsonRepository.js.map +1 -0
  66. package/dist/infrastructure/fs/FsWorkspaceRepository.d.ts +21 -0
  67. package/dist/infrastructure/fs/FsWorkspaceRepository.d.ts.map +1 -0
  68. package/dist/infrastructure/fs/FsWorkspaceRepository.js +87 -0
  69. package/dist/infrastructure/fs/FsWorkspaceRepository.js.map +1 -0
  70. package/dist/infrastructure/fs/WorkspaceRegistryFile.d.ts +17 -0
  71. package/dist/infrastructure/fs/WorkspaceRegistryFile.d.ts.map +1 -0
  72. package/dist/infrastructure/fs/WorkspaceRegistryFile.js +58 -0
  73. package/dist/infrastructure/fs/WorkspaceRegistryFile.js.map +1 -0
  74. package/dist/infrastructure/fs/frontmatter.d.ts +13 -0
  75. package/dist/infrastructure/fs/frontmatter.d.ts.map +1 -0
  76. package/dist/infrastructure/fs/frontmatter.js +46 -0
  77. package/dist/infrastructure/fs/frontmatter.js.map +1 -0
  78. package/dist/infrastructure/fs/jsonFileStore.d.ts +5 -0
  79. package/dist/infrastructure/fs/jsonFileStore.d.ts.map +1 -0
  80. package/dist/infrastructure/fs/jsonFileStore.js +29 -0
  81. package/dist/infrastructure/fs/jsonFileStore.js.map +1 -0
  82. package/dist/infrastructure/fs/paths.d.ts +22 -0
  83. package/dist/infrastructure/fs/paths.d.ts.map +1 -0
  84. package/dist/infrastructure/fs/paths.js +46 -0
  85. package/dist/infrastructure/fs/paths.js.map +1 -0
  86. package/dist/infrastructure/fs/productManifestWriter.d.ts +22 -0
  87. package/dist/infrastructure/fs/productManifestWriter.d.ts.map +1 -0
  88. package/dist/infrastructure/fs/productManifestWriter.js +75 -0
  89. package/dist/infrastructure/fs/productManifestWriter.js.map +1 -0
  90. package/dist/infrastructure/oauth/GoogleOAuth.d.ts +60 -0
  91. package/dist/infrastructure/oauth/GoogleOAuth.d.ts.map +1 -0
  92. package/dist/infrastructure/oauth/GoogleOAuth.js +114 -0
  93. package/dist/infrastructure/oauth/GoogleOAuth.js.map +1 -0
  94. package/dist/infrastructure/orphanReaper.d.ts +18 -0
  95. package/dist/infrastructure/orphanReaper.d.ts.map +1 -0
  96. package/dist/infrastructure/orphanReaper.js +42 -0
  97. package/dist/infrastructure/orphanReaper.js.map +1 -0
  98. package/dist/infrastructure/secrets/SecretStore.d.ts +36 -0
  99. package/dist/infrastructure/secrets/SecretStore.d.ts.map +1 -0
  100. package/dist/infrastructure/secrets/SecretStore.js +44 -0
  101. package/dist/infrastructure/secrets/SecretStore.js.map +1 -0
  102. package/dist/middleware/cors.d.ts +11 -0
  103. package/dist/middleware/cors.d.ts.map +1 -0
  104. package/dist/middleware/cors.js +30 -0
  105. package/dist/middleware/cors.js.map +1 -0
  106. package/dist/middleware/error.d.ts +3 -0
  107. package/dist/middleware/error.d.ts.map +1 -0
  108. package/dist/middleware/error.js +52 -0
  109. package/dist/middleware/error.js.map +1 -0
  110. package/dist/middleware/workspaceId.d.ts +10 -0
  111. package/dist/middleware/workspaceId.d.ts.map +1 -0
  112. package/dist/middleware/workspaceId.js +9 -0
  113. package/dist/middleware/workspaceId.js.map +1 -0
  114. package/dist/routes/clarify.d.ts +8 -0
  115. package/dist/routes/clarify.d.ts.map +1 -0
  116. package/dist/routes/clarify.js +84 -0
  117. package/dist/routes/clarify.js.map +1 -0
  118. package/dist/routes/decisions.d.ts +7 -0
  119. package/dist/routes/decisions.d.ts.map +1 -0
  120. package/dist/routes/decisions.js +30 -0
  121. package/dist/routes/decisions.js.map +1 -0
  122. package/dist/routes/edges.d.ts +7 -0
  123. package/dist/routes/edges.d.ts.map +1 -0
  124. package/dist/routes/edges.js +30 -0
  125. package/dist/routes/edges.js.map +1 -0
  126. package/dist/routes/health.d.ts +3 -0
  127. package/dist/routes/health.d.ts.map +1 -0
  128. package/dist/routes/health.js +10 -0
  129. package/dist/routes/health.js.map +1 -0
  130. package/dist/routes/helpers.d.ts +5 -0
  131. package/dist/routes/helpers.d.ts.map +1 -0
  132. package/dist/routes/helpers.js +14 -0
  133. package/dist/routes/helpers.js.map +1 -0
  134. package/dist/routes/model.d.ts +7 -0
  135. package/dist/routes/model.d.ts.map +1 -0
  136. package/dist/routes/model.js +12 -0
  137. package/dist/routes/model.js.map +1 -0
  138. package/dist/routes/nodes.d.ts +7 -0
  139. package/dist/routes/nodes.d.ts.map +1 -0
  140. package/dist/routes/nodes.js +47 -0
  141. package/dist/routes/nodes.js.map +1 -0
  142. package/dist/routes/oauth.d.ts +20 -0
  143. package/dist/routes/oauth.d.ts.map +1 -0
  144. package/dist/routes/oauth.js +107 -0
  145. package/dist/routes/oauth.js.map +1 -0
  146. package/dist/routes/ontology.d.ts +8 -0
  147. package/dist/routes/ontology.d.ts.map +1 -0
  148. package/dist/routes/ontology.js +21 -0
  149. package/dist/routes/ontology.js.map +1 -0
  150. package/dist/routes/proposals.d.ts +10 -0
  151. package/dist/routes/proposals.d.ts.map +1 -0
  152. package/dist/routes/proposals.js +80 -0
  153. package/dist/routes/proposals.js.map +1 -0
  154. package/dist/routes/runs.d.ts +9 -0
  155. package/dist/routes/runs.d.ts.map +1 -0
  156. package/dist/routes/runs.js +73 -0
  157. package/dist/routes/runs.js.map +1 -0
  158. package/dist/routes/skills.d.ts +9 -0
  159. package/dist/routes/skills.d.ts.map +1 -0
  160. package/dist/routes/skills.js +42 -0
  161. package/dist/routes/skills.js.map +1 -0
  162. package/dist/routes/workspaceEvents.d.ts +14 -0
  163. package/dist/routes/workspaceEvents.d.ts.map +1 -0
  164. package/dist/routes/workspaceEvents.js +37 -0
  165. package/dist/routes/workspaceEvents.js.map +1 -0
  166. package/dist/routes/workspaces.d.ts +8 -0
  167. package/dist/routes/workspaces.d.ts.map +1 -0
  168. package/dist/routes/workspaces.js +167 -0
  169. package/dist/routes/workspaces.js.map +1 -0
  170. package/dist/server.d.ts +2 -0
  171. package/dist/server.d.ts.map +1 -0
  172. package/dist/server.js +33 -0
  173. package/dist/server.js.map +1 -0
  174. package/package.json +49 -0
@@ -0,0 +1,30 @@
1
+ import { DecisionAction, DecisionId } from '@braidhq/schema';
2
+ import { zValidator } from '@hono/zod-validator';
3
+ import { Hono } from 'hono';
4
+ import { z } from 'zod';
5
+ import { getWorkspaceId } from '../middleware/workspaceId.js';
6
+ import { assertEntityInWorkspace } from './helpers.js';
7
+ const ListQuerySchema = z.object({
8
+ action: z.union([DecisionAction, z.array(DecisionAction)]).optional(),
9
+ limit: z.coerce.number().int().positive().optional(),
10
+ offset: z.coerce.number().int().nonnegative().optional(),
11
+ });
12
+ export function createDecisionsRouter(deps) {
13
+ const router = new Hono();
14
+ router.get('/', zValidator('query', ListQuerySchema), async (context) => {
15
+ const workspaceId = getWorkspaceId(context);
16
+ const { action, limit, offset } = context.req.valid('query');
17
+ const actions = action === undefined ? undefined : Array.isArray(action) ? action : [action];
18
+ const decisions = await deps.decisionRepository.list({ workspaceId, actions, limit, offset });
19
+ return context.json({ items: decisions });
20
+ });
21
+ router.get('/:decisionId', async (context) => {
22
+ const workspaceId = getWorkspaceId(context);
23
+ const decisionId = DecisionId.parse(context.req.param('decisionId'));
24
+ const decision = await deps.decisionRepository.load(decisionId);
25
+ assertEntityInWorkspace(workspaceId, decision.workspaceId, 'Decision', decisionId);
26
+ return context.json(decision);
27
+ });
28
+ return router;
29
+ }
30
+ //# sourceMappingURL=decisions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decisions.js","sourceRoot":"","sources":["../../src/routes/decisions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAEtD,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACrE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACpD,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;CACzD,CAAC,CAAA;AAMF,MAAM,UAAU,qBAAqB,CAAC,IAAyB;IAC7D,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAA;IAEzB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,OAAO,EAAE,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACtE,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;QAC3C,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC5D,MAAM,OAAO,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;QAC5F,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QAC7F,OAAO,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAA;IAC3C,CAAC,CAAC,CAAA;IAEF,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAC3C,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;QAC3C,MAAM,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAA;QACpE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAC/D,uBAAuB,CAAC,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,UAAU,EAAE,UAAU,CAAC,CAAA;QAClF,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC/B,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { ModelService } from '@braidhq/core';
2
+ import { Hono } from 'hono';
3
+ export interface EdgesRouterDeps {
4
+ modelService: ModelService;
5
+ }
6
+ export declare function createEdgesRouter(deps: EdgesRouterDeps): Hono;
7
+ //# sourceMappingURL=edges.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edges.d.ts","sourceRoot":"","sources":["../../src/routes/edges.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAGjD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAY3B,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,YAAY,CAAA;CAC3B;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAkB7D"}
@@ -0,0 +1,30 @@
1
+ import { EdgeTypeId, NodeId } from '@braidhq/schema';
2
+ import { zValidator } from '@hono/zod-validator';
3
+ import { Hono } from 'hono';
4
+ import { z } from 'zod';
5
+ import { getWorkspaceId } from '../middleware/workspaceId.js';
6
+ const ListQuerySchema = z.object({
7
+ type: z.union([EdgeTypeId, z.array(EdgeTypeId)]).optional(),
8
+ fromNodeId: NodeId.optional(),
9
+ toNodeId: NodeId.optional(),
10
+ limit: z.coerce.number().int().positive().optional(),
11
+ offset: z.coerce.number().int().nonnegative().optional(),
12
+ });
13
+ export function createEdgesRouter(deps) {
14
+ const router = new Hono();
15
+ router.get('/', zValidator('query', ListQuerySchema), async (context) => {
16
+ const workspaceId = getWorkspaceId(context);
17
+ const { type, fromNodeId, toNodeId, limit, offset } = context.req.valid('query');
18
+ const types = type === undefined ? undefined : Array.isArray(type) ? type : [type];
19
+ const edges = await deps.modelService.listEdges(workspaceId, {
20
+ types,
21
+ fromNodeId,
22
+ toNodeId,
23
+ limit,
24
+ offset,
25
+ });
26
+ return context.json({ items: edges });
27
+ });
28
+ return router;
29
+ }
30
+ //# sourceMappingURL=edges.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edges.js","sourceRoot":"","sources":["../../src/routes/edges.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAE7D,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC3D,UAAU,EAAE,MAAM,CAAC,QAAQ,EAAE;IAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE;IAC3B,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACpD,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;CACzD,CAAC,CAAA;AAMF,MAAM,UAAU,iBAAiB,CAAC,IAAqB;IACrD,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAA;IAEzB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,OAAO,EAAE,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACtE,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;QAC3C,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAChF,MAAM,KAAK,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAClF,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,WAAW,EAAE;YAC3D,KAAK;YACL,UAAU;YACV,QAAQ;YACR,KAAK;YACL,MAAM;SACP,CAAC,CAAA;QACF,OAAO,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ export declare const healthRouter: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,eAAO,MAAM,YAAY,4EAAa,CAAA"}
@@ -0,0 +1,10 @@
1
+ import { Hono } from 'hono';
2
+ export const healthRouter = new Hono();
3
+ healthRouter.get('/', (context) => {
4
+ return context.json({
5
+ status: 'ok',
6
+ service: 'braid-server',
7
+ timestamp: new Date().toISOString(),
8
+ });
9
+ });
10
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,IAAI,EAAE,CAAA;AAEtC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE;IAChC,OAAO,OAAO,CAAC,IAAI,CAAC;QAClB,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,cAAc;QACvB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,5 @@
1
+ import type { Workspace, WorkspaceRepository } from '@braidhq/core';
2
+ import type { WorkspaceId } from '@braidhq/schema';
3
+ export declare function assertEntityInWorkspace(expected: WorkspaceId, actual: WorkspaceId, entityKind: string, entityId: string): void;
4
+ export declare function loadWorkspaceById(workspaceId: WorkspaceId, workspaceRepository: WorkspaceRepository): Promise<Workspace>;
5
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/routes/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAGlD,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,IAAI,CAIN;AAED,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,WAAW,EACxB,mBAAmB,EAAE,mBAAmB,GACvC,OAAO,CAAC,SAAS,CAAC,CAMpB"}
@@ -0,0 +1,14 @@
1
+ import { NotFoundError } from '@braidhq/core';
2
+ export function assertEntityInWorkspace(expected, actual, entityKind, entityId) {
3
+ if (expected !== actual) {
4
+ throw new NotFoundError(`${entityKind} "${entityId}" not found in workspace "${expected}"`);
5
+ }
6
+ }
7
+ export async function loadWorkspaceById(workspaceId, workspaceRepository) {
8
+ const workspaces = await workspaceRepository.list();
9
+ const match = workspaces.find(workspace => workspace.id === workspaceId);
10
+ if (!match)
11
+ throw new NotFoundError(`Workspace "${workspaceId}" not registered`);
12
+ return match;
13
+ }
14
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/routes/helpers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE7C,MAAM,UAAU,uBAAuB,CACrC,QAAqB,EACrB,MAAmB,EACnB,UAAkB,EAClB,QAAgB;IAEhB,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,aAAa,CAAC,GAAG,UAAU,KAAK,QAAQ,6BAA6B,QAAQ,GAAG,CAAC,CAAA;IAC7F,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,WAAwB,EACxB,mBAAwC;IAExC,MAAM,UAAU,GAAG,MAAM,mBAAmB,CAAC,IAAI,EAAE,CAAA;IACnD,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,WAAW,CAAC,CAAA;IACxE,IAAI,CAAC,KAAK;QACR,MAAM,IAAI,aAAa,CAAC,cAAc,WAAW,kBAAkB,CAAC,CAAA;IACtE,OAAO,KAAK,CAAA;AACd,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { ModelService } from '@braidhq/core';
2
+ import { Hono } from 'hono';
3
+ export interface ModelRouterDeps {
4
+ modelService: ModelService;
5
+ }
6
+ export declare function createModelRouter(deps: ModelRouterDeps): Hono;
7
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/routes/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAG3B,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,YAAY,CAAA;CAC3B;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAU7D"}
@@ -0,0 +1,12 @@
1
+ import { Hono } from 'hono';
2
+ import { getWorkspaceId } from '../middleware/workspaceId.js';
3
+ export function createModelRouter(deps) {
4
+ const router = new Hono();
5
+ router.get('/snapshot', async (context) => {
6
+ const workspaceId = getWorkspaceId(context);
7
+ const snapshot = await deps.modelService.getSnapshot(workspaceId);
8
+ return context.json(snapshot);
9
+ });
10
+ return router;
11
+ }
12
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/routes/model.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAM7D,MAAM,UAAU,iBAAiB,CAAC,IAAqB;IACrD,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAA;IAEzB,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACxC,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;QAC3C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,WAAW,CAAC,CAAA;QACjE,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC/B,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { ModelService } from '@braidhq/core';
2
+ import { Hono } from 'hono';
3
+ export interface NodesRouterDeps {
4
+ modelService: ModelService;
5
+ }
6
+ export declare function createNodesRouter(deps: NodesRouterDeps): Hono;
7
+ //# sourceMappingURL=nodes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../../src/routes/nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAGjD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAgB3B,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,YAAY,CAAA;CAC3B;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAkC7D"}
@@ -0,0 +1,47 @@
1
+ import { NodeId, NodeStatus, NodeTypeId } from '@braidhq/schema';
2
+ import { zValidator } from '@hono/zod-validator';
3
+ import { Hono } from 'hono';
4
+ import { z } from 'zod';
5
+ import { getWorkspaceId } from '../middleware/workspaceId.js';
6
+ const ListQuerySchema = z.object({
7
+ type: z.union([NodeTypeId, z.array(NodeTypeId)]).optional(),
8
+ status: z.union([NodeStatus, z.array(NodeStatus)]).optional(),
9
+ q: z.string().optional(),
10
+ limit: z.coerce.number().int().positive().optional(),
11
+ offset: z.coerce.number().int().nonnegative().optional(),
12
+ });
13
+ const ScopeQuerySchema = z.object({
14
+ depth: z.coerce.number().int().positive().default(2),
15
+ });
16
+ export function createNodesRouter(deps) {
17
+ const router = new Hono();
18
+ router.get('/', zValidator('query', ListQuerySchema), async (context) => {
19
+ const workspaceId = getWorkspaceId(context);
20
+ const { type, status, q, limit, offset } = context.req.valid('query');
21
+ const types = type === undefined ? undefined : Array.isArray(type) ? type : [type];
22
+ const statuses = status === undefined ? undefined : Array.isArray(status) ? status : [status];
23
+ const nodes = await deps.modelService.findNodes(workspaceId, {
24
+ types,
25
+ statuses,
26
+ nameContains: q,
27
+ limit,
28
+ offset,
29
+ });
30
+ return context.json({ items: nodes });
31
+ });
32
+ router.get('/:nodeId', async (context) => {
33
+ const workspaceId = getWorkspaceId(context);
34
+ const nodeId = NodeId.parse(context.req.param('nodeId'));
35
+ const node = await deps.modelService.getNode(workspaceId, nodeId);
36
+ return context.json(node);
37
+ });
38
+ router.get('/:nodeId/scope', zValidator('query', ScopeQuerySchema), async (context) => {
39
+ const workspaceId = getWorkspaceId(context);
40
+ const nodeId = NodeId.parse(context.req.param('nodeId'));
41
+ const { depth } = context.req.valid('query');
42
+ const snapshot = await deps.modelService.scopeOf(workspaceId, nodeId, depth);
43
+ return context.json(snapshot);
44
+ });
45
+ return router;
46
+ }
47
+ //# sourceMappingURL=nodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nodes.js","sourceRoot":"","sources":["../../src/routes/nodes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAE7D,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC3D,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC7D,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACxB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACpD,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;CACzD,CAAC,CAAA;AAEF,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;CACrD,CAAC,CAAA;AAMF,MAAM,UAAU,iBAAiB,CAAC,IAAqB;IACrD,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAA;IAEzB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,OAAO,EAAE,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACtE,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;QAC3C,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACrE,MAAM,KAAK,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAClF,MAAM,QAAQ,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;QAC7F,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,WAAW,EAAE;YAC3D,KAAK;YACL,QAAQ;YACR,YAAY,EAAE,CAAC;YACf,KAAK;YACL,MAAM;SACP,CAAC,CAAA;QACF,OAAO,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACvC,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;QAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;QACxD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;QACjE,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC3B,CAAC,CAAC,CAAA;IAEF,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,UAAU,CAAC,OAAO,EAAE,gBAAgB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACpF,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;QAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;QACxD,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC5C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;QAC5E,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC/B,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { GoogleOAuth } from '../infrastructure/oauth/GoogleOAuth.js';
2
+ import type { SecretStore } from '../infrastructure/secrets/SecretStore.js';
3
+ import { Hono } from 'hono';
4
+ export interface OAuthRouterDeps {
5
+ readonly secretStore: SecretStore;
6
+ readonly google?: GoogleOAuth;
7
+ }
8
+ /**
9
+ * OAuth routes for source-loader providers that need user consent.
10
+ *
11
+ * POST /oauth/google/start → { authorizationUrl }
12
+ * GET /oauth/google/callback?code=…&state=… → HTML page that closes the popup
13
+ *
14
+ * Pending state is kept in process memory. The flow is short-lived
15
+ * (single browser round-trip); a server restart cancels in-flight flows,
16
+ * which is acceptable for a local desktop / single-user install. SaaS
17
+ * deployments should swap the in-memory `pending` map for a shared store.
18
+ */
19
+ export declare function createOAuthRouter(deps: OAuthRouterDeps): Hono;
20
+ //# sourceMappingURL=oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/routes/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAY,MAAM,wCAAwC,CAAA;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAA;AAE3E,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAW3B,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAC9B;AASD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAqD7D"}
@@ -0,0 +1,107 @@
1
+ import { zValidator } from '@hono/zod-validator';
2
+ import { Hono } from 'hono';
3
+ import { z } from 'zod';
4
+ import { createOAuthState, createPkceVerifier } from '../infrastructure/oauth/GoogleOAuth.js';
5
+ const DRIVE_READONLY_SCOPE = 'https://www.googleapis.com/auth/drive.readonly';
6
+ const StartBodySchema = z.object({
7
+ workspaceId: z.string().min(1),
8
+ sourceId: z.string().min(1),
9
+ });
10
+ /**
11
+ * OAuth routes for source-loader providers that need user consent.
12
+ *
13
+ * POST /oauth/google/start → { authorizationUrl }
14
+ * GET /oauth/google/callback?code=…&state=… → HTML page that closes the popup
15
+ *
16
+ * Pending state is kept in process memory. The flow is short-lived
17
+ * (single browser round-trip); a server restart cancels in-flight flows,
18
+ * which is acceptable for a local desktop / single-user install. SaaS
19
+ * deployments should swap the in-memory `pending` map for a shared store.
20
+ */
21
+ export function createOAuthRouter(deps) {
22
+ const router = new Hono();
23
+ const pending = new Map();
24
+ router.post('/google/start', zValidator('json', StartBodySchema), async (context) => {
25
+ if (!deps.google) {
26
+ return context.json({
27
+ error: 'Google OAuth is not configured on this server. Set BRAID_GOOGLE_CLIENT_ID + BRAID_GOOGLE_CLIENT_SECRET (and BRAID_GOOGLE_REDIRECT_URI if not the default) and restart.',
28
+ }, 503);
29
+ }
30
+ const { workspaceId, sourceId } = context.req.valid('json');
31
+ const state = createOAuthState();
32
+ const codeVerifier = createPkceVerifier();
33
+ pending.set(state, { workspaceId, sourceId, codeVerifier, createdAt: Date.now() });
34
+ sweepStale(pending);
35
+ const authorizationUrl = deps.google.buildAuthorizationUrl({
36
+ scopes: [DRIVE_READONLY_SCOPE],
37
+ state,
38
+ codeVerifier,
39
+ });
40
+ return context.json({ authorizationUrl });
41
+ });
42
+ router.get('/google/callback', async (context) => {
43
+ const state = context.req.query('state');
44
+ const code = context.req.query('code');
45
+ const error = context.req.query('error');
46
+ if (error)
47
+ return context.html(renderCallbackPage({ ok: false, message: `Google returned: ${error}` }), 400);
48
+ if (!state || !code)
49
+ return context.html(renderCallbackPage({ ok: false, message: 'Missing state or code query parameter.' }), 400);
50
+ if (!deps.google)
51
+ return context.html(renderCallbackPage({ ok: false, message: 'OAuth not configured.' }), 503);
52
+ const flow = pending.get(state);
53
+ pending.delete(state);
54
+ if (!flow)
55
+ return context.html(renderCallbackPage({ ok: false, message: 'State token not recognised (probably expired or already used).' }), 400);
56
+ try {
57
+ const tokens = await deps.google.exchangeCode({ code, codeVerifier: flow.codeVerifier });
58
+ await persistTokens(deps.secretStore, flow.workspaceId, flow.sourceId, tokens);
59
+ return context.html(renderCallbackPage({ ok: true, message: 'Connected. You can close this window.' }));
60
+ }
61
+ catch (err) {
62
+ return context.html(renderCallbackPage({
63
+ ok: false,
64
+ message: err instanceof Error ? err.message : String(err),
65
+ }), 500);
66
+ }
67
+ });
68
+ return router;
69
+ }
70
+ async function persistTokens(store, workspaceId, sourceId, tokens) {
71
+ await store.write('oauth-google', `${workspaceId}--${sourceId}`, tokens);
72
+ }
73
+ function sweepStale(pending) {
74
+ const cutoff = Date.now() - 10 * 60 * 1000;
75
+ for (const [state, flow] of pending) {
76
+ if (flow.createdAt < cutoff)
77
+ pending.delete(state);
78
+ }
79
+ }
80
+ function renderCallbackPage(input) {
81
+ // Tiny self-contained HTML. Tells the popup opener and closes itself.
82
+ // Inline style so the page works without any asset pipeline.
83
+ const colour = input.ok ? '#16a34a' : '#dc2626';
84
+ const status = input.ok ? 'success' : 'error';
85
+ return `<!doctype html>
86
+ <html><head><meta charset="utf-8"><title>Braid OAuth</title>
87
+ <style>
88
+ body { font: 14px -apple-system, system-ui, sans-serif; background: #fafafa; color: #1a1a1a; margin: 0; padding: 3rem; }
89
+ .card { max-width: 28rem; margin: 0 auto; background: white; border-radius: 8px; padding: 2rem; box-shadow: 0 1px 3px rgba(0,0,0,0.08); }
90
+ h1 { font-size: 1rem; margin: 0 0 0.5rem; color: ${colour}; }
91
+ p { margin: 0; color: #525252; line-height: 1.5; }
92
+ </style>
93
+ </head><body>
94
+ <div class="card">
95
+ <h1>${status === 'success' ? 'Connected to Google' : 'Authorization failed'}</h1>
96
+ <p>${escapeHtml(input.message)}</p>
97
+ </div>
98
+ <script>
99
+ try { window.opener?.postMessage({ source: 'braid-oauth', provider: 'google', status: ${JSON.stringify(status)} }, '*'); } catch (_e) {}
100
+ setTimeout(() => { try { window.close(); } catch (_e) {} }, 1500);
101
+ </script>
102
+ </body></html>`;
103
+ }
104
+ function escapeHtml(s) {
105
+ return s.replace(/[&<>"']/g, ch => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', '\'': '&#39;' })[ch]);
106
+ }
107
+ //# sourceMappingURL=oauth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/routes/oauth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { PluginRegistry, WorkspaceRepository } from '@braidhq/core';
2
+ import { Hono } from 'hono';
3
+ export interface OntologyRouterDeps {
4
+ workspaceRepository: WorkspaceRepository;
5
+ pluginRegistry: PluginRegistry;
6
+ }
7
+ export declare function createOntologyRouter(deps: OntologyRouterDeps): Hono;
8
+ //# sourceMappingURL=ontology.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ontology.d.ts","sourceRoot":"","sources":["../../src/routes/ontology.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAExE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAG3B,MAAM,WAAW,kBAAkB;IACjC,mBAAmB,EAAE,mBAAmB,CAAA;IACxC,cAAc,EAAE,cAAc,CAAA;CAC/B;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAkBnE"}
@@ -0,0 +1,21 @@
1
+ import { NotFoundError } from '@braidhq/core';
2
+ import { Hono } from 'hono';
3
+ import { getWorkspaceId } from '../middleware/workspaceId.js';
4
+ export function createOntologyRouter(deps) {
5
+ const router = new Hono();
6
+ router.get('/', async (context) => {
7
+ const workspaceId = getWorkspaceId(context);
8
+ const workspaces = await deps.workspaceRepository.list();
9
+ const workspace = workspaces.find(ws => ws.id === workspaceId);
10
+ if (!workspace)
11
+ throw new NotFoundError(`Workspace "${workspaceId}" not registered`);
12
+ const ontology = deps.pluginRegistry.requireOntology(workspace.productManifest.ontologyId);
13
+ return context.json({
14
+ ontologyId: ontology.ontologyId,
15
+ nodeTypes: ontology.nodeTypes,
16
+ edgeTypes: ontology.edgeTypes,
17
+ });
18
+ });
19
+ return router;
20
+ }
21
+ //# sourceMappingURL=ontology.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ontology.js","sourceRoot":"","sources":["../../src/routes/ontology.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAO7D,MAAM,UAAU,oBAAoB,CAAC,IAAwB;IAC3D,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAA;IAEzB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAChC,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;QAC3C,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,CAAA;QACxD,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,WAAW,CAAC,CAAA;QAC9D,IAAI,CAAC,SAAS;YACZ,MAAM,IAAI,aAAa,CAAC,cAAc,WAAW,kBAAkB,CAAC,CAAA;QACtE,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,SAAS,CAAC,eAAe,CAAC,UAAU,CAAC,CAAA;QAC1F,OAAO,OAAO,CAAC,IAAI,CAAC;YAClB,UAAU,EAAE,QAAQ,CAAC,UAAU;YAC/B,SAAS,EAAE,QAAQ,CAAC,SAAS;YAC7B,SAAS,EAAE,QAAQ,CAAC,SAAS;SAC9B,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { HITLService, ModelRepository, ProposalRepository, ValidationService } from '@braidhq/core';
2
+ import { Hono } from 'hono';
3
+ export interface ProposalsRouterDeps {
4
+ hitlService: HITLService;
5
+ proposalRepository: ProposalRepository;
6
+ modelRepository: ModelRepository;
7
+ validationService: ValidationService;
8
+ }
9
+ export declare function createProposalsRouter(deps: ProposalsRouterDeps): Hono;
10
+ //# sourceMappingURL=proposals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposals.d.ts","sourceRoot":"","sources":["../../src/routes/proposals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAGxG,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAyB3B,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,WAAW,CAAA;IACxB,kBAAkB,EAAE,kBAAkB,CAAA;IACtC,eAAe,EAAE,eAAe,CAAA;IAChC,iBAAiB,EAAE,iBAAiB,CAAA;CACrC;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAuErE"}
@@ -0,0 +1,80 @@
1
+ import { ProposalDraft, ProposalId, ProposalStatus, UserId } from '@braidhq/schema';
2
+ import { zValidator } from '@hono/zod-validator';
3
+ import { Hono } from 'hono';
4
+ import { z } from 'zod';
5
+ import { getWorkspaceId } from '../middleware/workspaceId.js';
6
+ import { assertEntityInWorkspace } from './helpers.js';
7
+ const ListQuerySchema = z.object({
8
+ status: z.union([ProposalStatus, z.array(ProposalStatus)]).optional(),
9
+ limit: z.coerce.number().int().positive().optional(),
10
+ offset: z.coerce.number().int().nonnegative().optional(),
11
+ });
12
+ const ApplyBodySchema = z.object({
13
+ userId: UserId,
14
+ });
15
+ const RejectBodySchema = z.object({
16
+ reason: z.string().min(1),
17
+ userId: UserId,
18
+ });
19
+ // Skill-facing create. Body must carry `workspaceId` matching the route
20
+ // param; we let zod parse the rest of the ProposalDraft fields and let
21
+ // HITLService.submitProposal validate ops against the live graph.
22
+ const CreateBodySchema = ProposalDraft.omit({ workspaceId: true });
23
+ export function createProposalsRouter(deps) {
24
+ const router = new Hono();
25
+ // Create. Returns 201 + the saved proposal on success, 400 + `issues`
26
+ // when ops fail validation. Skills call this instead of writing JSON files
27
+ // so they pick up validation errors on the write call, not on apply.
28
+ router.post('/', zValidator('json', CreateBodySchema), async (context) => {
29
+ const workspaceId = getWorkspaceId(context);
30
+ const body = context.req.valid('json');
31
+ const proposal = await deps.hitlService.submitProposal({ workspaceId, ...body });
32
+ return context.json(proposal.toData(), 201);
33
+ });
34
+ router.get('/', zValidator('query', ListQuerySchema), async (context) => {
35
+ const workspaceId = getWorkspaceId(context);
36
+ const { status, limit, offset } = context.req.valid('query');
37
+ const statuses = status === undefined ? undefined : Array.isArray(status) ? status : [status];
38
+ const proposals = await deps.proposalRepository.list({ workspaceId, statuses, limit, offset });
39
+ return context.json({ items: proposals.map(proposal => proposal.toData()) });
40
+ });
41
+ router.get('/:proposalId', async (context) => {
42
+ const workspaceId = getWorkspaceId(context);
43
+ const proposalId = ProposalId.parse(context.req.param('proposalId'));
44
+ const proposal = await deps.proposalRepository.load(proposalId);
45
+ assertEntityInWorkspace(workspaceId, proposal.workspaceId, 'Proposal', proposalId);
46
+ return context.json(proposal.toData());
47
+ });
48
+ // Pre-apply check: returns the validation issues a skill would hit if it
49
+ // tried to apply this proposal right now. Skills call this after writing
50
+ // their proposal so they can iterate on issues without the user in the loop.
51
+ router.get('/:proposalId/validate', async (context) => {
52
+ const workspaceId = getWorkspaceId(context);
53
+ const proposalId = ProposalId.parse(context.req.param('proposalId'));
54
+ const proposal = await deps.proposalRepository.load(proposalId);
55
+ assertEntityInWorkspace(workspaceId, proposal.workspaceId, 'Proposal', proposalId);
56
+ const snapshot = await deps.modelRepository.load(workspaceId);
57
+ const result = await deps.validationService.validateOperations(snapshot, proposal.operations);
58
+ return context.json(result);
59
+ });
60
+ router.post('/:proposalId/apply', zValidator('json', ApplyBodySchema), async (context) => {
61
+ const workspaceId = getWorkspaceId(context);
62
+ const proposalId = ProposalId.parse(context.req.param('proposalId'));
63
+ const { userId } = context.req.valid('json');
64
+ const proposal = await deps.proposalRepository.load(proposalId);
65
+ assertEntityInWorkspace(workspaceId, proposal.workspaceId, 'Proposal', proposalId);
66
+ const decision = await deps.hitlService.applyProposal(proposalId, userId);
67
+ return context.json(decision);
68
+ });
69
+ router.post('/:proposalId/reject', zValidator('json', RejectBodySchema), async (context) => {
70
+ const workspaceId = getWorkspaceId(context);
71
+ const proposalId = ProposalId.parse(context.req.param('proposalId'));
72
+ const { reason, userId } = context.req.valid('json');
73
+ const proposal = await deps.proposalRepository.load(proposalId);
74
+ assertEntityInWorkspace(workspaceId, proposal.workspaceId, 'Proposal', proposalId);
75
+ const decision = await deps.hitlService.rejectProposal(proposalId, reason, userId);
76
+ return context.json(decision);
77
+ });
78
+ return router;
79
+ }
80
+ //# sourceMappingURL=proposals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposals.js","sourceRoot":"","sources":["../../src/routes/proposals.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { RunRepository, SkillRunner, WorkspaceRepository } from '@braidhq/core';
2
+ import { Hono } from 'hono';
3
+ export interface RunsRouterDeps {
4
+ readonly runRepository: RunRepository;
5
+ readonly skillRunner: SkillRunner;
6
+ readonly workspaceRepository: WorkspaceRepository;
7
+ }
8
+ export declare function createRunsRouter(deps: RunsRouterDeps): Hono;
9
+ //# sourceMappingURL=runs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs.d.ts","sourceRoot":"","sources":["../../src/routes/runs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,mBAAmB,EACpB,MAAM,eAAe,CAAA;AAItB,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAM3B,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAA;IACrC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,mBAAmB,EAAE,mBAAmB,CAAA;CAClD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAyE3D"}
@@ -0,0 +1,73 @@
1
+ import { NotFoundError } from '@braidhq/core';
2
+ import { SkillRunId } from '@braidhq/schema';
3
+ import { Hono } from 'hono';
4
+ import { streamSSE } from 'hono/streaming';
5
+ import { createAsyncQueue } from '../infrastructure/agent/asyncQueue.js';
6
+ import { getWorkspaceId } from '../middleware/workspaceId.js';
7
+ import { loadWorkspaceById } from './helpers.js';
8
+ export function createRunsRouter(deps) {
9
+ const router = new Hono();
10
+ router.get('/', async (context) => {
11
+ const workspace = await loadWorkspaceById(getWorkspaceId(context), deps.workspaceRepository);
12
+ const items = await deps.runRepository.listRecords(workspace);
13
+ return context.json({ items });
14
+ });
15
+ // Replay the persisted JSONL log and, if the run is still active, tail new
16
+ // events as they arrive. Clients can open / close / reopen this stream
17
+ // freely; the underlying subprocess and event log are not affected.
18
+ router.get('/:runId/events', async (context) => {
19
+ const workspace = await loadWorkspaceById(getWorkspaceId(context), deps.workspaceRepository);
20
+ const runId = SkillRunId.parse(context.req.param('runId'));
21
+ return streamSSE(context, async (stream) => {
22
+ if (!deps.skillRunner.isActive(runId)) {
23
+ for await (const event of deps.runRepository.readEvents(workspace, runId)) {
24
+ await stream.writeSSE({ event: event.type, data: JSON.stringify(event) });
25
+ }
26
+ return;
27
+ }
28
+ // Subscribe BEFORE reading JSONL. positionAtSubscribe is the snapshot of
29
+ // how many events were already persisted, so we read exactly that many
30
+ // from disk and rely on the live listener for everything from there on.
31
+ const queue = createAsyncQueue();
32
+ const { unsubscribe, positionAtSubscribe } = deps.skillRunner.subscribe(runId, (event) => {
33
+ queue.push(event);
34
+ });
35
+ try {
36
+ let delivered = 0;
37
+ for await (const event of deps.runRepository.readEvents(workspace, runId)) {
38
+ if (delivered >= positionAtSubscribe)
39
+ break;
40
+ await stream.writeSSE({ event: event.type, data: JSON.stringify(event) });
41
+ delivered++;
42
+ }
43
+ for await (const event of queue.iterate()) {
44
+ await stream.writeSSE({ event: event.type, data: JSON.stringify(event) });
45
+ if (event.type === 'completed' || event.type === 'error') {
46
+ queue.end();
47
+ break;
48
+ }
49
+ }
50
+ }
51
+ finally {
52
+ unsubscribe();
53
+ }
54
+ });
55
+ });
56
+ // SIGTERM the underlying claude subprocess. The drain loop emits a
57
+ // `completed` event with the actual exit code, which the SSE tailers
58
+ // receive normally. 404 if the run already finished.
59
+ router.post('/:runId/cancel', async (context) => {
60
+ const runId = SkillRunId.parse(context.req.param('runId'));
61
+ await deps.skillRunner.cancel(runId);
62
+ return context.body(null, 204);
63
+ });
64
+ router.delete('/sessions/:sessionId', async (context) => {
65
+ const sessionId = context.req.param('sessionId');
66
+ if (!sessionId)
67
+ throw new NotFoundError('sessionId is required');
68
+ await deps.skillRunner.forgetSession(sessionId);
69
+ return context.body(null, 204);
70
+ });
71
+ return router;
72
+ }
73
+ //# sourceMappingURL=runs.js.map