@cat-factory/integrations 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +68 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +84 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/modules/datadog/DatadogClient.d.ts +54 -0
  7. package/dist/modules/datadog/DatadogClient.d.ts.map +1 -0
  8. package/dist/modules/datadog/DatadogClient.js +132 -0
  9. package/dist/modules/datadog/DatadogClient.js.map +1 -0
  10. package/dist/modules/datadog/DatadogReleaseHealthProvider.d.ts +30 -0
  11. package/dist/modules/datadog/DatadogReleaseHealthProvider.d.ts.map +1 -0
  12. package/dist/modules/datadog/DatadogReleaseHealthProvider.js +101 -0
  13. package/dist/modules/datadog/DatadogReleaseHealthProvider.js.map +1 -0
  14. package/dist/modules/datadog/datadog.logic.d.ts +37 -0
  15. package/dist/modules/datadog/datadog.logic.d.ts.map +1 -0
  16. package/dist/modules/datadog/datadog.logic.js +90 -0
  17. package/dist/modules/datadog/datadog.logic.js.map +1 -0
  18. package/dist/modules/documents/ConfluenceProvider.d.ts +29 -0
  19. package/dist/modules/documents/ConfluenceProvider.d.ts.map +1 -0
  20. package/dist/modules/documents/ConfluenceProvider.js +180 -0
  21. package/dist/modules/documents/ConfluenceProvider.js.map +1 -0
  22. package/dist/modules/documents/DocumentConnectionService.d.ts +30 -0
  23. package/dist/modules/documents/DocumentConnectionService.d.ts.map +1 -0
  24. package/dist/modules/documents/DocumentConnectionService.js +69 -0
  25. package/dist/modules/documents/DocumentConnectionService.js.map +1 -0
  26. package/dist/modules/documents/DocumentImportService.d.ts +34 -0
  27. package/dist/modules/documents/DocumentImportService.d.ts.map +1 -0
  28. package/dist/modules/documents/DocumentImportService.js +83 -0
  29. package/dist/modules/documents/DocumentImportService.js.map +1 -0
  30. package/dist/modules/documents/DocumentLinkService.d.ts +31 -0
  31. package/dist/modules/documents/DocumentLinkService.d.ts.map +1 -0
  32. package/dist/modules/documents/DocumentLinkService.js +75 -0
  33. package/dist/modules/documents/DocumentLinkService.js.map +1 -0
  34. package/dist/modules/documents/DocumentPlannerService.d.ts +23 -0
  35. package/dist/modules/documents/DocumentPlannerService.d.ts.map +1 -0
  36. package/dist/modules/documents/DocumentPlannerService.js +96 -0
  37. package/dist/modules/documents/DocumentPlannerService.js.map +1 -0
  38. package/dist/modules/documents/GitHubDocsProvider.d.ts +42 -0
  39. package/dist/modules/documents/GitHubDocsProvider.d.ts.map +1 -0
  40. package/dist/modules/documents/GitHubDocsProvider.js +86 -0
  41. package/dist/modules/documents/GitHubDocsProvider.js.map +1 -0
  42. package/dist/modules/documents/NotionProvider.d.ts +32 -0
  43. package/dist/modules/documents/NotionProvider.d.ts.map +1 -0
  44. package/dist/modules/documents/NotionProvider.js +221 -0
  45. package/dist/modules/documents/NotionProvider.js.map +1 -0
  46. package/dist/modules/documents/confluence.logic.d.ts +37 -0
  47. package/dist/modules/documents/confluence.logic.d.ts.map +1 -0
  48. package/dist/modules/documents/confluence.logic.js +133 -0
  49. package/dist/modules/documents/confluence.logic.js.map +1 -0
  50. package/dist/modules/documents/documents.logic.d.ts +22 -0
  51. package/dist/modules/documents/documents.logic.d.ts.map +1 -0
  52. package/dist/modules/documents/documents.logic.js +138 -0
  53. package/dist/modules/documents/documents.logic.js.map +1 -0
  54. package/dist/modules/documents/github-docs.logic.d.ts +52 -0
  55. package/dist/modules/documents/github-docs.logic.d.ts.map +1 -0
  56. package/dist/modules/documents/github-docs.logic.js +94 -0
  57. package/dist/modules/documents/github-docs.logic.js.map +1 -0
  58. package/dist/modules/documents/notion.logic.d.ts +31 -0
  59. package/dist/modules/documents/notion.logic.d.ts.map +1 -0
  60. package/dist/modules/documents/notion.logic.js +142 -0
  61. package/dist/modules/documents/notion.logic.js.map +1 -0
  62. package/dist/modules/email/EmailConnectionService.d.ts +34 -0
  63. package/dist/modules/email/EmailConnectionService.d.ts.map +1 -0
  64. package/dist/modules/email/EmailConnectionService.js +82 -0
  65. package/dist/modules/email/EmailConnectionService.js.map +1 -0
  66. package/dist/modules/email/adapters.d.ts +39 -0
  67. package/dist/modules/email/adapters.d.ts.map +1 -0
  68. package/dist/modules/email/adapters.js +79 -0
  69. package/dist/modules/email/adapters.js.map +1 -0
  70. package/dist/modules/environments/EnvironmentConnectionService.d.ts +42 -0
  71. package/dist/modules/environments/EnvironmentConnectionService.d.ts.map +1 -0
  72. package/dist/modules/environments/EnvironmentConnectionService.js +120 -0
  73. package/dist/modules/environments/EnvironmentConnectionService.js.map +1 -0
  74. package/dist/modules/environments/EnvironmentProvisioningService.d.ts +56 -0
  75. package/dist/modules/environments/EnvironmentProvisioningService.d.ts.map +1 -0
  76. package/dist/modules/environments/EnvironmentProvisioningService.js +153 -0
  77. package/dist/modules/environments/EnvironmentProvisioningService.js.map +1 -0
  78. package/dist/modules/environments/EnvironmentTeardownService.d.ts +24 -0
  79. package/dist/modules/environments/EnvironmentTeardownService.d.ts.map +1 -0
  80. package/dist/modules/environments/EnvironmentTeardownService.js +54 -0
  81. package/dist/modules/environments/EnvironmentTeardownService.js.map +1 -0
  82. package/dist/modules/environments/HttpEnvironmentProvider.d.ts +30 -0
  83. package/dist/modules/environments/HttpEnvironmentProvider.d.ts.map +1 -0
  84. package/dist/modules/environments/HttpEnvironmentProvider.js +316 -0
  85. package/dist/modules/environments/HttpEnvironmentProvider.js.map +1 -0
  86. package/dist/modules/environments/environments.logic.d.ts +50 -0
  87. package/dist/modules/environments/environments.logic.d.ts.map +1 -0
  88. package/dist/modules/environments/environments.logic.js +257 -0
  89. package/dist/modules/environments/environments.logic.js.map +1 -0
  90. package/dist/modules/github/GitHubInstallationService.d.ts +66 -0
  91. package/dist/modules/github/GitHubInstallationService.d.ts.map +1 -0
  92. package/dist/modules/github/GitHubInstallationService.js +143 -0
  93. package/dist/modules/github/GitHubInstallationService.js.map +1 -0
  94. package/dist/modules/github/GitHubService.d.ts +29 -0
  95. package/dist/modules/github/GitHubService.d.ts.map +1 -0
  96. package/dist/modules/github/GitHubService.js +61 -0
  97. package/dist/modules/github/GitHubService.js.map +1 -0
  98. package/dist/modules/github/GitHubSyncService.d.ts +97 -0
  99. package/dist/modules/github/GitHubSyncService.d.ts.map +1 -0
  100. package/dist/modules/github/GitHubSyncService.js +241 -0
  101. package/dist/modules/github/GitHubSyncService.js.map +1 -0
  102. package/dist/modules/github/RepoProvisioningService.d.ts +26 -0
  103. package/dist/modules/github/RepoProvisioningService.d.ts.map +1 -0
  104. package/dist/modules/github/RepoProvisioningService.js +36 -0
  105. package/dist/modules/github/RepoProvisioningService.js.map +1 -0
  106. package/dist/modules/github/WebhookService.d.ts +28 -0
  107. package/dist/modules/github/WebhookService.d.ts.map +1 -0
  108. package/dist/modules/github/WebhookService.js +156 -0
  109. package/dist/modules/github/WebhookService.js.map +1 -0
  110. package/dist/modules/github/projection.logic.d.ts +95 -0
  111. package/dist/modules/github/projection.logic.d.ts.map +1 -0
  112. package/dist/modules/github/projection.logic.js +94 -0
  113. package/dist/modules/github/projection.logic.js.map +1 -0
  114. package/dist/modules/github/provisioning.logic.d.ts +11 -0
  115. package/dist/modules/github/provisioning.logic.d.ts.map +1 -0
  116. package/dist/modules/github/provisioning.logic.js +18 -0
  117. package/dist/modules/github/provisioning.logic.js.map +1 -0
  118. package/dist/modules/incident/incident.logic.d.ts +16 -0
  119. package/dist/modules/incident/incident.logic.d.ts.map +1 -0
  120. package/dist/modules/incident/incident.logic.js +23 -0
  121. package/dist/modules/incident/incident.logic.js.map +1 -0
  122. package/dist/modules/incidentio/IncidentIoEnrichmentProvider.d.ts +26 -0
  123. package/dist/modules/incidentio/IncidentIoEnrichmentProvider.d.ts.map +1 -0
  124. package/dist/modules/incidentio/IncidentIoEnrichmentProvider.js +84 -0
  125. package/dist/modules/incidentio/IncidentIoEnrichmentProvider.js.map +1 -0
  126. package/dist/modules/pagerduty/PagerDutyEnrichmentProvider.d.ts +27 -0
  127. package/dist/modules/pagerduty/PagerDutyEnrichmentProvider.d.ts.map +1 -0
  128. package/dist/modules/pagerduty/PagerDutyEnrichmentProvider.js +65 -0
  129. package/dist/modules/pagerduty/PagerDutyEnrichmentProvider.js.map +1 -0
  130. package/dist/modules/providers/ApiKeyService.d.ts +73 -0
  131. package/dist/modules/providers/ApiKeyService.d.ts.map +1 -0
  132. package/dist/modules/providers/ApiKeyService.js +122 -0
  133. package/dist/modules/providers/ApiKeyService.js.map +1 -0
  134. package/dist/modules/providers/LocalModelEndpointService.d.ts +52 -0
  135. package/dist/modules/providers/LocalModelEndpointService.d.ts.map +1 -0
  136. package/dist/modules/providers/LocalModelEndpointService.js +131 -0
  137. package/dist/modules/providers/LocalModelEndpointService.js.map +1 -0
  138. package/dist/modules/providers/PersonalSubscriptionService.d.ts +94 -0
  139. package/dist/modules/providers/PersonalSubscriptionService.d.ts.map +1 -0
  140. package/dist/modules/providers/PersonalSubscriptionService.js +218 -0
  141. package/dist/modules/providers/PersonalSubscriptionService.js.map +1 -0
  142. package/dist/modules/providers/ProviderSubscriptionService.d.ts +75 -0
  143. package/dist/modules/providers/ProviderSubscriptionService.d.ts.map +1 -0
  144. package/dist/modules/providers/ProviderSubscriptionService.js +130 -0
  145. package/dist/modules/providers/ProviderSubscriptionService.js.map +1 -0
  146. package/dist/modules/providers/localModelUrl.d.ts +7 -0
  147. package/dist/modules/providers/localModelUrl.d.ts.map +1 -0
  148. package/dist/modules/providers/localModelUrl.js +67 -0
  149. package/dist/modules/providers/localModelUrl.js.map +1 -0
  150. package/dist/modules/providers/providers.logic.d.ts +23 -0
  151. package/dist/modules/providers/providers.logic.d.ts.map +1 -0
  152. package/dist/modules/providers/providers.logic.js +46 -0
  153. package/dist/modules/providers/providers.logic.js.map +1 -0
  154. package/dist/modules/runners/HttpRunnerPoolProvider.d.ts +51 -0
  155. package/dist/modules/runners/HttpRunnerPoolProvider.d.ts.map +1 -0
  156. package/dist/modules/runners/HttpRunnerPoolProvider.js +304 -0
  157. package/dist/modules/runners/HttpRunnerPoolProvider.js.map +1 -0
  158. package/dist/modules/runners/RunnerPoolConnectionService.d.ts +47 -0
  159. package/dist/modules/runners/RunnerPoolConnectionService.d.ts.map +1 -0
  160. package/dist/modules/runners/RunnerPoolConnectionService.js +98 -0
  161. package/dist/modules/runners/RunnerPoolConnectionService.js.map +1 -0
  162. package/dist/modules/runners/RunnerPoolTransport.d.ts +11 -0
  163. package/dist/modules/runners/RunnerPoolTransport.d.ts.map +1 -0
  164. package/dist/modules/runners/RunnerPoolTransport.js +61 -0
  165. package/dist/modules/runners/RunnerPoolTransport.js.map +1 -0
  166. package/dist/modules/runners/runners.logic.d.ts +16 -0
  167. package/dist/modules/runners/runners.logic.d.ts.map +1 -0
  168. package/dist/modules/runners/runners.logic.js +52 -0
  169. package/dist/modules/runners/runners.logic.js.map +1 -0
  170. package/dist/modules/slack/SlackApiClient.d.ts +67 -0
  171. package/dist/modules/slack/SlackApiClient.d.ts.map +1 -0
  172. package/dist/modules/slack/SlackApiClient.js +132 -0
  173. package/dist/modules/slack/SlackApiClient.js.map +1 -0
  174. package/dist/modules/slack/SlackConnectionService.d.ts +41 -0
  175. package/dist/modules/slack/SlackConnectionService.d.ts.map +1 -0
  176. package/dist/modules/slack/SlackConnectionService.js +136 -0
  177. package/dist/modules/slack/SlackConnectionService.js.map +1 -0
  178. package/dist/modules/slack/SlackMemberMappingService.d.ts +17 -0
  179. package/dist/modules/slack/SlackMemberMappingService.d.ts.map +1 -0
  180. package/dist/modules/slack/SlackMemberMappingService.js +28 -0
  181. package/dist/modules/slack/SlackMemberMappingService.js.map +1 -0
  182. package/dist/modules/slack/SlackNotificationChannel.d.ts +45 -0
  183. package/dist/modules/slack/SlackNotificationChannel.d.ts.map +1 -0
  184. package/dist/modules/slack/SlackNotificationChannel.js +84 -0
  185. package/dist/modules/slack/SlackNotificationChannel.js.map +1 -0
  186. package/dist/modules/slack/SlackSettingsService.d.ts +16 -0
  187. package/dist/modules/slack/SlackSettingsService.d.ts.map +1 -0
  188. package/dist/modules/slack/SlackSettingsService.js +41 -0
  189. package/dist/modules/slack/SlackSettingsService.js.map +1 -0
  190. package/dist/modules/slack/slack.logic.d.ts +55 -0
  191. package/dist/modules/slack/slack.logic.d.ts.map +1 -0
  192. package/dist/modules/slack/slack.logic.js +149 -0
  193. package/dist/modules/slack/slack.logic.js.map +1 -0
  194. package/dist/modules/tasks/GitHubIssuesProvider.d.ts +50 -0
  195. package/dist/modules/tasks/GitHubIssuesProvider.d.ts.map +1 -0
  196. package/dist/modules/tasks/GitHubIssuesProvider.js +92 -0
  197. package/dist/modules/tasks/GitHubIssuesProvider.js.map +1 -0
  198. package/dist/modules/tasks/JiraProvider.d.ts +29 -0
  199. package/dist/modules/tasks/JiraProvider.d.ts.map +1 -0
  200. package/dist/modules/tasks/JiraProvider.js +114 -0
  201. package/dist/modules/tasks/JiraProvider.js.map +1 -0
  202. package/dist/modules/tasks/TaskConnectionService.d.ts +30 -0
  203. package/dist/modules/tasks/TaskConnectionService.d.ts.map +1 -0
  204. package/dist/modules/tasks/TaskConnectionService.js +69 -0
  205. package/dist/modules/tasks/TaskConnectionService.js.map +1 -0
  206. package/dist/modules/tasks/TaskImportService.d.ts +34 -0
  207. package/dist/modules/tasks/TaskImportService.d.ts.map +1 -0
  208. package/dist/modules/tasks/TaskImportService.js +96 -0
  209. package/dist/modules/tasks/TaskImportService.js.map +1 -0
  210. package/dist/modules/tasks/TaskLinkService.d.ts +30 -0
  211. package/dist/modules/tasks/TaskLinkService.d.ts.map +1 -0
  212. package/dist/modules/tasks/TaskLinkService.js +56 -0
  213. package/dist/modules/tasks/TaskLinkService.js.map +1 -0
  214. package/dist/modules/tasks/github-issues.logic.d.ts +35 -0
  215. package/dist/modules/tasks/github-issues.logic.d.ts.map +1 -0
  216. package/dist/modules/tasks/github-issues.logic.js +67 -0
  217. package/dist/modules/tasks/github-issues.logic.js.map +1 -0
  218. package/dist/modules/tasks/jira.logic.d.ts +28 -0
  219. package/dist/modules/tasks/jira.logic.d.ts.map +1 -0
  220. package/dist/modules/tasks/jira.logic.js +151 -0
  221. package/dist/modules/tasks/jira.logic.js.map +1 -0
  222. package/dist/modules/tasks/tasks.logic.d.ts +12 -0
  223. package/dist/modules/tasks/tasks.logic.d.ts.map +1 -0
  224. package/dist/modules/tasks/tasks.logic.js +17 -0
  225. package/dist/modules/tasks/tasks.logic.js.map +1 -0
  226. package/dist/modules/tracker/TicketTrackerService.d.ts +45 -0
  227. package/dist/modules/tracker/TicketTrackerService.d.ts.map +1 -0
  228. package/dist/modules/tracker/TicketTrackerService.js +52 -0
  229. package/dist/modules/tracker/TicketTrackerService.js.map +1 -0
  230. package/dist/modules/tracker/base64.d.ts +2 -0
  231. package/dist/modules/tracker/base64.d.ts.map +1 -0
  232. package/dist/modules/tracker/base64.js +18 -0
  233. package/dist/modules/tracker/base64.js.map +1 -0
  234. package/dist/modules/tracker/github.create.logic.d.ts +16 -0
  235. package/dist/modules/tracker/github.create.logic.d.ts.map +1 -0
  236. package/dist/modules/tracker/github.create.logic.js +25 -0
  237. package/dist/modules/tracker/github.create.logic.js.map +1 -0
  238. package/dist/modules/tracker/jira.create.logic.d.ts +31 -0
  239. package/dist/modules/tracker/jira.create.logic.d.ts.map +1 -0
  240. package/dist/modules/tracker/jira.create.logic.js +59 -0
  241. package/dist/modules/tracker/jira.create.logic.js.map +1 -0
  242. package/package.json +36 -0
@@ -0,0 +1,75 @@
1
+ import { assertFound, ValidationError } from '@cat-factory/kernel';
2
+ import { toSourceDocument } from './DocumentImportService.js';
3
+ export class DocumentLinkService {
4
+ deps;
5
+ constructor(deps) {
6
+ this.deps = deps;
7
+ }
8
+ /**
9
+ * Apply a board plan to a workspace. Without `frameId` each planned frame
10
+ * becomes a new top-level frame; with it, the plan's modules and tasks are
11
+ * added inside that existing frame (the planned frames are flattened into it).
12
+ */
13
+ async spawn(workspaceId, plan, frameId) {
14
+ const result = { frames: 0, modules: 0, tasks: 0 };
15
+ if (frameId) {
16
+ const target = assertFound(await this.deps.blockRepository.get(workspaceId, frameId), 'Block', frameId);
17
+ if (target.level !== 'frame') {
18
+ throw new ValidationError('Document structure can only be spawned into a service frame');
19
+ }
20
+ for (const frame of plan.frames) {
21
+ await this.spawnInto(workspaceId, target.id, frame, result);
22
+ }
23
+ return result;
24
+ }
25
+ let column = 0;
26
+ for (const frame of plan.frames) {
27
+ const created = await this.deps.boardService.addFrame(workspaceId, {
28
+ type: frame.type,
29
+ position: { x: 80 + column * 380, y: 80 },
30
+ });
31
+ column += 1;
32
+ result.frames += 1;
33
+ await this.deps.boardService.updateBlock(workspaceId, created.id, {
34
+ title: frame.title,
35
+ ...(frame.description ? { description: frame.description } : {}),
36
+ });
37
+ await this.spawnInto(workspaceId, created.id, frame, result);
38
+ }
39
+ return result;
40
+ }
41
+ /** Add a planned frame's modules and tasks inside an existing frame. */
42
+ async spawnInto(workspaceId, frameId, frame, result) {
43
+ for (const task of frame.tasks) {
44
+ await this.addTask(workspaceId, frameId, task, result);
45
+ }
46
+ for (const planModule of frame.modules) {
47
+ const module = await this.deps.boardService.addModule(workspaceId, frameId, {
48
+ name: planModule.name,
49
+ });
50
+ result.modules += 1;
51
+ for (const task of planModule.tasks) {
52
+ await this.addTask(workspaceId, module.id, task, result);
53
+ }
54
+ }
55
+ }
56
+ async addTask(workspaceId, containerId, task, result) {
57
+ const created = await this.deps.boardService.addTask(workspaceId, containerId, {
58
+ title: task.title,
59
+ });
60
+ result.tasks += 1;
61
+ if (task.description) {
62
+ await this.deps.boardService.updateBlock(workspaceId, created.id, {
63
+ description: task.description,
64
+ });
65
+ }
66
+ }
67
+ /** Attach an imported document to a board block as extra agent context. */
68
+ async linkToBlock(workspaceId, blockId, source, externalId) {
69
+ const block = assertFound(await this.deps.blockRepository.get(workspaceId, blockId), 'Block', blockId);
70
+ const document = assertFound(await this.deps.documentRepository.get(workspaceId, source, externalId), 'Document', externalId);
71
+ await this.deps.documentRepository.linkBlock(workspaceId, source, externalId, block.id);
72
+ return toSourceDocument({ ...document, linkedBlockId: block.id });
73
+ }
74
+ }
75
+ //# sourceMappingURL=DocumentLinkService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocumentLinkService.js","sourceRoot":"","sources":["../../../src/modules/documents/DocumentLinkService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { ModelProvider, ModelProviderResolver, ModelRef } from '@cat-factory/kernel';
2
+ import type { DocumentRecord } from '@cat-factory/kernel';
3
+ import type { DocumentBoardPlan } from '@cat-factory/kernel';
4
+ export interface DocumentPlannerServiceDependencies {
5
+ /**
6
+ * Resolve a {@link ModelProvider} for a workspace's credential scope (DB-backed key
7
+ * pool). Preferred over the static `modelProvider`; the facade supplies it.
8
+ */
9
+ modelProviderResolver?: ModelProviderResolver;
10
+ /** Static planner model provider (e.g. a fake in tests). Used when no resolver is set. */
11
+ modelProvider?: ModelProvider;
12
+ /** Which model to use for planning (the agents' default model ref). */
13
+ modelRef?: ModelRef;
14
+ }
15
+ export declare class DocumentPlannerService {
16
+ private readonly deps;
17
+ constructor(deps: DocumentPlannerServiceDependencies);
18
+ /** Whether LLM planning is available (a model provider/resolver + ref are configured). */
19
+ get llmEnabled(): boolean;
20
+ /** Propose a board structure for an imported document. */
21
+ plan(record: DocumentRecord): Promise<DocumentBoardPlan>;
22
+ }
23
+ //# sourceMappingURL=DocumentPlannerService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocumentPlannerService.d.ts","sourceRoot":"","sources":["../../../src/modules/documents/DocumentPlannerService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACzF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAc5D,MAAM,WAAW,kCAAkC;IACjD;;;OAGG;IACH,qBAAqB,CAAC,EAAE,qBAAqB,CAAA;IAC7C,0FAA0F;IAC1F,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,uEAAuE;IACvE,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACpB;AA4CD,qBAAa,sBAAsB;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,kCAAkC,EAAI;IAEzE,0FAA0F;IAC1F,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,0DAA0D;IACpD,IAAI,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAiC7D;CACF"}
@@ -0,0 +1,96 @@
1
+ import { generateText } from 'ai';
2
+ import { catFactoryObservability } from '@cat-factory/kernel';
3
+ import { coercePlan, markdownToText, planFromHeadings } from './documents.logic.js';
4
+ // DocumentPlannerService: turns an imported document into a proposed board
5
+ // structure (frames → modules → tasks). When a model is configured it asks an
6
+ // LLM, via the provider-agnostic ModelProvider port, to extract the structure;
7
+ // otherwise — or if the LLM response can't be parsed — it falls back to the
8
+ // deterministic heading parser. The LLM is therefore optional: import, link and
9
+ // spawn all work without it. Source-agnostic, because providers normalize bodies
10
+ // to Markdown before they reach here.
11
+ const MAX_BODY_CHARS = 6000;
12
+ const SYSTEM_PROMPT = 'You are a software architect. You convert a product/requirements/RFC document into a ' +
13
+ 'concrete software-architecture board: top-level frames (services), modules within them, ' +
14
+ 'and tasks (units of work). Respond with ONLY a JSON object, no prose, no code fences.';
15
+ function buildUserPrompt(title, body) {
16
+ const text = markdownToText(body).slice(0, MAX_BODY_CHARS);
17
+ return [
18
+ `Document title: ${title}`,
19
+ '',
20
+ 'Document content:',
21
+ text,
22
+ '',
23
+ 'Produce a JSON object of this exact shape:',
24
+ '{',
25
+ ' "frames": [',
26
+ ' {',
27
+ ' "type": "service|api|frontend|database|queue|integration|external",',
28
+ ' "title": "string",',
29
+ ' "description": "string (optional)",',
30
+ ' "modules": [ { "name": "string", "tasks": [ { "title": "string", "description": "string (optional)" } ] } ],',
31
+ ' "tasks": [ { "title": "string", "description": "string (optional)" } ]',
32
+ ' }',
33
+ ' ]',
34
+ '}',
35
+ '',
36
+ 'Group related work into modules; keep titles short and imperative. Output JSON only.',
37
+ ].join('\n');
38
+ }
39
+ /** Pull the first JSON object out of a model response (tolerates code fences). */
40
+ function extractJson(text) {
41
+ const start = text.indexOf('{');
42
+ const end = text.lastIndexOf('}');
43
+ if (start === -1 || end <= start)
44
+ return null;
45
+ try {
46
+ return JSON.parse(text.slice(start, end + 1));
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ }
52
+ export class DocumentPlannerService {
53
+ deps;
54
+ constructor(deps) {
55
+ this.deps = deps;
56
+ }
57
+ /** Whether LLM planning is available (a model provider/resolver + ref are configured). */
58
+ get llmEnabled() {
59
+ return (!!this.deps.modelProviderResolver || !!this.deps.modelProvider) && !!this.deps.modelRef;
60
+ }
61
+ /** Propose a board structure for an imported document. */
62
+ async plan(record) {
63
+ const fallback = () => planFromHeadings(record.source, record.externalId, record.title, record.body);
64
+ if (!this.deps.modelRef || (!this.deps.modelProviderResolver && !this.deps.modelProvider)) {
65
+ return fallback();
66
+ }
67
+ try {
68
+ const provider = this.deps.modelProviderResolver
69
+ ? await this.deps.modelProviderResolver.forScope({ workspaceId: record.workspaceId })
70
+ : this.deps.modelProvider;
71
+ const model = provider.resolve(this.deps.modelRef);
72
+ const { text } = await generateText({
73
+ model,
74
+ system: SYSTEM_PROMPT,
75
+ prompt: buildUserPrompt(record.title, record.body),
76
+ temperature: 0.2,
77
+ // Headroom for a reasoning model's `<think>` before the JSON plan — a
78
+ // tight cap truncates the plan mid-output (finish_reason: length).
79
+ maxOutputTokens: 5000,
80
+ // Label the call for the trace sink (a no-op when no instrumented provider
81
+ // is wired). Not run-scoped, so it surfaces as its own standalone trace.
82
+ providerOptions: catFactoryObservability({
83
+ agentKind: 'document-planner',
84
+ workspaceId: record.workspaceId,
85
+ }),
86
+ });
87
+ const plan = coercePlan(record.source, record.externalId, extractJson(text));
88
+ return plan ?? fallback();
89
+ }
90
+ catch {
91
+ // Any provider/parse failure degrades gracefully to the deterministic plan.
92
+ return fallback();
93
+ }
94
+ }
95
+ }
96
+ //# sourceMappingURL=DocumentPlannerService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocumentPlannerService.js","sourceRoot":"","sources":["../../../src/modules/documents/DocumentPlannerService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { type DocumentContent, type DocumentCredentials, type DocumentSearchResult, type DocumentSourceProvider, type GitHubClient, type GitHubInstallationRepository, type NormalizedConnection } from '@cat-factory/kernel';
2
+ export interface GitHubDocsProviderDependencies {
3
+ githubClient: GitHubClient;
4
+ /** Resolves which installation owns a given repo owner (by account login). */
5
+ installations: GitHubInstallationRepository;
6
+ }
7
+ export declare class GitHubDocsProvider implements DocumentSourceProvider {
8
+ private readonly deps;
9
+ readonly kind: 'github';
10
+ readonly descriptor: {
11
+ source: "confluence" | "github" | "notion";
12
+ label: string;
13
+ icon: string;
14
+ credentialFields: {
15
+ key: string;
16
+ label: string;
17
+ help?: string | undefined;
18
+ placeholder?: string | undefined;
19
+ secret?: boolean | undefined;
20
+ }[];
21
+ refLabel: string;
22
+ refPlaceholder: string;
23
+ searchable?: boolean | undefined;
24
+ };
25
+ constructor(deps: GitHubDocsProviderDependencies);
26
+ /**
27
+ * GitHub docs piggyback on the installed GitHub App, so there is nothing to
28
+ * validate or persist — the connection is a marker. Any supplied fields are
29
+ * ignored (the connect form has none).
30
+ */
31
+ normalizeConnection(_input: DocumentCredentials): NormalizedConnection;
32
+ parseRef(input: string): string | null;
33
+ fetchDocument(_credentials: DocumentCredentials, externalId: string): Promise<DocumentContent>;
34
+ search(_credentials: DocumentCredentials, query: string, workspaceId: string): Promise<DocumentSearchResult[]>;
35
+ /**
36
+ * Find the GitHub App installation whose account owns `owner`. The
37
+ * installation token for that account is what can read the repo's contents,
38
+ * regardless of which workspace triggered the import.
39
+ */
40
+ private resolveInstallationId;
41
+ }
42
+ //# sourceMappingURL=GitHubDocsProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitHubDocsProvider.d.ts","sourceRoot":"","sources":["../../../src/modules/documents/GitHubDocsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,YAAY,EACjB,KAAK,4BAA4B,EACjC,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAA;AAe5B,MAAM,WAAW,8BAA8B;IAC7C,YAAY,EAAE,YAAY,CAAA;IAC1B,8EAA8E;IAC9E,aAAa,EAAE,4BAA4B,CAAA;CAC5C;AAED,qBAAa,kBAAmB,YAAW,sBAAsB;IAInD,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAS;IACjC,QAAQ,CAAC,UAAU;;;;;;;;;;;;;;MAAyB;IAE5C,YAA6B,IAAI,EAAE,8BAA8B,EAAI;IAErE;;;;OAIG;IACH,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,oBAAoB,CAErE;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAErC;IAEK,aAAa,CACjB,YAAY,EAAE,mBAAmB,EACjC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,CAAC,CAoB1B;IAEK,MAAM,CACV,YAAY,EAAE,mBAAmB,EACjC,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAkCjC;IAED;;;;OAIG;YACW,qBAAqB;CAUpC"}
@@ -0,0 +1,86 @@
1
+ import { ConflictError, ValidationError, } from '@cat-factory/kernel';
2
+ import { GITHUB_DOCS_DESCRIPTOR } from './github-docs.logic.js';
3
+ import * as githubDocsLogic from './github-docs.logic.js';
4
+ export class GitHubDocsProvider {
5
+ deps;
6
+ kind = 'github';
7
+ descriptor = GITHUB_DOCS_DESCRIPTOR;
8
+ constructor(deps) {
9
+ this.deps = deps;
10
+ }
11
+ /**
12
+ * GitHub docs piggyback on the installed GitHub App, so there is nothing to
13
+ * validate or persist — the connection is a marker. Any supplied fields are
14
+ * ignored (the connect form has none).
15
+ */
16
+ normalizeConnection(_input) {
17
+ return { credentials: {}, label: 'GitHub' };
18
+ }
19
+ parseRef(input) {
20
+ return githubDocsLogic.parseGitHubDocRef(input);
21
+ }
22
+ async fetchDocument(_credentials, externalId) {
23
+ const id = githubDocsLogic.parseGitHubDocExternalId(externalId);
24
+ if (!id) {
25
+ throw new ValidationError(`"${externalId}" is not a valid GitHub doc reference`);
26
+ }
27
+ const installationId = await this.resolveInstallationId(id.owner);
28
+ const file = await this.deps.githubClient.getFileContent(installationId, { owner: id.owner, repo: id.repo }, id.path);
29
+ if (!file) {
30
+ throw new ConflictError(`GitHub file "${id.path}" was not found in ${id.owner}/${id.repo}`);
31
+ }
32
+ return {
33
+ externalId: githubDocsLogic.githubDocExternalId(id),
34
+ title: githubDocsLogic.githubDocTitle(id.path),
35
+ url: githubDocsLogic.githubDocUrl(id),
36
+ body: file.content,
37
+ };
38
+ }
39
+ async search(_credentials, query, workspaceId) {
40
+ // Scope to *this workspace's* installation so docs never leak across tenants
41
+ // (a deployment may host many installations; a workspace owns exactly one).
42
+ // Code search is account-scoped anyway (GitHub requires an org/user
43
+ // qualifier), which we build from the installation's account.
44
+ const installation = await this.deps.installations.getByWorkspace(workspaceId);
45
+ if (!installation)
46
+ return [];
47
+ const scoped = githubDocsLogic.buildGitHubCodeSearchQuery(query, installation.accountLogin, installation.targetType);
48
+ const hits = await this.deps.githubClient
49
+ .searchCode(installation.installationId, scoped, 20)
50
+ .catch(() => []);
51
+ const out = [];
52
+ const seen = new Set();
53
+ for (const hit of hits) {
54
+ const externalId = githubDocsLogic.githubDocExternalId({
55
+ owner: hit.owner,
56
+ repo: hit.repo,
57
+ path: hit.path,
58
+ });
59
+ if (seen.has(externalId))
60
+ continue;
61
+ seen.add(externalId);
62
+ out.push({
63
+ source: 'github',
64
+ externalId,
65
+ title: githubDocsLogic.githubDocTitle(hit.path),
66
+ url: hit.url,
67
+ excerpt: '',
68
+ });
69
+ }
70
+ return out.slice(0, 20);
71
+ }
72
+ /**
73
+ * Find the GitHub App installation whose account owns `owner`. The
74
+ * installation token for that account is what can read the repo's contents,
75
+ * regardless of which workspace triggered the import.
76
+ */
77
+ async resolveInstallationId(owner) {
78
+ const active = await this.deps.installations.listActive();
79
+ const match = active.find((i) => i.accountLogin.toLowerCase() === owner.toLowerCase());
80
+ if (!match) {
81
+ throw new ConflictError(`No GitHub App installation found for "${owner}". Install the GitHub App on that account to link its docs.`);
82
+ }
83
+ return match.installationId;
84
+ }
85
+ }
86
+ //# sourceMappingURL=GitHubDocsProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GitHubDocsProvider.js","sourceRoot":"","sources":["../../../src/modules/documents/GitHubDocsProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { type DocumentContent, type DocumentCredentials, type DocumentSearchResult, type DocumentSourceProvider, type NormalizedConnection } from '@cat-factory/kernel';
2
+ /** Carries the HTTP status so callers can surface a meaningful error. */
3
+ export declare class NotionApiError extends Error {
4
+ readonly status: number;
5
+ constructor(status: number, message: string);
6
+ }
7
+ export declare class NotionProvider implements DocumentSourceProvider {
8
+ readonly kind: 'notion';
9
+ readonly descriptor: {
10
+ source: "confluence" | "github" | "notion";
11
+ label: string;
12
+ icon: string;
13
+ credentialFields: {
14
+ key: string;
15
+ label: string;
16
+ help?: string | undefined;
17
+ placeholder?: string | undefined;
18
+ secret?: boolean | undefined;
19
+ }[];
20
+ refLabel: string;
21
+ refPlaceholder: string;
22
+ searchable?: boolean | undefined;
23
+ };
24
+ normalizeConnection(input: DocumentCredentials): NormalizedConnection;
25
+ parseRef(input: string): string | null;
26
+ fetchDocument(credentials: DocumentCredentials, externalId: string): Promise<DocumentContent>;
27
+ search(credentials: DocumentCredentials, query: string): Promise<DocumentSearchResult[]>;
28
+ /** Page through a page's top-level blocks (bounded), returning them in order. */
29
+ private fetchBlocks;
30
+ private get;
31
+ }
32
+ //# sourceMappingURL=NotionProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotionProvider.d.ts","sourceRoot":"","sources":["../../../src/modules/documents/NotionProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAA;AAuB5B,yEAAyE;AACzE,qBAAa,cAAe,SAAQ,KAAK;IAErC,QAAQ,CAAC,MAAM,EAAE,MAAM;IADzB,YACW,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EAIhB;CACF;AAkGD,qBAAa,cAAe,YAAW,sBAAsB;IAC3D,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAS;IACjC,QAAQ,CAAC,UAAU;;;;;;;;;;;;;;MAAoB;IAEvC,mBAAmB,CAAC,KAAK,EAAE,mBAAmB,GAAG,oBAAoB,CAMpE;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAErC;IAEK,aAAa,CACjB,WAAW,EAAE,mBAAmB,EAChC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,CAAC,CAe1B;IAEK,MAAM,CAAC,WAAW,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CA6B7F;IAED,iFAAiF;YACnE,WAAW;YAqBX,GAAG;CA+BlB"}
@@ -0,0 +1,221 @@
1
+ import { ValidationError, } from '@cat-factory/kernel';
2
+ import { NOTION_DESCRIPTOR } from './notion.logic.js';
3
+ import * as notionLogic from './notion.logic.js';
4
+ // NotionProvider: the document-source provider for Notion. It authenticates with
5
+ // a single internal-integration token (Bearer), fetches a page for its title and
6
+ // URL, then pages through the page's top-level blocks and converts them to the
7
+ // Markdown the planner consumes. Because the API host is fixed
8
+ // (`api.notion.com`) and there is no per-site base URL, there is no SSRF surface.
9
+ // Notion-specific *pure* logic (ref parsing, block → Markdown) lives in
10
+ // `@cat-factory/integrations`; this class is the thin `fetch` shell.
11
+ const API_BASE = 'https://api.notion.com/v1';
12
+ const NOTION_API_HOST = 'api.notion.com';
13
+ const NOTION_VERSION = '2022-06-28';
14
+ const USER_AGENT = 'cat-factory';
15
+ /** Bound the block backfill so a huge page can't stall an import (100 blocks/page). */
16
+ const MAX_BLOCK_PAGES = 5;
17
+ /** Bound the redirect chain so the fixed API host can't 302 us elsewhere. */
18
+ const MAX_REDIRECTS = 5;
19
+ /** Hard cap on the bytes read off any response body, to protect the isolate. */
20
+ const MAX_RESPONSE_BYTES = 5_000_000;
21
+ /** Carries the HTTP status so callers can surface a meaningful error. */
22
+ export class NotionApiError extends Error {
23
+ status;
24
+ constructor(status, message) {
25
+ super(message);
26
+ this.status = status;
27
+ this.name = 'NotionApiError';
28
+ }
29
+ }
30
+ /**
31
+ * The Notion API host is fixed, so any redirect must stay on `api.notion.com`
32
+ * over https. A redirect off-host (e.g. to an internal address) is treated as an
33
+ * SSRF attempt and rejected. Mirrors the per-hop guard the site-configurable
34
+ * providers run.
35
+ */
36
+ function assertSafeNotionUrl(url) {
37
+ let parsed;
38
+ try {
39
+ parsed = new URL(url);
40
+ }
41
+ catch {
42
+ throw new NotionApiError(502, `Notion request URL is invalid: ${url}`);
43
+ }
44
+ if (parsed.protocol !== 'https:') {
45
+ throw new NotionApiError(502, 'Notion request must use https');
46
+ }
47
+ if (parsed.hostname.toLowerCase() !== NOTION_API_HOST) {
48
+ throw new NotionApiError(502, `Notion redirect to a disallowed host: ${parsed.hostname}`);
49
+ }
50
+ }
51
+ /**
52
+ * `fetch` with redirects followed by hand so the host guard runs against EVERY
53
+ * hop. With the default `redirect: 'follow'` a 302 from the API could be chased
54
+ * to an internal target (or downgraded to http), leaking the Bearer token. We
55
+ * force `redirect: 'manual'`, re-resolve the `Location`, and re-validate.
56
+ */
57
+ async function safeFetch(url, init) {
58
+ let current = url;
59
+ for (let hop = 0;; hop++) {
60
+ assertSafeNotionUrl(current);
61
+ const res = await fetch(current, { ...init, redirect: 'manual' });
62
+ if (res.status >= 300 && res.status < 400) {
63
+ const location = res.headers.get('location');
64
+ if (!location)
65
+ return res;
66
+ if (hop >= MAX_REDIRECTS) {
67
+ throw new NotionApiError(502, 'Notion returned too many redirects');
68
+ }
69
+ current = new URL(location, current).toString();
70
+ continue;
71
+ }
72
+ return res;
73
+ }
74
+ }
75
+ /**
76
+ * Read a response body with a running byte cap so a hostile/huge response can't
77
+ * OOM the isolate. Checks the declared Content-Length first, then enforces the
78
+ * cap while streaming.
79
+ */
80
+ async function readCappedText(res, maxBytes) {
81
+ const declared = res.headers.get('content-length');
82
+ if (declared && Number(declared) > maxBytes) {
83
+ throw new NotionApiError(502, 'Notion response too large');
84
+ }
85
+ const body = res.body;
86
+ if (!body)
87
+ return '';
88
+ const reader = body.getReader();
89
+ const chunks = [];
90
+ let total = 0;
91
+ try {
92
+ for (;;) {
93
+ const { done, value } = await reader.read();
94
+ if (done)
95
+ break;
96
+ if (!value)
97
+ continue;
98
+ total += value.byteLength;
99
+ if (total > maxBytes) {
100
+ await reader.cancel();
101
+ throw new NotionApiError(502, 'Notion response too large');
102
+ }
103
+ chunks.push(value);
104
+ }
105
+ }
106
+ finally {
107
+ reader.releaseLock();
108
+ }
109
+ const merged = new Uint8Array(total);
110
+ let offset = 0;
111
+ for (const c of chunks) {
112
+ merged.set(c, offset);
113
+ offset += c.byteLength;
114
+ }
115
+ return new TextDecoder().decode(merged);
116
+ }
117
+ export class NotionProvider {
118
+ kind = 'notion';
119
+ descriptor = NOTION_DESCRIPTOR;
120
+ normalizeConnection(input) {
121
+ const apiToken = input.apiToken?.trim();
122
+ if (!apiToken) {
123
+ throw new ValidationError('Notion requires an internal integration token');
124
+ }
125
+ return { credentials: { apiToken }, label: 'Notion workspace' };
126
+ }
127
+ parseRef(input) {
128
+ return notionLogic.parseNotionRef(input);
129
+ }
130
+ async fetchDocument(credentials, externalId) {
131
+ const page = await this.get(credentials, `/pages/${encodeURIComponent(externalId)}`);
132
+ if (!page.id) {
133
+ throw new NotionApiError(502, `Notion returned an unexpected body for page ${externalId}`);
134
+ }
135
+ const blocks = await this.fetchBlocks(credentials, page.id);
136
+ return {
137
+ externalId: page.id,
138
+ title: notionLogic.notionPageTitle(page.properties),
139
+ url: page.url ?? `https://www.notion.so/${page.id.replace(/-/g, '')}`,
140
+ body: notionLogic.notionBlocksToMarkdown(blocks),
141
+ };
142
+ }
143
+ async search(credentials, query) {
144
+ const res = await safeFetch(`${API_BASE}/search`, {
145
+ method: 'POST',
146
+ headers: {
147
+ authorization: `Bearer ${credentials.apiToken}`,
148
+ 'notion-version': NOTION_VERSION,
149
+ accept: 'application/json',
150
+ 'content-type': 'application/json',
151
+ 'user-agent': USER_AGENT,
152
+ },
153
+ body: JSON.stringify({
154
+ query,
155
+ filter: { property: 'object', value: 'page' },
156
+ page_size: 20,
157
+ }),
158
+ });
159
+ if (!res.ok) {
160
+ const text = await readCappedText(res, MAX_RESPONSE_BYTES).catch(() => '');
161
+ throw new NotionApiError(res.status, `Notion search → ${res.status}: ${text.slice(0, 300)}`);
162
+ }
163
+ const text = await readCappedText(res, MAX_RESPONSE_BYTES);
164
+ const json = (() => {
165
+ try {
166
+ return JSON.parse(text);
167
+ }
168
+ catch {
169
+ return null;
170
+ }
171
+ })();
172
+ return notionLogic.parseNotionSearchResults(json);
173
+ }
174
+ /** Page through a page's top-level blocks (bounded), returning them in order. */
175
+ async fetchBlocks(credentials, pageId) {
176
+ const blocks = [];
177
+ let cursor;
178
+ for (let i = 0; i < MAX_BLOCK_PAGES; i++) {
179
+ const query = cursor
180
+ ? `?page_size=100&start_cursor=${encodeURIComponent(cursor)}`
181
+ : '?page_size=100';
182
+ const res = await this.get(credentials, `/blocks/${encodeURIComponent(pageId)}/children${query}`);
183
+ if (Array.isArray(res.results))
184
+ blocks.push(...res.results);
185
+ if (!res.has_more || !res.next_cursor)
186
+ break;
187
+ cursor = res.next_cursor;
188
+ }
189
+ return blocks;
190
+ }
191
+ async get(credentials, path) {
192
+ const url = `${API_BASE}${path}`;
193
+ const res = await safeFetch(url, {
194
+ method: 'GET',
195
+ headers: {
196
+ authorization: `Bearer ${credentials.apiToken}`,
197
+ 'notion-version': NOTION_VERSION,
198
+ accept: 'application/json',
199
+ 'user-agent': USER_AGENT,
200
+ },
201
+ });
202
+ if (!res.ok) {
203
+ const text = await readCappedText(res, MAX_RESPONSE_BYTES).catch(() => '');
204
+ throw new NotionApiError(res.status, `Notion GET ${url} → ${res.status}: ${text.slice(0, 300)}`);
205
+ }
206
+ const text = await readCappedText(res, MAX_RESPONSE_BYTES);
207
+ const json = (() => {
208
+ try {
209
+ return JSON.parse(text);
210
+ }
211
+ catch {
212
+ return null;
213
+ }
214
+ })();
215
+ if (json === null) {
216
+ throw new NotionApiError(502, `Notion returned an unparseable body for ${path}`);
217
+ }
218
+ return json;
219
+ }
220
+ }
221
+ //# sourceMappingURL=NotionProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotionProvider.js","sourceRoot":"","sources":["../../../src/modules/documents/NotionProvider.ts"],"names":[],"mappings":"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"}