@opengeni/api-router 0.5.2 → 0.5.4
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/dist/app.js +1 -1
- package/dist/{chunk-YY6OAEL6.js → chunk-DO2G3JSB.js} +5333 -2205
- package/dist/chunk-DO2G3JSB.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +297 -54
- package/dist/index.js.map +1 -1
- package/package.json +21 -21
- package/src/app.ts +415 -147
- package/src/auth/managed-auth.ts +32 -16
- package/src/http/auth.ts +8 -1
- package/src/http/common.ts +6 -2
- package/src/http/sse.ts +27 -6
- package/src/index.ts +196 -74
- package/src/integrations/oauth-client.ts +592 -131
- package/src/integrations/provider-domain.ts +4 -1
- package/src/mcp/documents.ts +173 -94
- package/src/mcp/server.ts +1517 -692
- package/src/mcp/session-view.ts +8 -2
- package/src/mcp/toolspace.ts +175 -84
- package/src/observability.ts +7 -1
- package/src/routes/api-keys.ts +39 -23
- package/src/routes/billing.ts +180 -65
- package/src/routes/capabilities.ts +17 -8
- package/src/routes/catalog-assets.ts +5 -2
- package/src/routes/codex.ts +244 -63
- package/src/routes/connections.ts +72 -34
- package/src/routes/documents.ts +242 -92
- package/src/routes/enrollments.ts +100 -70
- package/src/routes/environments.ts +205 -136
- package/src/routes/files.ts +164 -39
- package/src/routes/github.ts +123 -50
- package/src/routes/install.ts +9 -2
- package/src/routes/machines.ts +9 -8
- package/src/routes/packs.ts +141 -89
- package/src/routes/rigs.ts +189 -0
- package/src/routes/scheduled-tasks.ts +51 -9
- package/src/routes/sessions.ts +839 -329
- package/src/routes/social.ts +50 -38
- package/src/routes/workspace-capture.ts +238 -0
- package/src/routes/workspaces.ts +159 -13
- package/src/sandbox/access.ts +11 -3
- package/src/sandbox/auth-callout.ts +5 -1
- package/src/sandbox/channel-a.ts +104 -27
- package/src/sandbox/enrollment.ts +13 -3
- package/src/sandbox/machines.ts +68 -59
- package/src/sandbox/metrics-ingestion.ts +238 -17
- package/src/sandbox/viewer.ts +172 -46
- package/dist/chunk-YY6OAEL6.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { getSettings } from '@opengeni/config';
|
|
2
2
|
import { ScheduledTaskOverlapPolicy, ScheduledTaskScheduleSpec } from '@opengeni/contracts';
|
|
3
|
+
import { Database } from '@opengeni/db';
|
|
3
4
|
import { ScheduleOverlapPolicy, ScheduleSpec } from '@temporalio/client';
|
|
4
5
|
import { SessionWorkflowClient, DocumentIndexClient } from '@opengeni/core';
|
|
5
6
|
|
|
6
|
-
declare function createTemporalWorkflowClient(settings: ReturnType<typeof getSettings
|
|
7
|
+
declare function createTemporalWorkflowClient(settings: ReturnType<typeof getSettings>, db: Database): Promise<{
|
|
7
8
|
client: SessionWorkflowClient;
|
|
8
9
|
documentIndexer: DocumentIndexClient;
|
|
9
10
|
close: () => Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createApp
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-DO2G3JSB.js";
|
|
4
4
|
|
|
5
5
|
// src/index.ts
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import {
|
|
7
|
+
dbSearchPath,
|
|
8
|
+
getSettings,
|
|
9
|
+
resolveNatsCalloutConfig,
|
|
10
|
+
resolveNatsControlPlaneAuth,
|
|
11
|
+
retryStartupDependency,
|
|
12
|
+
startupRetryOptions
|
|
13
|
+
} from "@opengeni/config";
|
|
14
|
+
import { createDb, markSessionWorkflowWakeDelivered } from "@opengeni/db";
|
|
8
15
|
import { createNatsEventBus } from "@opengeni/events";
|
|
9
16
|
import { createObservability, logStartupDependencyRetry } from "@opengeni/observability";
|
|
10
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
Connection,
|
|
19
|
+
Client as TemporalClient,
|
|
20
|
+
ScheduleNotFoundError,
|
|
21
|
+
ScheduleOverlapPolicy,
|
|
22
|
+
WorkflowExecutionAlreadyStartedError
|
|
23
|
+
} from "@temporalio/client";
|
|
11
24
|
|
|
12
25
|
// src/observability.ts
|
|
13
26
|
function observabilityEventLogger(observability) {
|
|
@@ -38,7 +51,9 @@ function eventAttributeValue(value) {
|
|
|
38
51
|
}
|
|
39
52
|
|
|
40
53
|
// src/sandbox/auth-callout.ts
|
|
41
|
-
import {
|
|
54
|
+
import {
|
|
55
|
+
resolveEnrollmentSigningSecret
|
|
56
|
+
} from "@opengeni/config";
|
|
42
57
|
import { verifyEnrollmentBearer } from "@opengeni/contracts";
|
|
43
58
|
import { getEnrollment } from "@opengeni/db";
|
|
44
59
|
import {
|
|
@@ -135,12 +150,22 @@ async function startAuthCalloutResponder(deps, natsUrl) {
|
|
|
135
150
|
|
|
136
151
|
// src/sandbox/metrics-ingestion.ts
|
|
137
152
|
import {
|
|
153
|
+
clearEnrollmentWentOffline,
|
|
138
154
|
getEnrollment as getEnrollment2,
|
|
139
155
|
ingestMachineMetricsSample,
|
|
156
|
+
sessionsWithActiveOpOnEnrollment,
|
|
140
157
|
setEnrollmentDisplayState,
|
|
158
|
+
setEnrollmentOpStreamState,
|
|
159
|
+
setEnrollmentWentOffline,
|
|
141
160
|
touchEnrollmentLastSeen
|
|
142
161
|
} from "@opengeni/db";
|
|
143
|
-
import {
|
|
162
|
+
import { appendAndPublishEvents } from "@opengeni/events";
|
|
163
|
+
import {
|
|
164
|
+
AgentEvent,
|
|
165
|
+
GoingOfflineReason,
|
|
166
|
+
Hello,
|
|
167
|
+
goingOfflineReasonToJSON
|
|
168
|
+
} from "@opengeni/agent-proto";
|
|
144
169
|
var AGENT_EVENTS_SUBJECT = "agent.*.*.events";
|
|
145
170
|
var AGENT_HELLO_SUBJECT = "agent.*.*.hello";
|
|
146
171
|
function parseAgentSubject(subject, tail) {
|
|
@@ -196,7 +221,27 @@ async function ingestHeartbeat(db, input) {
|
|
|
196
221
|
});
|
|
197
222
|
return { ingested: true, seriesAppended: result.seriesAppended };
|
|
198
223
|
}
|
|
199
|
-
async function
|
|
224
|
+
async function fanOutMachineLinkEvents(db, bus, observability, workspaceId, enrollmentId, build) {
|
|
225
|
+
const sessions = await sessionsWithActiveOpOnEnrollment(db, { workspaceId, enrollmentId });
|
|
226
|
+
for (const session of sessions) {
|
|
227
|
+
try {
|
|
228
|
+
await appendAndPublishEvents(
|
|
229
|
+
db,
|
|
230
|
+
bus,
|
|
231
|
+
workspaceId,
|
|
232
|
+
session.sessionId,
|
|
233
|
+
build(session.activeTurnId)
|
|
234
|
+
);
|
|
235
|
+
} catch (error) {
|
|
236
|
+
observability?.warn?.("Failed to fan out a machine-link event to a session", {
|
|
237
|
+
workspaceId,
|
|
238
|
+
sessionId: session.sessionId,
|
|
239
|
+
error: error instanceof Error ? error.message : String(error)
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
async function handleAgentEventPayload(db, observability, payload, subject, bus) {
|
|
200
245
|
const ids = parseAgentEventSubject(subject);
|
|
201
246
|
if (!ids) {
|
|
202
247
|
return;
|
|
@@ -211,6 +256,54 @@ async function handleAgentEventPayload(db, observability, payload, subject) {
|
|
|
211
256
|
});
|
|
212
257
|
return;
|
|
213
258
|
}
|
|
259
|
+
if (event.event?.$case === "goingOffline") {
|
|
260
|
+
const reason = goingOfflineReasonToJSON(event.event.goingOffline.reason);
|
|
261
|
+
observability?.incrementCounter({
|
|
262
|
+
name: "opengeni_machine_going_offline_total",
|
|
263
|
+
help: "Total Connected Machine clean GoingOffline signals by typed reason.",
|
|
264
|
+
labels: { reason }
|
|
265
|
+
});
|
|
266
|
+
try {
|
|
267
|
+
const enrollment = await getEnrollment2(db, ids.workspaceId, ids.agentId);
|
|
268
|
+
if (enrollment) {
|
|
269
|
+
await setEnrollmentWentOffline(db, {
|
|
270
|
+
accountId: enrollment.accountId,
|
|
271
|
+
workspaceId: ids.workspaceId,
|
|
272
|
+
enrollmentId: ids.agentId,
|
|
273
|
+
reason
|
|
274
|
+
});
|
|
275
|
+
if (bus) {
|
|
276
|
+
const isSelfUpdate = event.event.goingOffline.reason === GoingOfflineReason.GOING_OFFLINE_REASON_UPDATE;
|
|
277
|
+
await fanOutMachineLinkEvents(
|
|
278
|
+
db,
|
|
279
|
+
bus,
|
|
280
|
+
observability,
|
|
281
|
+
ids.workspaceId,
|
|
282
|
+
ids.agentId,
|
|
283
|
+
(activeTurnId) => {
|
|
284
|
+
const events = [
|
|
285
|
+
{ type: "machine.link.lost", turnId: activeTurnId, payload: { reason } }
|
|
286
|
+
];
|
|
287
|
+
if (isSelfUpdate) {
|
|
288
|
+
events.push({
|
|
289
|
+
type: "machine.runner.restarted",
|
|
290
|
+
turnId: activeTurnId,
|
|
291
|
+
payload: {}
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
return events;
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
} catch (error) {
|
|
300
|
+
observability?.warn?.("Failed to record a machine clean going-offline", {
|
|
301
|
+
subject,
|
|
302
|
+
error: error instanceof Error ? error.message : String(error)
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
214
307
|
if (event.event?.$case !== "heartbeat") {
|
|
215
308
|
return;
|
|
216
309
|
}
|
|
@@ -219,7 +312,11 @@ async function handleAgentEventPayload(db, observability, payload, subject) {
|
|
|
219
312
|
return;
|
|
220
313
|
}
|
|
221
314
|
try {
|
|
222
|
-
await ingestHeartbeat(db, {
|
|
315
|
+
await ingestHeartbeat(db, {
|
|
316
|
+
workspaceId: ids.workspaceId,
|
|
317
|
+
agentId: ids.agentId,
|
|
318
|
+
sample: metrics
|
|
319
|
+
});
|
|
223
320
|
} catch (error) {
|
|
224
321
|
observability?.warn?.("Failed to ingest a machine metrics heartbeat", {
|
|
225
322
|
subject,
|
|
@@ -230,7 +327,7 @@ async function handleAgentEventPayload(db, observability, payload, subject) {
|
|
|
230
327
|
function startMetricsIngestion(deps) {
|
|
231
328
|
return deps.bus.subscribeAgentEvents(
|
|
232
329
|
AGENT_EVENTS_SUBJECT,
|
|
233
|
-
(payload, subject) => handleAgentEventPayload(deps.db, deps.observability, payload, subject)
|
|
330
|
+
(payload, subject) => handleAgentEventPayload(deps.db, deps.observability, payload, subject, deps.bus)
|
|
234
331
|
);
|
|
235
332
|
}
|
|
236
333
|
function helloReportsDisplay(hello) {
|
|
@@ -247,6 +344,9 @@ function helloDesktopUnavailableReason(hello) {
|
|
|
247
344
|
const reason = hello.capabilities?.desktopUnavailableReason;
|
|
248
345
|
return reason ? reason : null;
|
|
249
346
|
}
|
|
347
|
+
function helloReportsOpStream(hello) {
|
|
348
|
+
return hello.capabilities?.opStream === true;
|
|
349
|
+
}
|
|
250
350
|
async function refreshEnrollmentDisplay(db, input) {
|
|
251
351
|
const desktopUnavailableReason = input.desktopUnavailableReason ?? null;
|
|
252
352
|
const enrollment = await getEnrollment2(db, input.workspaceId, input.agentId);
|
|
@@ -264,7 +364,22 @@ async function refreshEnrollmentDisplay(db, input) {
|
|
|
264
364
|
desktopUnavailableReason
|
|
265
365
|
});
|
|
266
366
|
}
|
|
267
|
-
async function
|
|
367
|
+
async function refreshEnrollmentOpStream(db, input) {
|
|
368
|
+
const enrollment = await getEnrollment2(db, input.workspaceId, input.agentId);
|
|
369
|
+
if (!enrollment) {
|
|
370
|
+
return { updated: false };
|
|
371
|
+
}
|
|
372
|
+
if (enrollment.opStream === input.opStream) {
|
|
373
|
+
return { updated: false };
|
|
374
|
+
}
|
|
375
|
+
return await setEnrollmentOpStreamState(db, {
|
|
376
|
+
accountId: enrollment.accountId,
|
|
377
|
+
workspaceId: input.workspaceId,
|
|
378
|
+
enrollmentId: input.agentId,
|
|
379
|
+
opStream: input.opStream
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
async function handleHelloPayload(db, observability, payload, subject, bus) {
|
|
268
383
|
const ids = parseAgentHelloSubject(subject);
|
|
269
384
|
if (!ids) {
|
|
270
385
|
return;
|
|
@@ -286,8 +401,38 @@ async function handleHelloPayload(db, observability, payload, subject) {
|
|
|
286
401
|
hasDisplay: helloReportsDisplay(hello),
|
|
287
402
|
desktopUnavailableReason: helloDesktopUnavailableReason(hello)
|
|
288
403
|
});
|
|
404
|
+
await refreshEnrollmentOpStream(db, {
|
|
405
|
+
workspaceId: ids.workspaceId,
|
|
406
|
+
agentId: ids.agentId,
|
|
407
|
+
opStream: helloReportsOpStream(hello)
|
|
408
|
+
});
|
|
409
|
+
} catch (error) {
|
|
410
|
+
observability?.warn?.("Failed to refresh an enrollment's capabilities from a Hello", {
|
|
411
|
+
subject,
|
|
412
|
+
error: error instanceof Error ? error.message : String(error)
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
try {
|
|
416
|
+
const enrollment = await getEnrollment2(db, ids.workspaceId, ids.agentId);
|
|
417
|
+
if (enrollment) {
|
|
418
|
+
const { cleared } = await clearEnrollmentWentOffline(db, {
|
|
419
|
+
accountId: enrollment.accountId,
|
|
420
|
+
workspaceId: ids.workspaceId,
|
|
421
|
+
enrollmentId: ids.agentId
|
|
422
|
+
});
|
|
423
|
+
if (cleared && bus) {
|
|
424
|
+
await fanOutMachineLinkEvents(
|
|
425
|
+
db,
|
|
426
|
+
bus,
|
|
427
|
+
observability,
|
|
428
|
+
ids.workspaceId,
|
|
429
|
+
ids.agentId,
|
|
430
|
+
(activeTurnId) => [{ type: "machine.link.restored", turnId: activeTurnId, payload: {} }]
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
289
434
|
} catch (error) {
|
|
290
|
-
observability?.warn?.("Failed to
|
|
435
|
+
observability?.warn?.("Failed to clear a machine going-offline marker on a Hello", {
|
|
291
436
|
subject,
|
|
292
437
|
error: error instanceof Error ? error.message : String(error)
|
|
293
438
|
});
|
|
@@ -296,7 +441,7 @@ async function handleHelloPayload(db, observability, payload, subject) {
|
|
|
296
441
|
function startHelloIngestion(deps) {
|
|
297
442
|
return deps.bus.subscribeAgentEvents(
|
|
298
443
|
AGENT_HELLO_SUBJECT,
|
|
299
|
-
(payload, subject) => handleHelloPayload(deps.db, deps.observability, payload, subject)
|
|
444
|
+
(payload, subject) => handleHelloPayload(deps.db, deps.observability, payload, subject, deps.bus)
|
|
300
445
|
);
|
|
301
446
|
}
|
|
302
447
|
|
|
@@ -318,7 +463,7 @@ var TEMPORAL_MONTHS = [
|
|
|
318
463
|
"NOVEMBER",
|
|
319
464
|
"DECEMBER"
|
|
320
465
|
];
|
|
321
|
-
async function createTemporalWorkflowClient(settings) {
|
|
466
|
+
async function createTemporalWorkflowClient(settings, db) {
|
|
322
467
|
const connection = await Connection.connect({ address: settings.temporalHost });
|
|
323
468
|
const temporal = new TemporalClient({
|
|
324
469
|
connection,
|
|
@@ -328,7 +473,13 @@ async function createTemporalWorkflowClient(settings) {
|
|
|
328
473
|
signalUserMessage: async ({ eventId, workflowId }) => {
|
|
329
474
|
await temporal.workflow.getHandle(workflowId).signal("userMessage", eventId);
|
|
330
475
|
},
|
|
331
|
-
wakeSessionWorkflow: async ({
|
|
476
|
+
wakeSessionWorkflow: async ({
|
|
477
|
+
accountId,
|
|
478
|
+
workspaceId,
|
|
479
|
+
sessionId,
|
|
480
|
+
workflowId,
|
|
481
|
+
wakeRevision
|
|
482
|
+
}) => {
|
|
332
483
|
await temporal.workflow.signalWithStart("sessionWorkflow", {
|
|
333
484
|
taskQueue: settings.temporalTaskQueue,
|
|
334
485
|
workflowId,
|
|
@@ -336,19 +487,85 @@ async function createTemporalWorkflowClient(settings) {
|
|
|
336
487
|
args: [{ accountId, workspaceId, sessionId }],
|
|
337
488
|
signal: "queueChanged"
|
|
338
489
|
});
|
|
490
|
+
await markSessionWorkflowWakeDelivered(db, {
|
|
491
|
+
accountId,
|
|
492
|
+
workspaceId,
|
|
493
|
+
sessionId,
|
|
494
|
+
temporalWorkflowId: workflowId,
|
|
495
|
+
wakeRevision
|
|
496
|
+
});
|
|
339
497
|
},
|
|
340
|
-
|
|
341
|
-
|
|
498
|
+
signalCodexCapacity: async ({
|
|
499
|
+
accountId,
|
|
500
|
+
workspaceId,
|
|
501
|
+
sessionId,
|
|
502
|
+
workflowId,
|
|
503
|
+
wakeRevision,
|
|
504
|
+
workflowWakeRevision
|
|
505
|
+
}) => {
|
|
506
|
+
await temporal.workflow.signalWithStart("sessionWorkflow", {
|
|
507
|
+
taskQueue: settings.temporalTaskQueue,
|
|
508
|
+
workflowId,
|
|
509
|
+
workflowIdReusePolicy: "ALLOW_DUPLICATE",
|
|
510
|
+
args: [{ accountId, workspaceId, sessionId }],
|
|
511
|
+
signal: "codexCapacityChanged",
|
|
512
|
+
signalArgs: [wakeRevision]
|
|
513
|
+
});
|
|
514
|
+
await markSessionWorkflowWakeDelivered(db, {
|
|
515
|
+
accountId,
|
|
516
|
+
workspaceId,
|
|
517
|
+
sessionId,
|
|
518
|
+
temporalWorkflowId: workflowId,
|
|
519
|
+
wakeRevision: workflowWakeRevision
|
|
520
|
+
});
|
|
342
521
|
},
|
|
343
|
-
|
|
522
|
+
signalApprovalDecision: async ({
|
|
523
|
+
accountId,
|
|
524
|
+
workspaceId,
|
|
525
|
+
sessionId,
|
|
526
|
+
eventId,
|
|
527
|
+
workflowId,
|
|
528
|
+
workflowWakeRevision
|
|
529
|
+
}) => {
|
|
344
530
|
await temporal.workflow.signalWithStart("sessionWorkflow", {
|
|
345
531
|
taskQueue: settings.temporalTaskQueue,
|
|
346
532
|
workflowId,
|
|
347
533
|
workflowIdReusePolicy: "ALLOW_DUPLICATE",
|
|
348
534
|
args: [{ accountId, workspaceId, sessionId }],
|
|
349
|
-
signal: "
|
|
535
|
+
signal: "approvalDecision",
|
|
350
536
|
signalArgs: [eventId]
|
|
351
537
|
});
|
|
538
|
+
await markSessionWorkflowWakeDelivered(db, {
|
|
539
|
+
accountId,
|
|
540
|
+
workspaceId,
|
|
541
|
+
sessionId,
|
|
542
|
+
temporalWorkflowId: workflowId,
|
|
543
|
+
wakeRevision: workflowWakeRevision
|
|
544
|
+
});
|
|
545
|
+
},
|
|
546
|
+
signalSessionControl: async ({
|
|
547
|
+
accountId,
|
|
548
|
+
workspaceId,
|
|
549
|
+
sessionId,
|
|
550
|
+
eventId,
|
|
551
|
+
workflowId,
|
|
552
|
+
workflowWakeRevision
|
|
553
|
+
}) => {
|
|
554
|
+
await temporal.workflow.signalWithStart("sessionWorkflow", {
|
|
555
|
+
taskQueue: settings.temporalTaskQueue,
|
|
556
|
+
workflowId,
|
|
557
|
+
workflowIdReusePolicy: "ALLOW_DUPLICATE",
|
|
558
|
+
args: [{ accountId, workspaceId, sessionId }],
|
|
559
|
+
signal: "sessionControl",
|
|
560
|
+
signalArgs: [eventId]
|
|
561
|
+
});
|
|
562
|
+
await markSessionWorkflowWakeDelivered(db, {
|
|
563
|
+
accountId,
|
|
564
|
+
workspaceId,
|
|
565
|
+
sessionId,
|
|
566
|
+
temporalWorkflowId: workflowId,
|
|
567
|
+
wakeRevision: workflowWakeRevision
|
|
568
|
+
});
|
|
352
569
|
},
|
|
353
570
|
syncScheduledTask: async ({ task }) => {
|
|
354
571
|
const schedule = temporal.schedule.getHandle(task.temporalScheduleId);
|
|
@@ -372,13 +589,15 @@ async function createTemporalWorkflowClient(settings) {
|
|
|
372
589
|
taskQueue: settings.temporalTaskQueue,
|
|
373
590
|
workflowId,
|
|
374
591
|
workflowIdReusePolicy: "REJECT_DUPLICATE",
|
|
375
|
-
args: [
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
592
|
+
args: [
|
|
593
|
+
{
|
|
594
|
+
accountId: task.accountId,
|
|
595
|
+
workspaceId: task.workspaceId,
|
|
596
|
+
taskId: task.id,
|
|
597
|
+
triggerType: "manual",
|
|
598
|
+
agentRunUsageIdempotencyKey
|
|
599
|
+
}
|
|
600
|
+
]
|
|
382
601
|
});
|
|
383
602
|
} catch (error) {
|
|
384
603
|
if (isWorkflowAlreadyStarted(error)) {
|
|
@@ -387,6 +606,24 @@ async function createTemporalWorkflowClient(settings) {
|
|
|
387
606
|
throw error;
|
|
388
607
|
}
|
|
389
608
|
},
|
|
609
|
+
startRigVerification: async ({ workspaceId, changeId, versionId, workflowId }) => {
|
|
610
|
+
const targetId = changeId ?? versionId;
|
|
611
|
+
if (!targetId) {
|
|
612
|
+
throw new Error("rig verification requires changeId or versionId");
|
|
613
|
+
}
|
|
614
|
+
await temporal.workflow.start("rigVerificationWorkflow", {
|
|
615
|
+
taskQueue: settings.temporalTaskQueue,
|
|
616
|
+
workflowId: workflowId ?? `rig-verification-${targetId}-${crypto.randomUUID()}`,
|
|
617
|
+
workflowIdReusePolicy: "ALLOW_DUPLICATE",
|
|
618
|
+
args: [
|
|
619
|
+
{
|
|
620
|
+
workspaceId,
|
|
621
|
+
...changeId ? { changeId } : {},
|
|
622
|
+
...versionId ? { versionId } : {}
|
|
623
|
+
}
|
|
624
|
+
]
|
|
625
|
+
});
|
|
626
|
+
},
|
|
390
627
|
check: async () => {
|
|
391
628
|
await connection.workflowService.getSystemInfo({});
|
|
392
629
|
}
|
|
@@ -435,16 +672,16 @@ async function startApi() {
|
|
|
435
672
|
onRetry
|
|
436
673
|
}
|
|
437
674
|
);
|
|
438
|
-
workflowClient = await retryStartupDependency(
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
675
|
+
workflowClient = await retryStartupDependency(
|
|
676
|
+
"Temporal",
|
|
677
|
+
() => createTemporalWorkflowClient(settings, dbClient.db),
|
|
678
|
+
{
|
|
679
|
+
...retryOptions,
|
|
680
|
+
onRetry
|
|
681
|
+
}
|
|
682
|
+
);
|
|
442
683
|
} catch (error) {
|
|
443
|
-
await Promise.allSettled([
|
|
444
|
-
bus?.close(),
|
|
445
|
-
workflowClient?.close(),
|
|
446
|
-
dbClient.close()
|
|
447
|
-
]);
|
|
684
|
+
await Promise.allSettled([bus?.close(), workflowClient?.close(), dbClient.close()]);
|
|
448
685
|
throw error;
|
|
449
686
|
}
|
|
450
687
|
if (!bus || !workflowClient) {
|
|
@@ -535,25 +772,29 @@ function temporalScheduleSpec(schedule) {
|
|
|
535
772
|
}
|
|
536
773
|
if (schedule.type === "calendar") {
|
|
537
774
|
return {
|
|
538
|
-
calendars: [
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
775
|
+
calendars: [
|
|
776
|
+
{
|
|
777
|
+
hour: schedule.hour,
|
|
778
|
+
minute: schedule.minute,
|
|
779
|
+
second: 0,
|
|
780
|
+
...schedule.daysOfWeek ? { dayOfWeek: schedule.daysOfWeek } : {}
|
|
781
|
+
}
|
|
782
|
+
],
|
|
544
783
|
timezone: schedule.timeZone
|
|
545
784
|
};
|
|
546
785
|
}
|
|
547
786
|
const runAt = new Date(schedule.runAt);
|
|
548
787
|
return {
|
|
549
|
-
calendars: [
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
788
|
+
calendars: [
|
|
789
|
+
{
|
|
790
|
+
year: runAt.getUTCFullYear(),
|
|
791
|
+
month: temporalMonth(runAt.getUTCMonth()),
|
|
792
|
+
dayOfMonth: runAt.getUTCDate(),
|
|
793
|
+
hour: runAt.getUTCHours(),
|
|
794
|
+
minute: runAt.getUTCMinutes(),
|
|
795
|
+
second: runAt.getUTCSeconds()
|
|
796
|
+
}
|
|
797
|
+
],
|
|
557
798
|
timezone: "UTC"
|
|
558
799
|
};
|
|
559
800
|
}
|
|
@@ -568,12 +809,14 @@ function temporalScheduleOptions(task, taskQueue) {
|
|
|
568
809
|
type: "startWorkflow",
|
|
569
810
|
workflowType: "scheduledTaskFireWorkflow",
|
|
570
811
|
taskQueue,
|
|
571
|
-
args: [
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
812
|
+
args: [
|
|
813
|
+
{
|
|
814
|
+
accountId: task.accountId,
|
|
815
|
+
workspaceId: task.workspaceId,
|
|
816
|
+
taskId: task.id,
|
|
817
|
+
triggerType: "scheduled"
|
|
818
|
+
}
|
|
819
|
+
]
|
|
577
820
|
},
|
|
578
821
|
policies: {
|
|
579
822
|
overlap: temporalOverlapPolicy(task.overlapPolicy),
|