@cat-factory/worker 0.6.0 → 0.7.2

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 (55) hide show
  1. package/LICENSE +21 -21
  2. package/dist/infrastructure/container.d.ts.map +1 -1
  3. package/dist/infrastructure/container.js +36 -2
  4. package/dist/infrastructure/container.js.map +1 -1
  5. package/dist/infrastructure/repositories/D1BootstrapJobRepository.js +4 -4
  6. package/dist/infrastructure/repositories/D1ModelDefaultsRepository.js +1 -1
  7. package/dist/infrastructure/repositories/D1PipelineScheduleRepository.js +25 -25
  8. package/dist/infrastructure/repositories/D1RepoProjectionRepository.js +6 -6
  9. package/dist/infrastructure/repositories/D1ServiceRepository.js +1 -1
  10. package/dist/infrastructure/repositories/D1TrackerSettingsRepository.d.ts.map +1 -1
  11. package/dist/infrastructure/repositories/D1TrackerSettingsRepository.js +12 -6
  12. package/dist/infrastructure/repositories/D1TrackerSettingsRepository.js.map +1 -1
  13. package/dist/infrastructure/repositories/D1WorkspaceMountRepository.js +8 -8
  14. package/migrations/0005_issue_tracker_writeback.sql +11 -0
  15. package/package.json +18 -13
  16. package/dist/infrastructure/ai/CloudflareModelProvider.d.ts +0 -23
  17. package/dist/infrastructure/ai/CloudflareModelProvider.d.ts.map +0 -1
  18. package/dist/infrastructure/ai/CloudflareModelProvider.js +0 -62
  19. package/dist/infrastructure/ai/CloudflareModelProvider.js.map +0 -1
  20. package/dist/infrastructure/ai/ContainerRepoScanner.d.ts +0 -39
  21. package/dist/infrastructure/ai/ContainerRepoScanner.d.ts.map +0 -1
  22. package/dist/infrastructure/ai/ContainerRepoScanner.js +0 -115
  23. package/dist/infrastructure/ai/ContainerRepoScanner.js.map +0 -1
  24. package/dist/infrastructure/documents/ConfluenceProvider.d.ts +0 -29
  25. package/dist/infrastructure/documents/ConfluenceProvider.d.ts.map +0 -1
  26. package/dist/infrastructure/documents/ConfluenceProvider.js +0 -179
  27. package/dist/infrastructure/documents/ConfluenceProvider.js.map +0 -1
  28. package/dist/infrastructure/documents/GitHubDocsProvider.d.ts +0 -42
  29. package/dist/infrastructure/documents/GitHubDocsProvider.d.ts.map +0 -1
  30. package/dist/infrastructure/documents/GitHubDocsProvider.js +0 -85
  31. package/dist/infrastructure/documents/GitHubDocsProvider.js.map +0 -1
  32. package/dist/infrastructure/documents/NotionProvider.d.ts +0 -32
  33. package/dist/infrastructure/documents/NotionProvider.d.ts.map +0 -1
  34. package/dist/infrastructure/documents/NotionProvider.js +0 -220
  35. package/dist/infrastructure/documents/NotionProvider.js.map +0 -1
  36. package/dist/infrastructure/environments/HttpEnvironmentProvider.d.ts +0 -27
  37. package/dist/infrastructure/environments/HttpEnvironmentProvider.d.ts.map +0 -1
  38. package/dist/infrastructure/environments/HttpEnvironmentProvider.js +0 -314
  39. package/dist/infrastructure/environments/HttpEnvironmentProvider.js.map +0 -1
  40. package/dist/infrastructure/events/InAppNotificationChannel.d.ts +0 -19
  41. package/dist/infrastructure/events/InAppNotificationChannel.d.ts.map +0 -1
  42. package/dist/infrastructure/events/InAppNotificationChannel.js +0 -22
  43. package/dist/infrastructure/events/InAppNotificationChannel.js.map +0 -1
  44. package/dist/infrastructure/repositories/D1RepoBlueprintRepository.d.ts +0 -20
  45. package/dist/infrastructure/repositories/D1RepoBlueprintRepository.d.ts.map +0 -1
  46. package/dist/infrastructure/repositories/D1RepoBlueprintRepository.js +0 -64
  47. package/dist/infrastructure/repositories/D1RepoBlueprintRepository.js.map +0 -1
  48. package/dist/infrastructure/tasks/GitHubIssuesProvider.d.ts +0 -50
  49. package/dist/infrastructure/tasks/GitHubIssuesProvider.d.ts.map +0 -1
  50. package/dist/infrastructure/tasks/GitHubIssuesProvider.js +0 -91
  51. package/dist/infrastructure/tasks/GitHubIssuesProvider.js.map +0 -1
  52. package/dist/infrastructure/tasks/JiraProvider.d.ts +0 -29
  53. package/dist/infrastructure/tasks/JiraProvider.d.ts.map +0 -1
  54. package/dist/infrastructure/tasks/JiraProvider.js +0 -109
  55. package/dist/infrastructure/tasks/JiraProvider.js.map +0 -1
@@ -1,220 +0,0 @@
1
- import { ValidationError, } from '@cat-factory/kernel';
2
- import { NOTION_DESCRIPTOR, notionLogic } from '@cat-factory/integrations';
3
- // NotionProvider: the document-source provider for Notion. It authenticates with
4
- // a single internal-integration token (Bearer), fetches a page for its title and
5
- // URL, then pages through the page's top-level blocks and converts them to the
6
- // Markdown the planner consumes. Because the API host is fixed
7
- // (`api.notion.com`) and there is no per-site base URL, there is no SSRF surface.
8
- // Notion-specific *pure* logic (ref parsing, block → Markdown) lives in
9
- // `@cat-factory/integrations`; this class is the thin `fetch` shell.
10
- const API_BASE = 'https://api.notion.com/v1';
11
- const NOTION_API_HOST = 'api.notion.com';
12
- const NOTION_VERSION = '2022-06-28';
13
- const USER_AGENT = 'cat-factory';
14
- /** Bound the block backfill so a huge page can't stall an import (100 blocks/page). */
15
- const MAX_BLOCK_PAGES = 5;
16
- /** Bound the redirect chain so the fixed API host can't 302 us elsewhere. */
17
- const MAX_REDIRECTS = 5;
18
- /** Hard cap on the bytes read off any response body, to protect the isolate. */
19
- const MAX_RESPONSE_BYTES = 5_000_000;
20
- /** Carries the HTTP status so callers can surface a meaningful error. */
21
- export class NotionApiError extends Error {
22
- status;
23
- constructor(status, message) {
24
- super(message);
25
- this.status = status;
26
- this.name = 'NotionApiError';
27
- }
28
- }
29
- /**
30
- * The Notion API host is fixed, so any redirect must stay on `api.notion.com`
31
- * over https. A redirect off-host (e.g. to an internal address) is treated as an
32
- * SSRF attempt and rejected. Mirrors the per-hop guard the site-configurable
33
- * providers run.
34
- */
35
- function assertSafeNotionUrl(url) {
36
- let parsed;
37
- try {
38
- parsed = new URL(url);
39
- }
40
- catch {
41
- throw new NotionApiError(502, `Notion request URL is invalid: ${url}`);
42
- }
43
- if (parsed.protocol !== 'https:') {
44
- throw new NotionApiError(502, 'Notion request must use https');
45
- }
46
- if (parsed.hostname.toLowerCase() !== NOTION_API_HOST) {
47
- throw new NotionApiError(502, `Notion redirect to a disallowed host: ${parsed.hostname}`);
48
- }
49
- }
50
- /**
51
- * `fetch` with redirects followed by hand so the host guard runs against EVERY
52
- * hop. With the default `redirect: 'follow'` a 302 from the API could be chased
53
- * to an internal target (or downgraded to http), leaking the Bearer token. We
54
- * force `redirect: 'manual'`, re-resolve the `Location`, and re-validate.
55
- */
56
- async function safeFetch(url, init) {
57
- let current = url;
58
- for (let hop = 0;; hop++) {
59
- assertSafeNotionUrl(current);
60
- const res = await fetch(current, { ...init, redirect: 'manual' });
61
- if (res.status >= 300 && res.status < 400) {
62
- const location = res.headers.get('location');
63
- if (!location)
64
- return res;
65
- if (hop >= MAX_REDIRECTS) {
66
- throw new NotionApiError(502, 'Notion returned too many redirects');
67
- }
68
- current = new URL(location, current).toString();
69
- continue;
70
- }
71
- return res;
72
- }
73
- }
74
- /**
75
- * Read a response body with a running byte cap so a hostile/huge response can't
76
- * OOM the isolate. Checks the declared Content-Length first, then enforces the
77
- * cap while streaming.
78
- */
79
- async function readCappedText(res, maxBytes) {
80
- const declared = res.headers.get('content-length');
81
- if (declared && Number(declared) > maxBytes) {
82
- throw new NotionApiError(502, 'Notion response too large');
83
- }
84
- const body = res.body;
85
- if (!body)
86
- return '';
87
- const reader = body.getReader();
88
- const chunks = [];
89
- let total = 0;
90
- try {
91
- for (;;) {
92
- const { done, value } = await reader.read();
93
- if (done)
94
- break;
95
- if (!value)
96
- continue;
97
- total += value.byteLength;
98
- if (total > maxBytes) {
99
- await reader.cancel();
100
- throw new NotionApiError(502, 'Notion response too large');
101
- }
102
- chunks.push(value);
103
- }
104
- }
105
- finally {
106
- reader.releaseLock();
107
- }
108
- const merged = new Uint8Array(total);
109
- let offset = 0;
110
- for (const c of chunks) {
111
- merged.set(c, offset);
112
- offset += c.byteLength;
113
- }
114
- return new TextDecoder().decode(merged);
115
- }
116
- export class NotionProvider {
117
- kind = 'notion';
118
- descriptor = NOTION_DESCRIPTOR;
119
- normalizeConnection(input) {
120
- const apiToken = input.apiToken?.trim();
121
- if (!apiToken) {
122
- throw new ValidationError('Notion requires an internal integration token');
123
- }
124
- return { credentials: { apiToken }, label: 'Notion workspace' };
125
- }
126
- parseRef(input) {
127
- return notionLogic.parseNotionRef(input);
128
- }
129
- async fetchDocument(credentials, externalId) {
130
- const page = await this.get(credentials, `/pages/${encodeURIComponent(externalId)}`);
131
- if (!page.id) {
132
- throw new NotionApiError(502, `Notion returned an unexpected body for page ${externalId}`);
133
- }
134
- const blocks = await this.fetchBlocks(credentials, page.id);
135
- return {
136
- externalId: page.id,
137
- title: notionLogic.notionPageTitle(page.properties),
138
- url: page.url ?? `https://www.notion.so/${page.id.replace(/-/g, '')}`,
139
- body: notionLogic.notionBlocksToMarkdown(blocks),
140
- };
141
- }
142
- async search(credentials, query) {
143
- const res = await safeFetch(`${API_BASE}/search`, {
144
- method: 'POST',
145
- headers: {
146
- authorization: `Bearer ${credentials.apiToken}`,
147
- 'notion-version': NOTION_VERSION,
148
- accept: 'application/json',
149
- 'content-type': 'application/json',
150
- 'user-agent': USER_AGENT,
151
- },
152
- body: JSON.stringify({
153
- query,
154
- filter: { property: 'object', value: 'page' },
155
- page_size: 20,
156
- }),
157
- });
158
- if (!res.ok) {
159
- const text = await readCappedText(res, MAX_RESPONSE_BYTES).catch(() => '');
160
- throw new NotionApiError(res.status, `Notion search → ${res.status}: ${text.slice(0, 300)}`);
161
- }
162
- const text = await readCappedText(res, MAX_RESPONSE_BYTES);
163
- const json = (() => {
164
- try {
165
- return JSON.parse(text);
166
- }
167
- catch {
168
- return null;
169
- }
170
- })();
171
- return notionLogic.parseNotionSearchResults(json);
172
- }
173
- /** Page through a page's top-level blocks (bounded), returning them in order. */
174
- async fetchBlocks(credentials, pageId) {
175
- const blocks = [];
176
- let cursor;
177
- for (let i = 0; i < MAX_BLOCK_PAGES; i++) {
178
- const query = cursor
179
- ? `?page_size=100&start_cursor=${encodeURIComponent(cursor)}`
180
- : '?page_size=100';
181
- const res = await this.get(credentials, `/blocks/${encodeURIComponent(pageId)}/children${query}`);
182
- if (Array.isArray(res.results))
183
- blocks.push(...res.results);
184
- if (!res.has_more || !res.next_cursor)
185
- break;
186
- cursor = res.next_cursor;
187
- }
188
- return blocks;
189
- }
190
- async get(credentials, path) {
191
- const url = `${API_BASE}${path}`;
192
- const res = await safeFetch(url, {
193
- method: 'GET',
194
- headers: {
195
- authorization: `Bearer ${credentials.apiToken}`,
196
- 'notion-version': NOTION_VERSION,
197
- accept: 'application/json',
198
- 'user-agent': USER_AGENT,
199
- },
200
- });
201
- if (!res.ok) {
202
- const text = await readCappedText(res, MAX_RESPONSE_BYTES).catch(() => '');
203
- throw new NotionApiError(res.status, `Notion GET ${url} → ${res.status}: ${text.slice(0, 300)}`);
204
- }
205
- const text = await readCappedText(res, MAX_RESPONSE_BYTES);
206
- const json = (() => {
207
- try {
208
- return JSON.parse(text);
209
- }
210
- catch {
211
- return null;
212
- }
213
- })();
214
- if (json === null) {
215
- throw new NotionApiError(502, `Notion returned an unparseable body for ${path}`);
216
- }
217
- return json;
218
- }
219
- }
220
- //# sourceMappingURL=NotionProvider.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"NotionProvider.js","sourceRoot":"","sources":["../../../src/infrastructure/documents/NotionProvider.ts"],"names":[],"mappings":"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"}
@@ -1,27 +0,0 @@
1
- import { type EnvironmentProvider, type EnvironmentStatusRequest, type EnvironmentTeardownRequest, type EnvironmentStatus, type ProvisionEnvironmentRequest, type ProvisionedEnvironment } from '@cat-factory/kernel';
2
- /** Carries the HTTP status so the API can surface a meaningful (redacted) error. */
3
- export declare class EnvironmentApiError extends Error {
4
- readonly status: number;
5
- constructor(status: number, message: string);
6
- }
7
- export interface HttpEnvironmentProviderOptions {
8
- defaultTimeoutMs?: number;
9
- }
10
- export declare class HttpEnvironmentProvider implements EnvironmentProvider {
11
- private readonly defaultTimeoutMs;
12
- /** Per-isolate OAuth token cache, keyed by token URL + client id. */
13
- private readonly oauthCache;
14
- constructor(options?: HttpEnvironmentProviderOptions);
15
- provision(req: ProvisionEnvironmentRequest): Promise<ProvisionedEnvironment>;
16
- status(req: EnvironmentStatusRequest): Promise<ProvisionedEnvironment>;
17
- teardown(req: EnvironmentTeardownRequest): Promise<{
18
- status: EnvironmentStatus;
19
- }>;
20
- private execute;
21
- private buildUrl;
22
- private authHeaders;
23
- private oauthToken;
24
- private mapResponse;
25
- private mapAccess;
26
- }
27
- //# sourceMappingURL=HttpEnvironmentProvider.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"HttpEnvironmentProvider.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/environments/HttpEnvironmentProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,mBAAmB,EAExB,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EAEhC,KAAK,sBAAsB,EAE5B,MAAM,qBAAqB,CAAA;AAqB5B,oFAAoF;AACpF,qBAAa,mBAAoB,SAAQ,KAAK;IAE1C,QAAQ,CAAC,MAAM,EAAE,MAAM;IADzB,YACW,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EAIhB;CACF;AAqFD,MAAM,WAAW,8BAA8B;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,qBAAa,uBAAwB,YAAW,mBAAmB;IACjE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;IACzC,qEAAqE;IACrE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0D;IAErF,YAAY,OAAO,GAAE,8BAAmC,EAEvD;IAEK,SAAS,CAAC,GAAG,EAAE,2BAA2B,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAajF;IAEK,MAAM,CAAC,GAAG,EAAE,wBAAwB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAwB3E;IAEK,QAAQ,CAAC,GAAG,EAAE,0BAA0B,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,iBAAiB,CAAA;KAAE,CAAC,CAatF;YAIa,OAAO;IAmDrB,OAAO,CAAC,QAAQ;YAoBF,WAAW;YAgCX,UAAU;IAsDxB,OAAO,CAAC,WAAW;IA4BnB,OAAO,CAAC,SAAS;CAiBlB"}
@@ -1,314 +0,0 @@
1
- import {} from '@cat-factory/kernel';
2
- import { environmentsLogic } from '@cat-factory/integrations';
3
- // The single generic adapter that interprets ANY environment manifest. There are
4
- // no per-provider presets: an org's self-rolled management API is described as
5
- // HTTP request templates with `{{var}}` interpolation, an auth scheme, and a
6
- // dot-path mapping from its (arbitrary) response onto the canonical handle.
7
- //
8
- // Security: every URL is SSRF-guarded before it is fetched; the per-tenant
9
- // secrets are resolved in-memory via the injected resolver and only ever placed
10
- // in request headers — never logged or echoed in errors (error bodies are
11
- // length-capped and carry no request headers).
12
- const DEFAULT_TIMEOUT_MS = 15_000;
13
- const MAX_RESPONSE_CHARS = 200_000;
14
- /** Hard cap on the bytes read off any response body (mirrors MAX_RESPONSE_CHARS). */
15
- const MAX_RESPONSE_BYTES = MAX_RESPONSE_CHARS;
16
- /** Bound the redirect chain so a permitted first hop can't walk us anywhere. */
17
- const MAX_REDIRECTS = 5;
18
- const USER_AGENT = 'cat-factory';
19
- /** Carries the HTTP status so the API can surface a meaningful (redacted) error. */
20
- export class EnvironmentApiError extends Error {
21
- status;
22
- constructor(status, message) {
23
- super(message);
24
- this.status = status;
25
- this.name = 'EnvironmentApiError';
26
- }
27
- }
28
- /**
29
- * `fetch` with redirects followed by hand so the SSRF guard runs against EVERY
30
- * hop, not just the first URL. With the default `redirect: 'follow'` a permitted
31
- * host can 302 to an internal target (e.g. 169.254.169.254) — or downgrade
32
- * https→http — and the runtime would follow it unchecked. We force
33
- * `redirect: 'manual'`, re-resolve the `Location` against the current URL, and
34
- * re-run the same `assertSafe` guard (which also enforces https-only) before
35
- * following. A redirect target that fails the guard throws exactly as an invalid
36
- * initial URL would.
37
- */
38
- async function safeFetch(url, init, assertSafe) {
39
- let current = url;
40
- for (let hop = 0;; hop++) {
41
- assertSafe(current);
42
- const res = await fetch(current, { ...init, redirect: 'manual' });
43
- if (res.status >= 300 && res.status < 400) {
44
- const location = res.headers.get('location');
45
- if (!location)
46
- return res;
47
- if (hop >= MAX_REDIRECTS) {
48
- throw new EnvironmentApiError(502, 'Environment provider returned too many redirects');
49
- }
50
- // Resolve relative redirects against the current URL, then re-validate.
51
- current = new URL(location, current).toString();
52
- continue;
53
- }
54
- return res;
55
- }
56
- }
57
- /**
58
- * Read a response body with a running byte cap so a hostile/huge response can't
59
- * OOM the isolate. Checks the declared Content-Length first, then enforces the
60
- * cap while streaming. When `throwOnOverflow` is false (error snippets) the body
61
- * is truncated instead of throwing.
62
- */
63
- async function readCappedText(res, maxBytes, throwOnOverflow = true) {
64
- const declared = res.headers.get('content-length');
65
- if (declared && Number(declared) > maxBytes) {
66
- if (throwOnOverflow) {
67
- throw new EnvironmentApiError(502, 'Environment provider response too large');
68
- }
69
- }
70
- const body = res.body;
71
- if (!body)
72
- return '';
73
- const reader = body.getReader();
74
- const chunks = [];
75
- let total = 0;
76
- try {
77
- for (;;) {
78
- const { done, value } = await reader.read();
79
- if (done)
80
- break;
81
- if (!value)
82
- continue;
83
- total += value.byteLength;
84
- if (total > maxBytes) {
85
- await reader.cancel();
86
- if (throwOnOverflow) {
87
- throw new EnvironmentApiError(502, 'Environment provider response too large');
88
- }
89
- chunks.push(value);
90
- break;
91
- }
92
- chunks.push(value);
93
- }
94
- }
95
- finally {
96
- reader.releaseLock();
97
- }
98
- const merged = new Uint8Array(chunks.reduce((n, c) => n + c.byteLength, 0));
99
- let offset = 0;
100
- for (const c of chunks) {
101
- merged.set(c, offset);
102
- offset += c.byteLength;
103
- }
104
- return new TextDecoder().decode(merged).slice(0, maxBytes);
105
- }
106
- export class HttpEnvironmentProvider {
107
- defaultTimeoutMs;
108
- /** Per-isolate OAuth token cache, keyed by token URL + client id. */
109
- oauthCache = new Map();
110
- constructor(options = {}) {
111
- this.defaultTimeoutMs = options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS;
112
- }
113
- async provision(req) {
114
- const json = await this.execute(req.manifest, req.manifest.provision, {
115
- input: req.inputs,
116
- provision: {},
117
- }, req.resolveSecret);
118
- // A successful provision call defaults to 'ready' unless the manifest maps a
119
- // status string (e.g. an async provisioner returning 'pending').
120
- return this.mapResponse(req.manifest, json, 'ready');
121
- }
122
- async status(req) {
123
- if (!req.manifest.status) {
124
- // No status endpoint declared: treat the environment as ready and echo what
125
- // we captured at provision time.
126
- return {
127
- externalId: req.externalId,
128
- url: req.provisionFields.url ?? null,
129
- status: 'ready',
130
- expiresAt: null,
131
- access: null,
132
- fields: req.provisionFields,
133
- };
134
- }
135
- const json = await this.execute(req.manifest, req.manifest.status, {
136
- input: {},
137
- provision: req.provisionFields,
138
- }, req.resolveSecret);
139
- const mapped = this.mapResponse(req.manifest, json, 'ready');
140
- return { ...mapped, externalId: mapped.externalId ?? req.externalId };
141
- }
142
- async teardown(req) {
143
- if (req.manifest.teardown) {
144
- await this.execute(req.manifest, req.manifest.teardown, {
145
- input: {},
146
- provision: req.provisionFields,
147
- }, req.resolveSecret);
148
- }
149
- return { status: 'torn_down' };
150
- }
151
- // --- internals ----------------------------------------------------------
152
- async execute(manifest, template, scope, resolveSecret) {
153
- const url = this.buildUrl(manifest.baseUrl, template, scope);
154
- const headers = {
155
- accept: 'application/json',
156
- 'user-agent': USER_AGENT,
157
- ...(await this.authHeaders(manifest.auth, resolveSecret)),
158
- };
159
- for (const h of template.headers ?? []) {
160
- headers[h.name] = environmentsLogic.interpolateTemplate(h.value, scope);
161
- }
162
- let body;
163
- if (template.bodyTemplate !== undefined && template.method !== 'GET') {
164
- body = environmentsLogic.interpolateTemplate(template.bodyTemplate, scope);
165
- if (!headers['content-type'])
166
- headers['content-type'] = 'application/json';
167
- }
168
- const res = await safeFetch(url, {
169
- method: template.method,
170
- headers,
171
- body,
172
- signal: AbortSignal.timeout(template.timeoutMs ?? this.defaultTimeoutMs),
173
- }, (u) => environmentsLogic.assertSafeEnvironmentUrl(u, 'request URL'));
174
- if (!res.ok) {
175
- const errText = await readCappedText(res, MAX_RESPONSE_BYTES, false).catch(() => '');
176
- throw new EnvironmentApiError(res.status, `Environment provider ${template.method} → ${res.status}: ${errText.slice(0, 300)}`);
177
- }
178
- const text = await readCappedText(res, MAX_RESPONSE_BYTES);
179
- if (!text)
180
- return {};
181
- try {
182
- return JSON.parse(text);
183
- }
184
- catch {
185
- // Non-JSON responses leave the mapping to resolve to nulls.
186
- return {};
187
- }
188
- }
189
- buildUrl(baseUrl, template, scope) {
190
- const base = baseUrl.replace(/\/+$/, '');
191
- const path = environmentsLogic.interpolateTemplate(template.pathTemplate, scope);
192
- let url = path ? `${base}${path.startsWith('/') ? '' : '/'}${path}` : base;
193
- const query = (template.query ?? [])
194
- .map((q) => `${encodeURIComponent(q.key)}=${encodeURIComponent(environmentsLogic.interpolateTemplate(q.value, scope))}`)
195
- .join('&');
196
- if (query)
197
- url += `${url.includes('?') ? '&' : '?'}${query}`;
198
- return url;
199
- }
200
- async authHeaders(auth, resolveSecret) {
201
- const secret = (key) => {
202
- const value = resolveSecret(key);
203
- if (value === undefined)
204
- throw new EnvironmentApiError(500, `Missing secret '${key}'`);
205
- return value;
206
- };
207
- switch (auth.type) {
208
- case 'none':
209
- return {};
210
- case 'api_key':
211
- return { [auth.headerName]: `${auth.valuePrefix ?? ''}${secret(auth.secretRef.key)}` };
212
- case 'bearer':
213
- return { authorization: `Bearer ${secret(auth.secretRef.key)}` };
214
- case 'basic':
215
- return {
216
- authorization: `Basic ${btoa(`${secret(auth.usernameSecretRef.key)}:${secret(auth.passwordSecretRef.key)}`)}`,
217
- };
218
- case 'oauth2_client_credentials':
219
- return { authorization: `Bearer ${await this.oauthToken(auth, secret)}` };
220
- case 'custom_headers': {
221
- const headers = {};
222
- for (const h of auth.headers)
223
- headers[h.name] = secret(h.secretRef.key);
224
- return headers;
225
- }
226
- }
227
- }
228
- async oauthToken(auth, secret) {
229
- const clientId = secret(auth.clientIdSecretRef.key);
230
- const cacheKey = `${auth.tokenUrl}::${clientId}`;
231
- const cached = this.oauthCache.get(cacheKey);
232
- if (cached && cached.expiresAt > Date.now() + 5_000)
233
- return cached.token;
234
- const form = new URLSearchParams({
235
- grant_type: 'client_credentials',
236
- client_id: clientId,
237
- client_secret: secret(auth.clientSecretSecretRef.key),
238
- });
239
- if (auth.scope)
240
- form.set('scope', auth.scope);
241
- if (auth.audience)
242
- form.set('audience', auth.audience);
243
- const res = await safeFetch(auth.tokenUrl, {
244
- method: 'POST',
245
- headers: {
246
- 'content-type': 'application/x-www-form-urlencoded',
247
- accept: 'application/json',
248
- 'user-agent': USER_AGENT,
249
- },
250
- body: form.toString(),
251
- signal: AbortSignal.timeout(this.defaultTimeoutMs),
252
- }, (u) => environmentsLogic.assertSafeEnvironmentUrl(u, 'OAuth token URL'));
253
- if (!res.ok) {
254
- const text = await readCappedText(res, MAX_RESPONSE_BYTES, false).catch(() => '');
255
- throw new EnvironmentApiError(res.status, `OAuth token request → ${res.status}: ${text.slice(0, 200)}`);
256
- }
257
- const tokenText = await readCappedText(res, MAX_RESPONSE_BYTES);
258
- const json = (() => {
259
- try {
260
- return JSON.parse(tokenText);
261
- }
262
- catch {
263
- return null;
264
- }
265
- })();
266
- if (!json?.access_token) {
267
- throw new EnvironmentApiError(502, 'OAuth token response missing access_token');
268
- }
269
- const ttlMs = (typeof json.expires_in === 'number' ? json.expires_in : 300) * 1000;
270
- this.oauthCache.set(cacheKey, { token: json.access_token, expiresAt: Date.now() + ttlMs });
271
- return json.access_token;
272
- }
273
- mapResponse(manifest, json, fallbackStatus) {
274
- const r = manifest.response;
275
- const externalId = environmentsLogic.extractString(json, r.externalIdPath) ?? null;
276
- const url = environmentsLogic.extractString(json, r.urlPath) ?? null;
277
- const rawStatus = environmentsLogic.extractString(json, r.statusPath);
278
- const status = environmentsLogic.mapStatus(rawStatus, r.statusMap, fallbackStatus);
279
- const expiresAt = r.expiresAtPath
280
- ? environmentsLogic.coerceExpiresAt(environmentsLogic.extractByPath(json, r.expiresAtPath))
281
- : null;
282
- const fields = {};
283
- if (externalId)
284
- fields.externalId = externalId;
285
- if (url)
286
- fields.url = url;
287
- return {
288
- externalId,
289
- url,
290
- status,
291
- expiresAt,
292
- access: this.mapAccess(r.access, json),
293
- fields,
294
- };
295
- }
296
- mapAccess(mapping, json) {
297
- if (!mapping)
298
- return null;
299
- const access = { scheme: mapping.scheme };
300
- if (mapping.scheme === 'bearer') {
301
- access.token = environmentsLogic.extractString(json, mapping.tokenPath);
302
- }
303
- else if (mapping.scheme === 'basic') {
304
- access.username = environmentsLogic.extractString(json, mapping.usernamePath);
305
- access.password = environmentsLogic.extractString(json, mapping.passwordPath);
306
- }
307
- else if (mapping.scheme === 'custom_header') {
308
- access.headerName = mapping.headerName;
309
- access.headerValue = environmentsLogic.extractString(json, mapping.headerValuePath);
310
- }
311
- return access;
312
- }
313
- }
314
- //# sourceMappingURL=HttpEnvironmentProvider.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"HttpEnvironmentProvider.js","sourceRoot":"","sources":["../../../src/infrastructure/environments/HttpEnvironmentProvider.ts"],"names":[],"mappings":"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"}
@@ -1,19 +0,0 @@
1
- import type { ExecutionEventPublisher, Notification, NotificationChannel } from '@cat-factory/kernel';
2
- /**
3
- * The in-app notification channel: pushes the `notification` WorkspaceEvent to the
4
- * board (via the same event publisher that carries execution/board events) so the
5
- * inbox + per-block badge update live. The canonical row is already persisted by
6
- * the NotificationService, so this is purely the live push — best-effort, errors
7
- * swallowed by the publisher.
8
- *
9
- * This is the only channel today; future EmailNotificationChannel /
10
- * SlackNotificationChannel implement the same {@link NotificationChannel} port and
11
- * are composed alongside it via CompositeNotificationChannel, with no change to the
12
- * code that raises notifications.
13
- */
14
- export declare class InAppNotificationChannel implements NotificationChannel {
15
- private readonly publisher;
16
- constructor(publisher: ExecutionEventPublisher);
17
- deliver(workspaceId: string, notification: Notification): Promise<void>;
18
- }
19
- //# sourceMappingURL=InAppNotificationChannel.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"InAppNotificationChannel.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/events/InAppNotificationChannel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,YAAY,EACZ,mBAAmB,EACpB,MAAM,qBAAqB,CAAA;AAE5B;;;;;;;;;;;GAWG;AACH,qBAAa,wBAAyB,YAAW,mBAAmB;IACtD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAAtC,YAA6B,SAAS,EAAE,uBAAuB,EAAI;IAE7D,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5E;CACF"}
@@ -1,22 +0,0 @@
1
- /**
2
- * The in-app notification channel: pushes the `notification` WorkspaceEvent to the
3
- * board (via the same event publisher that carries execution/board events) so the
4
- * inbox + per-block badge update live. The canonical row is already persisted by
5
- * the NotificationService, so this is purely the live push — best-effort, errors
6
- * swallowed by the publisher.
7
- *
8
- * This is the only channel today; future EmailNotificationChannel /
9
- * SlackNotificationChannel implement the same {@link NotificationChannel} port and
10
- * are composed alongside it via CompositeNotificationChannel, with no change to the
11
- * code that raises notifications.
12
- */
13
- export class InAppNotificationChannel {
14
- publisher;
15
- constructor(publisher) {
16
- this.publisher = publisher;
17
- }
18
- async deliver(workspaceId, notification) {
19
- await this.publisher.notificationChanged?.(workspaceId, notification);
20
- }
21
- }
22
- //# sourceMappingURL=InAppNotificationChannel.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"InAppNotificationChannel.js","sourceRoot":"","sources":["../../../src/infrastructure/events/InAppNotificationChannel.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,wBAAwB;IACN,SAAS;IAAtC,YAA6B,SAAkC;yBAAlC,SAAS;IAA4B,CAAC;IAEnE,KAAK,CAAC,OAAO,CAAC,WAAmB,EAAE,YAA0B;QAC3D,MAAM,IAAI,CAAC,SAAS,CAAC,mBAAmB,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC,CAAA;IACvE,CAAC;CACF"}