@cat-factory/worker 0.6.0 → 0.7.3
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.
- package/LICENSE +21 -21
- package/dist/infrastructure/config/agents.d.ts.map +1 -1
- package/dist/infrastructure/config/agents.js +10 -0
- package/dist/infrastructure/config/agents.js.map +1 -1
- package/dist/infrastructure/container.d.ts.map +1 -1
- package/dist/infrastructure/container.js +36 -2
- package/dist/infrastructure/container.js.map +1 -1
- package/dist/infrastructure/repositories/D1BootstrapJobRepository.js +4 -4
- package/dist/infrastructure/repositories/D1ModelDefaultsRepository.js +1 -1
- package/dist/infrastructure/repositories/D1PipelineScheduleRepository.js +25 -25
- package/dist/infrastructure/repositories/D1RepoProjectionRepository.js +6 -6
- package/dist/infrastructure/repositories/D1ServiceRepository.js +1 -1
- package/dist/infrastructure/repositories/D1TrackerSettingsRepository.d.ts.map +1 -1
- package/dist/infrastructure/repositories/D1TrackerSettingsRepository.js +12 -6
- package/dist/infrastructure/repositories/D1TrackerSettingsRepository.js.map +1 -1
- package/dist/infrastructure/repositories/D1WorkspaceMountRepository.js +8 -8
- package/migrations/0005_issue_tracker_writeback.sql +11 -0
- package/package.json +18 -13
- package/dist/infrastructure/ai/CloudflareModelProvider.d.ts +0 -23
- package/dist/infrastructure/ai/CloudflareModelProvider.d.ts.map +0 -1
- package/dist/infrastructure/ai/CloudflareModelProvider.js +0 -62
- package/dist/infrastructure/ai/CloudflareModelProvider.js.map +0 -1
- package/dist/infrastructure/ai/ContainerRepoScanner.d.ts +0 -39
- package/dist/infrastructure/ai/ContainerRepoScanner.d.ts.map +0 -1
- package/dist/infrastructure/ai/ContainerRepoScanner.js +0 -115
- package/dist/infrastructure/ai/ContainerRepoScanner.js.map +0 -1
- package/dist/infrastructure/documents/ConfluenceProvider.d.ts +0 -29
- package/dist/infrastructure/documents/ConfluenceProvider.d.ts.map +0 -1
- package/dist/infrastructure/documents/ConfluenceProvider.js +0 -179
- package/dist/infrastructure/documents/ConfluenceProvider.js.map +0 -1
- package/dist/infrastructure/documents/GitHubDocsProvider.d.ts +0 -42
- package/dist/infrastructure/documents/GitHubDocsProvider.d.ts.map +0 -1
- package/dist/infrastructure/documents/GitHubDocsProvider.js +0 -85
- package/dist/infrastructure/documents/GitHubDocsProvider.js.map +0 -1
- package/dist/infrastructure/documents/NotionProvider.d.ts +0 -32
- package/dist/infrastructure/documents/NotionProvider.d.ts.map +0 -1
- package/dist/infrastructure/documents/NotionProvider.js +0 -220
- package/dist/infrastructure/documents/NotionProvider.js.map +0 -1
- package/dist/infrastructure/environments/HttpEnvironmentProvider.d.ts +0 -27
- package/dist/infrastructure/environments/HttpEnvironmentProvider.d.ts.map +0 -1
- package/dist/infrastructure/environments/HttpEnvironmentProvider.js +0 -314
- package/dist/infrastructure/environments/HttpEnvironmentProvider.js.map +0 -1
- package/dist/infrastructure/events/InAppNotificationChannel.d.ts +0 -19
- package/dist/infrastructure/events/InAppNotificationChannel.d.ts.map +0 -1
- package/dist/infrastructure/events/InAppNotificationChannel.js +0 -22
- package/dist/infrastructure/events/InAppNotificationChannel.js.map +0 -1
- package/dist/infrastructure/repositories/D1RepoBlueprintRepository.d.ts +0 -20
- package/dist/infrastructure/repositories/D1RepoBlueprintRepository.d.ts.map +0 -1
- package/dist/infrastructure/repositories/D1RepoBlueprintRepository.js +0 -64
- package/dist/infrastructure/repositories/D1RepoBlueprintRepository.js.map +0 -1
- package/dist/infrastructure/tasks/GitHubIssuesProvider.d.ts +0 -50
- package/dist/infrastructure/tasks/GitHubIssuesProvider.d.ts.map +0 -1
- package/dist/infrastructure/tasks/GitHubIssuesProvider.js +0 -91
- package/dist/infrastructure/tasks/GitHubIssuesProvider.js.map +0 -1
- package/dist/infrastructure/tasks/JiraProvider.d.ts +0 -29
- package/dist/infrastructure/tasks/JiraProvider.d.ts.map +0 -1
- package/dist/infrastructure/tasks/JiraProvider.js +0 -109
- package/dist/infrastructure/tasks/JiraProvider.js.map +0 -1
|
@@ -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"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { RepoBlueprintRecord, RepoBlueprintRepository } from '@cat-factory/kernel';
|
|
2
|
-
import type { D1Database } from '@cloudflare/workers-types';
|
|
3
|
-
/**
|
|
4
|
-
* D1-backed store of repository blueprints (migration 0011). One row per
|
|
5
|
-
* (workspace, repo): `upsert` replaces the existing blueprint in place, keyed by
|
|
6
|
-
* the unique `(workspace_id, repo_owner, repo_name)` index, so the row is always
|
|
7
|
-
* the single current decomposition. The tree is persisted whole as JSON.
|
|
8
|
-
*/
|
|
9
|
-
export declare class D1RepoBlueprintRepository implements RepoBlueprintRepository {
|
|
10
|
-
private readonly db;
|
|
11
|
-
constructor({ db }: {
|
|
12
|
-
db: D1Database;
|
|
13
|
-
});
|
|
14
|
-
upsert(record: RepoBlueprintRecord): Promise<void>;
|
|
15
|
-
get(workspaceId: string, id: string): Promise<RepoBlueprintRecord | null>;
|
|
16
|
-
getByRepo(workspaceId: string, repoOwner: string, repoName: string): Promise<RepoBlueprintRecord | null>;
|
|
17
|
-
listByWorkspace(workspaceId: string): Promise<RepoBlueprintRecord[]>;
|
|
18
|
-
delete(workspaceId: string, id: string): Promise<void>;
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=D1RepoBlueprintRepository.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"D1RepoBlueprintRepository.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/repositories/D1RepoBlueprintRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AA0B3D;;;;;GAKG;AACH,qBAAa,yBAA0B,YAAW,uBAAuB;IACvE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAY;IAE/B,YAAY,EAAE,EAAE,EAAE,EAAE;QAAE,EAAE,EAAE,UAAU,CAAA;KAAE,EAErC;IAEK,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBvD;IAEK,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAM9E;IAEK,SAAS,CACb,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAQrC;IAEK,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAMzE;IAEK,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK3D;CACF"}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
function rowToRecord(row) {
|
|
2
|
-
return {
|
|
3
|
-
id: row.id,
|
|
4
|
-
workspaceId: row.workspace_id,
|
|
5
|
-
repoOwner: row.repo_owner,
|
|
6
|
-
repoName: row.repo_name,
|
|
7
|
-
source: row.source,
|
|
8
|
-
service: JSON.parse(row.service_json),
|
|
9
|
-
createdAt: row.created_at,
|
|
10
|
-
updatedAt: row.updated_at,
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* D1-backed store of repository blueprints (migration 0011). One row per
|
|
15
|
-
* (workspace, repo): `upsert` replaces the existing blueprint in place, keyed by
|
|
16
|
-
* the unique `(workspace_id, repo_owner, repo_name)` index, so the row is always
|
|
17
|
-
* the single current decomposition. The tree is persisted whole as JSON.
|
|
18
|
-
*/
|
|
19
|
-
export class D1RepoBlueprintRepository {
|
|
20
|
-
db;
|
|
21
|
-
constructor({ db }) {
|
|
22
|
-
this.db = db;
|
|
23
|
-
}
|
|
24
|
-
async upsert(record) {
|
|
25
|
-
await this.db
|
|
26
|
-
.prepare(`INSERT INTO repo_blueprints
|
|
27
|
-
(id, workspace_id, repo_owner, repo_name, source, service_json, created_at, updated_at)
|
|
28
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
29
|
-
ON CONFLICT (workspace_id, repo_owner, repo_name) DO UPDATE SET
|
|
30
|
-
source = excluded.source,
|
|
31
|
-
service_json = excluded.service_json,
|
|
32
|
-
updated_at = excluded.updated_at`)
|
|
33
|
-
.bind(record.id, record.workspaceId, record.repoOwner, record.repoName, record.source, JSON.stringify(record.service), record.createdAt, record.updatedAt)
|
|
34
|
-
.run();
|
|
35
|
-
}
|
|
36
|
-
async get(workspaceId, id) {
|
|
37
|
-
const row = await this.db
|
|
38
|
-
.prepare('SELECT * FROM repo_blueprints WHERE workspace_id = ? AND id = ?')
|
|
39
|
-
.bind(workspaceId, id)
|
|
40
|
-
.first();
|
|
41
|
-
return row ? rowToRecord(row) : null;
|
|
42
|
-
}
|
|
43
|
-
async getByRepo(workspaceId, repoOwner, repoName) {
|
|
44
|
-
const row = await this.db
|
|
45
|
-
.prepare('SELECT * FROM repo_blueprints WHERE workspace_id = ? AND repo_owner = ? AND repo_name = ?')
|
|
46
|
-
.bind(workspaceId, repoOwner, repoName)
|
|
47
|
-
.first();
|
|
48
|
-
return row ? rowToRecord(row) : null;
|
|
49
|
-
}
|
|
50
|
-
async listByWorkspace(workspaceId) {
|
|
51
|
-
const { results } = await this.db
|
|
52
|
-
.prepare('SELECT * FROM repo_blueprints WHERE workspace_id = ? ORDER BY updated_at DESC')
|
|
53
|
-
.bind(workspaceId)
|
|
54
|
-
.all();
|
|
55
|
-
return (results ?? []).map(rowToRecord);
|
|
56
|
-
}
|
|
57
|
-
async delete(workspaceId, id) {
|
|
58
|
-
await this.db
|
|
59
|
-
.prepare('DELETE FROM repo_blueprints WHERE workspace_id = ? AND id = ?')
|
|
60
|
-
.bind(workspaceId, id)
|
|
61
|
-
.run();
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
//# sourceMappingURL=D1RepoBlueprintRepository.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"D1RepoBlueprintRepository.js","sourceRoot":"","sources":["../../../src/infrastructure/repositories/D1RepoBlueprintRepository.ts"],"names":[],"mappings":"AAkBA,SAAS,WAAW,CAAC,GAAqB;IACxC,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,WAAW,EAAE,GAAG,CAAC,YAAY;QAC7B,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,MAAM,EAAE,GAAG,CAAC,MAAuC;QACnD,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAqB;QACzD,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,SAAS,EAAE,GAAG,CAAC,UAAU;KAC1B,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,yBAAyB;IACnB,EAAE,CAAY;IAE/B,YAAY,EAAE,EAAE,EAAsB;QACpC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAA;IACd,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAA2B;QACtC,MAAM,IAAI,CAAC,EAAE;aACV,OAAO,CACN;;;;;;4CAMoC,CACrC;aACA,IAAI,CACH,MAAM,CAAC,EAAE,EACT,MAAM,CAAC,WAAW,EAClB,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,MAAM,EACb,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,EAC9B,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,SAAS,CACjB;aACA,GAAG,EAAE,CAAA;IACV,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,WAAmB,EAAE,EAAU;QACvC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE;aACtB,OAAO,CAAC,iEAAiE,CAAC;aAC1E,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;aACrB,KAAK,EAAoB,CAAA;QAC5B,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACtC,CAAC;IAED,KAAK,CAAC,SAAS,CACb,WAAmB,EACnB,SAAiB,EACjB,QAAgB;QAEhB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE;aACtB,OAAO,CACN,2FAA2F,CAC5F;aACA,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,CAAC;aACtC,KAAK,EAAoB,CAAA;QAC5B,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACtC,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,WAAmB;QACvC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,EAAE;aAC9B,OAAO,CAAC,+EAA+E,CAAC;aACxF,IAAI,CAAC,WAAW,CAAC;aACjB,GAAG,EAAoB,CAAA;QAC1B,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IACzC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,WAAmB,EAAE,EAAU;QAC1C,MAAM,IAAI,CAAC,EAAE;aACV,OAAO,CAAC,+DAA+D,CAAC;aACxE,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;aACrB,GAAG,EAAE,CAAA;IACV,CAAC;CACF"}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { type GitHubClient, type GitHubInstallationRepository, type TaskContent, type TaskCredentials, type TaskSearchResult, type TaskSourceProvider, type NormalizedTaskConnection } from '@cat-factory/kernel';
|
|
2
|
-
export interface GitHubIssuesProviderDependencies {
|
|
3
|
-
githubClient: GitHubClient;
|
|
4
|
-
/** Resolves which installation owns a given repo owner (by account login). */
|
|
5
|
-
installations: GitHubInstallationRepository;
|
|
6
|
-
}
|
|
7
|
-
export declare class GitHubIssuesProvider implements TaskSourceProvider {
|
|
8
|
-
private readonly deps;
|
|
9
|
-
readonly kind: 'github';
|
|
10
|
-
readonly descriptor: {
|
|
11
|
-
source: "github" | "jira";
|
|
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: GitHubIssuesProviderDependencies);
|
|
26
|
-
/**
|
|
27
|
-
* GitHub issues 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: TaskCredentials): NormalizedTaskConnection;
|
|
32
|
-
parseRef(input: string): string | null;
|
|
33
|
-
fetchTask(_credentials: TaskCredentials, externalId: string): Promise<TaskContent>;
|
|
34
|
-
/**
|
|
35
|
-
* Search issues visible to *this workspace's* GitHub App installation. The
|
|
36
|
-
* installation token only sees its own account's repos, so scoping to the
|
|
37
|
-
* workspace's installation keeps results from leaking across tenants — a
|
|
38
|
-
* deployment may host many installations, but a workspace owns exactly one.
|
|
39
|
-
* Credentials are unused (the App authenticates), matching `fetchTask`.
|
|
40
|
-
*/
|
|
41
|
-
search(_credentials: TaskCredentials, query: string, workspaceId: string): Promise<TaskSearchResult[]>;
|
|
42
|
-
/**
|
|
43
|
-
* Find the GitHub App installation whose account owns `owner`. The
|
|
44
|
-
* installation token for that account is what can read the repo's issues,
|
|
45
|
-
* regardless of which workspace triggered the import (one account → one
|
|
46
|
-
* installation, shared across that account's workspaces).
|
|
47
|
-
*/
|
|
48
|
-
private resolveInstallationId;
|
|
49
|
-
}
|
|
50
|
-
//# sourceMappingURL=GitHubIssuesProvider.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GitHubIssuesProvider.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/tasks/GitHubIssuesProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,4BAA4B,EACjC,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC9B,MAAM,qBAAqB,CAAA;AAW5B,MAAM,WAAW,gCAAgC;IAC/C,YAAY,EAAE,YAAY,CAAA;IAC1B,8EAA8E;IAC9E,aAAa,EAAE,4BAA4B,CAAA;CAC5C;AAED,qBAAa,oBAAqB,YAAW,kBAAkB;IAIjD,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAS;IACjC,QAAQ,CAAC,UAAU;;;;;;;;;;;;;;MAA2B;IAE9C,YAA6B,IAAI,EAAE,gCAAgC,EAAI;IAEvE;;;;OAIG;IACH,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,wBAAwB,CAErE;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAErC;IAEK,SAAS,CAAC,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA0BvF;IAED;;;;;;OAMG;IACG,MAAM,CACV,YAAY,EAAE,eAAe,EAC7B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAsB7B;IAED;;;;;OAKG;YACW,qBAAqB;CAUpC"}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { ConflictError, ValidationError, } from '@cat-factory/kernel';
|
|
2
|
-
import { GITHUB_ISSUES_DESCRIPTOR, githubIssuesLogic } from '@cat-factory/integrations';
|
|
3
|
-
export class GitHubIssuesProvider {
|
|
4
|
-
deps;
|
|
5
|
-
kind = 'github';
|
|
6
|
-
descriptor = GITHUB_ISSUES_DESCRIPTOR;
|
|
7
|
-
constructor(deps) {
|
|
8
|
-
this.deps = deps;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* GitHub issues piggyback on the installed GitHub App, so there is nothing to
|
|
12
|
-
* validate or persist — the connection is a marker. Any supplied fields are
|
|
13
|
-
* ignored (the connect form has none).
|
|
14
|
-
*/
|
|
15
|
-
normalizeConnection(_input) {
|
|
16
|
-
return { credentials: {}, label: 'GitHub' };
|
|
17
|
-
}
|
|
18
|
-
parseRef(input) {
|
|
19
|
-
return githubIssuesLogic.parseGitHubIssueRef(input);
|
|
20
|
-
}
|
|
21
|
-
async fetchTask(_credentials, externalId) {
|
|
22
|
-
const id = githubIssuesLogic.parseGitHubIssueExternalId(externalId);
|
|
23
|
-
if (!id) {
|
|
24
|
-
throw new ValidationError(`"${externalId}" is not a valid GitHub issue reference`);
|
|
25
|
-
}
|
|
26
|
-
const installationId = await this.resolveInstallationId(id.owner);
|
|
27
|
-
const detail = await this.deps.githubClient.getIssue(installationId, { owner: id.owner, repo: id.repo }, id.number);
|
|
28
|
-
return {
|
|
29
|
-
externalId,
|
|
30
|
-
url: detail.url || githubIssuesLogic.githubIssueUrl(id),
|
|
31
|
-
title: detail.title,
|
|
32
|
-
// GitHub issues have no workflow status or type beyond open/closed; surface
|
|
33
|
-
// the state as the status and a constant type so the structured prompt
|
|
34
|
-
// rendering stays uniform across sources.
|
|
35
|
-
status: detail.state,
|
|
36
|
-
type: 'Issue',
|
|
37
|
-
assignee: detail.assignee,
|
|
38
|
-
priority: null,
|
|
39
|
-
labels: detail.labels,
|
|
40
|
-
description: detail.body,
|
|
41
|
-
comments: detail.comments,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Search issues visible to *this workspace's* GitHub App installation. The
|
|
46
|
-
* installation token only sees its own account's repos, so scoping to the
|
|
47
|
-
* workspace's installation keeps results from leaking across tenants — a
|
|
48
|
-
* deployment may host many installations, but a workspace owns exactly one.
|
|
49
|
-
* Credentials are unused (the App authenticates), matching `fetchTask`.
|
|
50
|
-
*/
|
|
51
|
-
async search(_credentials, query, workspaceId) {
|
|
52
|
-
const installation = await this.deps.installations.getByWorkspace(workspaceId);
|
|
53
|
-
if (!installation)
|
|
54
|
-
return [];
|
|
55
|
-
const hits = await this.deps.githubClient
|
|
56
|
-
.searchIssues(installation.installationId, query, 20)
|
|
57
|
-
.catch(() => []);
|
|
58
|
-
const out = [];
|
|
59
|
-
const seen = new Set();
|
|
60
|
-
for (const hit of hits) {
|
|
61
|
-
const externalId = githubIssuesLogic.githubIssueExternalId(hit);
|
|
62
|
-
if (seen.has(externalId))
|
|
63
|
-
continue;
|
|
64
|
-
seen.add(externalId);
|
|
65
|
-
out.push({
|
|
66
|
-
source: 'github',
|
|
67
|
-
externalId,
|
|
68
|
-
title: hit.title,
|
|
69
|
-
url: hit.url,
|
|
70
|
-
status: hit.state,
|
|
71
|
-
excerpt: '',
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
return out.slice(0, 20);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Find the GitHub App installation whose account owns `owner`. The
|
|
78
|
-
* installation token for that account is what can read the repo's issues,
|
|
79
|
-
* regardless of which workspace triggered the import (one account → one
|
|
80
|
-
* installation, shared across that account's workspaces).
|
|
81
|
-
*/
|
|
82
|
-
async resolveInstallationId(owner) {
|
|
83
|
-
const active = await this.deps.installations.listActive();
|
|
84
|
-
const match = active.find((i) => i.accountLogin.toLowerCase() === owner.toLowerCase());
|
|
85
|
-
if (!match) {
|
|
86
|
-
throw new ConflictError(`No GitHub App installation found for "${owner}". Install the GitHub App on that account to link its issues.`);
|
|
87
|
-
}
|
|
88
|
-
return match.installationId;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
//# sourceMappingURL=GitHubIssuesProvider.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GitHubIssuesProvider.js","sourceRoot":"","sources":["../../../src/infrastructure/tasks/GitHubIssuesProvider.ts"],"names":[],"mappings":"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"}
|