@on-par/factory-core 0.9.26 → 0.9.27-next.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 (87) hide show
  1. package/dist/config/index.d.ts +0 -1
  2. package/dist/config/index.d.ts.map +1 -1
  3. package/dist/config/index.js +1 -3
  4. package/dist/config/index.js.map +1 -1
  5. package/dist/config/run-section.d.ts +1 -1
  6. package/dist/config/run-section.js +1 -1
  7. package/dist/index.d.ts +6 -29
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +3 -17
  10. package/dist/index.js.map +1 -1
  11. package/package.json +5 -5
  12. package/dist/config/v2-models.d.ts +0 -75
  13. package/dist/config/v2-models.d.ts.map +0 -1
  14. package/dist/config/v2-models.js +0 -119
  15. package/dist/config/v2-models.js.map +0 -1
  16. package/dist/config/v2.d.ts +0 -252
  17. package/dist/config/v2.d.ts.map +0 -1
  18. package/dist/config/v2.js +0 -369
  19. package/dist/config/v2.js.map +0 -1
  20. package/dist/hosted/control-plane.d.ts +0 -40
  21. package/dist/hosted/control-plane.d.ts.map +0 -1
  22. package/dist/hosted/control-plane.js +0 -198
  23. package/dist/hosted/control-plane.js.map +0 -1
  24. package/dist/hosted/queue-client.d.ts +0 -51
  25. package/dist/hosted/queue-client.d.ts.map +0 -1
  26. package/dist/hosted/queue-client.js +0 -92
  27. package/dist/hosted/queue-client.js.map +0 -1
  28. package/dist/hosted/runner-client.d.ts +0 -78
  29. package/dist/hosted/runner-client.d.ts.map +0 -1
  30. package/dist/hosted/runner-client.js +0 -82
  31. package/dist/hosted/runner-client.js.map +0 -1
  32. package/dist/hosted/runner.d.ts +0 -74
  33. package/dist/hosted/runner.d.ts.map +0 -1
  34. package/dist/hosted/runner.js +0 -174
  35. package/dist/hosted/runner.js.map +0 -1
  36. package/dist/hosted/smoke.d.ts +0 -46
  37. package/dist/hosted/smoke.d.ts.map +0 -1
  38. package/dist/hosted/smoke.js +0 -56
  39. package/dist/hosted/smoke.js.map +0 -1
  40. package/dist/hosted/store-resolve.d.ts +0 -16
  41. package/dist/hosted/store-resolve.d.ts.map +0 -1
  42. package/dist/hosted/store-resolve.js +0 -13
  43. package/dist/hosted/store-resolve.js.map +0 -1
  44. package/dist/hosted/store-sqlite.d.ts +0 -10
  45. package/dist/hosted/store-sqlite.d.ts.map +0 -1
  46. package/dist/hosted/store-sqlite.js +0 -67
  47. package/dist/hosted/store-sqlite.js.map +0 -1
  48. package/dist/hosted/summary.d.ts +0 -26
  49. package/dist/hosted/summary.d.ts.map +0 -1
  50. package/dist/hosted/summary.js +0 -27
  51. package/dist/hosted/summary.js.map +0 -1
  52. package/dist/hosted/watchdog.d.ts +0 -38
  53. package/dist/hosted/watchdog.d.ts.map +0 -1
  54. package/dist/hosted/watchdog.js +0 -56
  55. package/dist/hosted/watchdog.js.map +0 -1
  56. package/dist/phases/board-queue-dispatch.d.ts +0 -21
  57. package/dist/phases/board-queue-dispatch.d.ts.map +0 -1
  58. package/dist/phases/board-queue-dispatch.js +0 -57
  59. package/dist/phases/board-queue-dispatch.js.map +0 -1
  60. package/dist/phases/board-queue-scheduler.d.ts +0 -19
  61. package/dist/phases/board-queue-scheduler.d.ts.map +0 -1
  62. package/dist/phases/board-queue-scheduler.js +0 -56
  63. package/dist/phases/board-queue-scheduler.js.map +0 -1
  64. package/dist/projects/project-queue-poller.d.ts +0 -25
  65. package/dist/projects/project-queue-poller.d.ts.map +0 -1
  66. package/dist/projects/project-queue-poller.js +0 -92
  67. package/dist/projects/project-queue-poller.js.map +0 -1
  68. package/dist/projects/project-queue-reader.d.ts +0 -40
  69. package/dist/projects/project-queue-reader.d.ts.map +0 -1
  70. package/dist/projects/project-queue-reader.js +0 -185
  71. package/dist/projects/project-queue-reader.js.map +0 -1
  72. package/dist/projects/project-status-writer.d.ts +0 -12
  73. package/dist/projects/project-status-writer.d.ts.map +0 -1
  74. package/dist/projects/project-status-writer.js +0 -42
  75. package/dist/projects/project-status-writer.js.map +0 -1
  76. package/dist/queue/project-board-poller.d.ts +0 -15
  77. package/dist/queue/project-board-poller.d.ts.map +0 -1
  78. package/dist/queue/project-board-poller.js +0 -3
  79. package/dist/queue/project-board-poller.js.map +0 -1
  80. package/dist/queue/project-board-status-writer.d.ts +0 -42
  81. package/dist/queue/project-board-status-writer.d.ts.map +0 -1
  82. package/dist/queue/project-board-status-writer.js +0 -83
  83. package/dist/queue/project-board-status-writer.js.map +0 -1
  84. package/dist/queue/reprioritization-audit.d.ts +0 -19
  85. package/dist/queue/reprioritization-audit.d.ts.map +0 -1
  86. package/dist/queue/reprioritization-audit.js +0 -77
  87. package/dist/queue/reprioritization-audit.js.map +0 -1
@@ -1,40 +0,0 @@
1
- import http from 'node:http';
2
- import type { HostedJobStore } from './store.js';
3
- export interface ControlPlaneResponse {
4
- status: number;
5
- body: unknown;
6
- }
7
- export interface HostedControlPlaneOptions {
8
- store: HostedJobStore;
9
- /** Defaults to process.env. Gate check reads FACTORY_HOSTED_EXEC from this. */
10
- env?: NodeJS.ProcessEnv;
11
- /** Default 8799; pass 0 in tests for an ephemeral port. */
12
- port?: number;
13
- /** Default '127.0.0.1' — never anything else in production code paths. */
14
- host?: string;
15
- /** Default randomUUID(); injectable for deterministic tests. */
16
- generateJobId?: () => string;
17
- }
18
- export interface HostedControlPlaneServer {
19
- server: http.Server;
20
- /** Actual bound port after start() resolves. */
21
- port: number;
22
- start(): Promise<number>;
23
- stop(): Promise<void>;
24
- }
25
- interface HostedControlPlaneRequest {
26
- method: string;
27
- pathname: string;
28
- body: unknown;
29
- generateJobId: () => string;
30
- }
31
- /** Pure router: no I/O, no clock — everything comes from the injected store
32
- * and request shape. Responses only ever contain summarizeHostedJob output
33
- * and the store's already-redacted events/result, never raw secrets. */
34
- export declare function handleHostedControlPlaneRequest(store: HostedJobStore, request: HostedControlPlaneRequest): ControlPlaneResponse;
35
- /** Constructs the http.Server wrapper. Throws synchronously (start() never
36
- * binds) when FACTORY_HOSTED_EXEC is not '1' — construction, not just
37
- * start(), fails closed. */
38
- export declare function createHostedControlPlaneServer(options: HostedControlPlaneOptions): HostedControlPlaneServer;
39
- export {};
40
- //# sourceMappingURL=control-plane.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"control-plane.d.ts","sourceRoot":"","sources":["../../src/hosted/control-plane.ts"],"names":[],"mappings":"AAaA,OAAO,IAAI,MAAM,WAAW,CAAC;AAM7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAsBjD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,cAAc,CAAC;IACtB,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;IACpB,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACzB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,UAAU,yBAAyB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,EAAE,MAAM,MAAM,CAAC;CAC7B;AAKD;;wEAEwE;AACxE,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,yBAAyB,GACjC,oBAAoB,CAqFtB;AAsBD;;4BAE4B;AAC5B,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,yBAAyB,GAAG,wBAAwB,CA6D3G"}
@@ -1,198 +0,0 @@
1
- // src/hosted/control-plane.ts — Minimal local HTTP control-plane API over the
2
- // in-memory HostedJobStore (#924, parent #895/#896). Proves the hosted-exec
3
- // server/client split with a pure request router plus a thin node:http
4
- // wrapper: create a job, inspect it, list its events and result, and cancel
5
- // it. Off by default (gated by FACTORY_HOSTED_EXEC via hostedExecEnabled),
6
- // secret-redacted (responses only ever serialize summarizeHostedJob output
7
- // and the store's already-redacted events/result), no persistence, no auth.
8
- //
9
- // Manual smoke: `FACTORY_HOSTED_EXEC=1` then start the server and
10
- // `curl -XPOST localhost:8799/jobs -d '{"repoSlug":"on-par/software-factory","taskPayload":"smoke","requiredCapabilities":["git"],"requiredAuthority":"repo:write"}'`
11
- // followed by `curl localhost:8799/jobs/<id>`.
12
- import { randomUUID } from 'node:crypto';
13
- import http from 'node:http';
14
- import { hostedExecEnabled } from '@on-par/contracts';
15
- import { z } from 'zod';
16
- import { summarizeHostedJob } from './summary.js';
17
- const CreateJobBodySchema = z.object({
18
- jobId: z.string().min(1).optional(),
19
- repoSlug: z.string().min(1),
20
- taskPayload: z.string().min(1),
21
- requiredCapabilities: z.array(z.string().min(1)),
22
- requiredAuthority: z.string().min(1),
23
- });
24
- const RegisterRunnerBodySchema = z.object({
25
- runnerId: z.string().min(1),
26
- capabilities: z.array(z.string().min(1)),
27
- });
28
- const PollForLeaseBodySchema = z.object({
29
- capabilities: z.array(z.string().min(1)),
30
- leaseId: z.string().min(1),
31
- ttlMs: z.number().int().positive(),
32
- heartbeatIntervalMs: z.number().int().positive(),
33
- });
34
- const JOB_PATH_PATTERN = /^\/jobs\/([^/]+)(?:\/(events|result|cancel))?$/;
35
- const RUNNER_POLL_PATH_PATTERN = /^\/runners\/([^/]+)\/poll$/;
36
- /** Pure router: no I/O, no clock — everything comes from the injected store
37
- * and request shape. Responses only ever contain summarizeHostedJob output
38
- * and the store's already-redacted events/result, never raw secrets. */
39
- export function handleHostedControlPlaneRequest(store, request) {
40
- const { method, pathname, body, generateJobId } = request;
41
- if (pathname === '/jobs') {
42
- if (method !== 'POST') {
43
- return { status: 405, body: { error: 'method not allowed' } };
44
- }
45
- const parsed = CreateJobBodySchema.safeParse(body);
46
- if (!parsed.success) {
47
- return { status: 400, body: { error: parsed.error.message } };
48
- }
49
- const jobId = parsed.data.jobId ?? generateJobId();
50
- try {
51
- const job = store.create({ ...parsed.data, jobId });
52
- return { status: 201, body: { job: summarizeHostedJob(job) } };
53
- }
54
- catch (error) {
55
- return { status: 409, body: { error: error.message } };
56
- }
57
- }
58
- if (pathname === '/runners') {
59
- if (method !== 'POST') {
60
- return { status: 405, body: { error: 'method not allowed' } };
61
- }
62
- const parsed = RegisterRunnerBodySchema.safeParse(body);
63
- if (!parsed.success) {
64
- return { status: 400, body: { error: parsed.error.message } };
65
- }
66
- const runner = store.registerRunner(parsed.data);
67
- return { status: 201, body: { runner } };
68
- }
69
- const pollMatch = RUNNER_POLL_PATH_PATTERN.exec(pathname);
70
- if (pollMatch) {
71
- if (method !== 'POST') {
72
- return { status: 405, body: { error: 'method not allowed' } };
73
- }
74
- const parsed = PollForLeaseBodySchema.safeParse(body);
75
- if (!parsed.success) {
76
- return { status: 400, body: { error: parsed.error.message } };
77
- }
78
- const runnerId = pollMatch[1];
79
- const result = store.pollForLease({ runnerId, ...parsed.data });
80
- if (!result.ok) {
81
- return { status: 200, body: { ok: false, reason: result.reason } };
82
- }
83
- return { status: 200, body: { ok: true, lease: result.lease, job: summarizeHostedJob(result.job) } };
84
- }
85
- const match = JOB_PATH_PATTERN.exec(pathname);
86
- if (!match) {
87
- return { status: 404, body: { error: 'not found' } };
88
- }
89
- const [, jobId, subresource] = match;
90
- if (subresource === 'cancel') {
91
- if (method !== 'POST') {
92
- return { status: 405, body: { error: 'method not allowed' } };
93
- }
94
- const result = store.cancel(jobId, 'operator requested cancellation via control plane');
95
- if (!result.ok) {
96
- return { status: 404, body: { error: 'job not found' } };
97
- }
98
- return {
99
- status: 200,
100
- body: { jobId, status: result.job.request.status, alreadyTerminal: result.alreadyTerminal },
101
- };
102
- }
103
- if (method !== 'GET') {
104
- return { status: 405, body: { error: 'method not allowed' } };
105
- }
106
- const job = store.get(jobId);
107
- if (!job) {
108
- return { status: 404, body: { error: 'job not found' } };
109
- }
110
- if (subresource === 'events') {
111
- return { status: 200, body: { events: job.events } };
112
- }
113
- if (subresource === 'result') {
114
- return { status: 200, body: { result: job.result } };
115
- }
116
- return { status: 200, body: { job: summarizeHostedJob(job) } };
117
- }
118
- function readJsonBody(req) {
119
- return new Promise((resolvePromise) => {
120
- const chunks = [];
121
- req.on('data', (chunk) => chunks.push(chunk));
122
- req.on('error', () => resolvePromise({ ok: false }));
123
- req.on('end', () => {
124
- const text = Buffer.concat(chunks).toString('utf-8');
125
- if (!text) {
126
- resolvePromise({ ok: true, value: {} });
127
- return;
128
- }
129
- try {
130
- resolvePromise({ ok: true, value: JSON.parse(text) });
131
- }
132
- catch {
133
- resolvePromise({ ok: false });
134
- }
135
- });
136
- });
137
- }
138
- /** Constructs the http.Server wrapper. Throws synchronously (start() never
139
- * binds) when FACTORY_HOSTED_EXEC is not '1' — construction, not just
140
- * start(), fails closed. */
141
- export function createHostedControlPlaneServer(options) {
142
- const env = options.env ?? process.env;
143
- if (!hostedExecEnabled(env)) {
144
- throw new Error('hosted-exec control plane refused to start: set FACTORY_HOSTED_EXEC=1 to enable');
145
- }
146
- const { store } = options;
147
- const desiredPort = options.port ?? 8799;
148
- const host = options.host ?? '127.0.0.1';
149
- const generateJobId = options.generateJobId ?? (() => randomUUID());
150
- const server = http.createServer((req, res) => {
151
- void (async () => {
152
- const method = req.method ?? 'GET';
153
- const pathname = new URL(req.url ?? '/', 'http://localhost').pathname;
154
- let body = {};
155
- if (method === 'POST') {
156
- const parsed = await readJsonBody(req);
157
- if (!parsed.ok) {
158
- res.writeHead(400, { 'content-type': 'application/json' });
159
- res.end(JSON.stringify({ error: 'invalid json body' }));
160
- return;
161
- }
162
- body = parsed.value;
163
- }
164
- const response = handleHostedControlPlaneRequest(store, { method, pathname, body, generateJobId });
165
- res.writeHead(response.status, { 'content-type': 'application/json' });
166
- res.end(JSON.stringify(response.body));
167
- })();
168
- });
169
- const controlPlane = {
170
- server,
171
- port: desiredPort,
172
- start() {
173
- return new Promise((resolvePromise, reject) => {
174
- const onError = (err) => {
175
- server.off('listening', onListening);
176
- reject(err);
177
- };
178
- const onListening = () => {
179
- server.off('error', onError);
180
- const addr = server.address();
181
- controlPlane.port = addr && typeof addr === 'object' ? addr.port : desiredPort;
182
- resolvePromise(controlPlane.port);
183
- };
184
- server.once('error', onError);
185
- server.once('listening', onListening);
186
- server.listen({ port: desiredPort, host, exclusive: true });
187
- });
188
- },
189
- stop() {
190
- return new Promise((resolvePromise) => {
191
- server.closeAllConnections();
192
- server.close(() => resolvePromise());
193
- });
194
- },
195
- };
196
- return controlPlane;
197
- }
198
- //# sourceMappingURL=control-plane.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"control-plane.js","sourceRoot":"","sources":["../../src/hosted/control-plane.ts"],"names":[],"mappings":"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"}
@@ -1,51 +0,0 @@
1
- import type { HostedJobEvent, HostedJobStatus } from '@on-par/contracts';
2
- import type { HostedControlPlaneFetchFn } from './runner-client.js';
3
- import type { HostedJobSummary } from './summary.js';
4
- export interface HostedJobClient {
5
- createJob(input: {
6
- repoSlug: string;
7
- taskPayload: string;
8
- requiredCapabilities: string[];
9
- requiredAuthority: string;
10
- jobId?: string;
11
- }): Promise<HostedJobSummary>;
12
- getJob(jobId: string): Promise<HostedJobSummary>;
13
- getEvents(jobId: string): Promise<HostedJobEvent[]>;
14
- }
15
- export interface HttpHostedJobClientOptions {
16
- /** e.g. 'http://127.0.0.1:8799'. Trailing slash tolerated. */
17
- baseUrl: string;
18
- /** default globalThis.fetch */
19
- fetchImpl?: HostedControlPlaneFetchFn;
20
- }
21
- /** Production client: talks to a running createHostedControlPlaneServer over
22
- * HTTP. Throws on transport/HTTP failure — the caller decides how to react. */
23
- export declare function createHttpHostedJobClient(options: HttpHostedJobClientOptions): HostedJobClient;
24
- export interface QueueAndTailConfig {
25
- repoSlug: string;
26
- taskPayload: string;
27
- requiredCapabilities: string[];
28
- requiredAuthority: string;
29
- jobId?: string;
30
- /** Bounded wait window for polling to a terminal status. Default 120_000. */
31
- timeoutMs?: number;
32
- /** Delay between summary polls. Default 1_000. */
33
- pollIntervalMs?: number;
34
- /** default () => Date.now() */
35
- now?: () => number;
36
- /** default a real setTimeout-backed delay */
37
- sleep?: (ms: number) => Promise<void>;
38
- }
39
- export interface QueueAndTailOutcome {
40
- jobId: string;
41
- terminal: boolean;
42
- status: HostedJobStatus;
43
- summary: HostedJobSummary;
44
- events: HostedJobEvent[];
45
- trace: string;
46
- }
47
- /** Creates one job, polls its summary within a bounded wait window until it
48
- * reaches a terminal status (or the window elapses), then reads the full
49
- * ordered event list once. Never loops past the deadline. */
50
- export declare function queueAndTailJob(client: HostedJobClient, config: QueueAndTailConfig): Promise<QueueAndTailOutcome>;
51
- //# sourceMappingURL=queue-client.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"queue-client.d.ts","sourceRoot":"","sources":["../../src/hosted/queue-client.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAkBrD,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,KAAK,EAAE;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,oBAAoB,EAAE,MAAM,EAAE,CAAC;QAC/B,iBAAiB,EAAE,MAAM,CAAC;QAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC9B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACjD,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,0BAA0B;IACzC,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,SAAS,CAAC,EAAE,yBAAyB,CAAC;CACvC;AAED;+EAC+E;AAC/E,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,0BAA0B,GAAG,eAAe,CA4C9F;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;6DAE6D;AAC7D,wBAAsB,eAAe,CACnC,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,mBAAmB,CAAC,CAkC9B"}
@@ -1,92 +0,0 @@
1
- /** Linear-time trim (no regex) — baseUrl is caller-supplied library input, so a
2
- * `/\/+$/`-style pattern would flag as a polynomial-regex-on-untrusted-input risk. */
3
- function trimTrailingSlashes(value) {
4
- let end = value.length;
5
- while (end > 0 && value[end - 1] === '/') {
6
- end -= 1;
7
- }
8
- return value.slice(0, end);
9
- }
10
- const TERMINAL_STATUSES = new Set(['done', 'failed', 'canceled']);
11
- function isTerminalStatus(status) {
12
- return TERMINAL_STATUSES.has(status);
13
- }
14
- /** Production client: talks to a running createHostedControlPlaneServer over
15
- * HTTP. Throws on transport/HTTP failure — the caller decides how to react. */
16
- export function createHttpHostedJobClient(options) {
17
- const baseUrl = trimTrailingSlashes(options.baseUrl);
18
- const fetchImpl = options.fetchImpl ?? globalThis.fetch;
19
- async function post(path, body) {
20
- const res = await fetchImpl(`${baseUrl}${path}`, {
21
- method: 'POST',
22
- headers: { 'content-type': 'application/json' },
23
- body: JSON.stringify(body),
24
- });
25
- const data = await res.json();
26
- if (!res.ok) {
27
- const message = data && typeof data === 'object' && 'error' in data ? String(data.error) : res.status;
28
- throw new Error(`hosted job client ${path} failed: ${message}`);
29
- }
30
- return data;
31
- }
32
- async function get(path) {
33
- const res = await fetchImpl(`${baseUrl}${path}`, { method: 'GET' });
34
- const data = await res.json();
35
- if (!res.ok) {
36
- const message = data && typeof data === 'object' && 'error' in data ? String(data.error) : res.status;
37
- throw new Error(`hosted job client ${path} failed: ${message}`);
38
- }
39
- return data;
40
- }
41
- return {
42
- async createJob(input) {
43
- const data = (await post('/jobs', input));
44
- return data.job;
45
- },
46
- async getJob(jobId) {
47
- const data = (await get(`/jobs/${encodeURIComponent(jobId)}`));
48
- return data.job;
49
- },
50
- async getEvents(jobId) {
51
- const data = (await get(`/jobs/${encodeURIComponent(jobId)}/events`));
52
- return data.events;
53
- },
54
- };
55
- }
56
- /** Creates one job, polls its summary within a bounded wait window until it
57
- * reaches a terminal status (or the window elapses), then reads the full
58
- * ordered event list once. Never loops past the deadline. */
59
- export async function queueAndTailJob(client, config) {
60
- const timeoutMs = config.timeoutMs ?? 120_000;
61
- const pollIntervalMs = config.pollIntervalMs ?? 1_000;
62
- const now = config.now ?? (() => Date.now());
63
- const sleep = config.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
64
- let summary = await client.createJob({
65
- repoSlug: config.repoSlug,
66
- taskPayload: config.taskPayload,
67
- requiredCapabilities: config.requiredCapabilities,
68
- requiredAuthority: config.requiredAuthority,
69
- jobId: config.jobId,
70
- });
71
- const jobId = summary.jobId;
72
- const deadline = now() + timeoutMs;
73
- for (;;) {
74
- if (isTerminalStatus(summary.status))
75
- break;
76
- if (now() >= deadline)
77
- break;
78
- await sleep(pollIntervalMs);
79
- summary = await client.getJob(jobId);
80
- }
81
- const events = await client.getEvents(jobId);
82
- const terminal = isTerminalStatus(summary.status);
83
- return {
84
- jobId,
85
- terminal,
86
- status: summary.status,
87
- summary,
88
- events,
89
- trace: `queued ${jobId} -> ${summary.status}`,
90
- };
91
- }
92
- //# sourceMappingURL=queue-client.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"queue-client.js","sourceRoot":"","sources":["../../src/hosted/queue-client.ts"],"names":[],"mappings":"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"}
@@ -1,78 +0,0 @@
1
- import type { RunnerLease } from '@on-par/contracts';
2
- import type { HostedJobSummary } from './summary.js';
3
- export interface RegisteredRunner {
4
- runnerId: string;
5
- capabilities: string[];
6
- available: boolean;
7
- lastHeartbeatAt: string;
8
- }
9
- export type PollForLeaseResult = {
10
- ok: true;
11
- lease: RunnerLease;
12
- job: HostedJobSummary;
13
- } | {
14
- ok: false;
15
- reason: 'no-match';
16
- };
17
- export interface HostedControlPlaneClient {
18
- registerRunner(input: {
19
- runnerId: string;
20
- capabilities: string[];
21
- }): Promise<RegisteredRunner>;
22
- pollForLease(input: {
23
- runnerId: string;
24
- capabilities: string[];
25
- leaseId: string;
26
- ttlMs: number;
27
- heartbeatIntervalMs: number;
28
- }): Promise<PollForLeaseResult>;
29
- }
30
- /** Structurally identical to the router's FetchFn — defined here so this
31
- * module does not import from ../router (avoids an import cycle). */
32
- export type HostedControlPlaneFetchFn = (input: string, init?: {
33
- method?: string;
34
- headers?: Record<string, string>;
35
- body?: string;
36
- }) => Promise<{
37
- ok: boolean;
38
- status: number;
39
- json(): Promise<unknown>;
40
- }>;
41
- export interface HttpHostedControlPlaneClientOptions {
42
- /** e.g. 'http://127.0.0.1:8799'. Trailing slash tolerated. */
43
- baseUrl: string;
44
- /** default globalThis.fetch */
45
- fetchImpl?: HostedControlPlaneFetchFn;
46
- }
47
- /** Production client: talks to a running createHostedControlPlaneServer over
48
- * HTTP. Throws on transport/HTTP failure — the caller decides how to react. */
49
- export declare function createHttpHostedControlPlaneClient(options: HttpHostedControlPlaneClientOptions): HostedControlPlaneClient;
50
- export interface OneJobRunnerConfig {
51
- runnerId: string;
52
- capabilities: string[];
53
- leaseId: string;
54
- ttlMs: number;
55
- heartbeatIntervalMs: number;
56
- /** Bounded wait window for polling before giving up with no lease. Default 30_000. */
57
- timeoutMs?: number;
58
- /** Delay between poll attempts. Default 2_000. */
59
- pollIntervalMs?: number;
60
- /** default () => Date.now() */
61
- now?: () => number;
62
- /** default a real setTimeout-backed delay */
63
- sleep?: (ms: number) => Promise<void>;
64
- }
65
- export interface OneJobRunnerOutcome {
66
- leased: boolean;
67
- runner: RegisteredRunner;
68
- attempts: number;
69
- jobId?: string;
70
- lease?: RunnerLease;
71
- job?: HostedJobSummary;
72
- trace: string;
73
- }
74
- /** Registers once, then polls for a compatible job within a bounded wait
75
- * window, leasing at most one job. Exits (returns) cleanly — leased or not —
76
- * once a lease is acquired or the window elapses; never loops past that. */
77
- export declare function runOneJobRunner(client: HostedControlPlaneClient, config: OneJobRunnerConfig): Promise<OneJobRunnerOutcome>;
78
- //# sourceMappingURL=runner-client.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"runner-client.d.ts","sourceRoot":"","sources":["../../src/hosted/runner-client.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CACzB;AAYD,MAAM,MAAM,kBAAkB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,gBAAgB,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC;AAE9F,MAAM,WAAW,wBAAwB;IACvC,cAAc,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC/F,YAAY,CAAC,KAAK,EAAE;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,mBAAmB,EAAE,MAAM,CAAC;KAC7B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACjC;AAED;qEACqE;AACrE,MAAM,MAAM,yBAAyB,GAAG,CACtC,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KACxE,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,CAAC,CAAC;AAExE,MAAM,WAAW,mCAAmC;IAClD,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,SAAS,CAAC,EAAE,yBAAyB,CAAC;CACvC;AAED;+EAC+E;AAC/E,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,mCAAmC,GAC3C,wBAAwB,CA8B1B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,EAAE,MAAM,CAAC;IAC5B,sFAAsF;IACtF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,gBAAgB,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,GAAG,CAAC,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;4EAE4E;AAC5E,wBAAsB,eAAe,CACnC,MAAM,EAAE,wBAAwB,EAChC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,mBAAmB,CAAC,CA4C9B"}
@@ -1,82 +0,0 @@
1
- /** Linear-time trim (no regex) — baseUrl is caller-supplied library input, so a
2
- * `/\/+$/`-style pattern would flag as a polynomial-regex-on-untrusted-input risk. */
3
- function trimTrailingSlashes(value) {
4
- let end = value.length;
5
- while (end > 0 && value[end - 1] === '/') {
6
- end -= 1;
7
- }
8
- return value.slice(0, end);
9
- }
10
- /** Production client: talks to a running createHostedControlPlaneServer over
11
- * HTTP. Throws on transport/HTTP failure — the caller decides how to react. */
12
- export function createHttpHostedControlPlaneClient(options) {
13
- const baseUrl = trimTrailingSlashes(options.baseUrl);
14
- const fetchImpl = options.fetchImpl ?? globalThis.fetch;
15
- async function post(path, body) {
16
- const res = await fetchImpl(`${baseUrl}${path}`, {
17
- method: 'POST',
18
- headers: { 'content-type': 'application/json' },
19
- body: JSON.stringify(body),
20
- });
21
- const data = await res.json();
22
- if (!res.ok) {
23
- const message = data && typeof data === 'object' && 'error' in data ? String(data.error) : res.status;
24
- throw new Error(`hosted control plane ${path} failed: ${message}`);
25
- }
26
- return data;
27
- }
28
- return {
29
- async registerRunner(input) {
30
- const data = (await post('/runners', input));
31
- return data.runner;
32
- },
33
- async pollForLease(input) {
34
- const { runnerId, ...body } = input;
35
- const data = (await post(`/runners/${encodeURIComponent(runnerId)}/poll`, body));
36
- return data;
37
- },
38
- };
39
- }
40
- /** Registers once, then polls for a compatible job within a bounded wait
41
- * window, leasing at most one job. Exits (returns) cleanly — leased or not —
42
- * once a lease is acquired or the window elapses; never loops past that. */
43
- export async function runOneJobRunner(client, config) {
44
- const timeoutMs = config.timeoutMs ?? 30_000;
45
- const pollIntervalMs = config.pollIntervalMs ?? 2_000;
46
- const now = config.now ?? (() => Date.now());
47
- const sleep = config.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
48
- const runner = await client.registerRunner({ runnerId: config.runnerId, capabilities: config.capabilities });
49
- const deadline = now() + timeoutMs;
50
- let attempts = 0;
51
- for (;;) {
52
- attempts += 1;
53
- const poll = await client.pollForLease({
54
- runnerId: config.runnerId,
55
- capabilities: config.capabilities,
56
- leaseId: config.leaseId,
57
- ttlMs: config.ttlMs,
58
- heartbeatIntervalMs: config.heartbeatIntervalMs,
59
- });
60
- if (poll.ok) {
61
- return {
62
- leased: true,
63
- runner,
64
- attempts,
65
- jobId: poll.job.jobId,
66
- lease: poll.lease,
67
- job: poll.job,
68
- trace: `registered ${config.runnerId} -> leased ${poll.job.jobId} after ${attempts} poll(s)`,
69
- };
70
- }
71
- if (now() >= deadline) {
72
- return {
73
- leased: false,
74
- runner,
75
- attempts,
76
- trace: `registered ${config.runnerId} -> no compatible job within ${timeoutMs}ms (${attempts} poll(s))`,
77
- };
78
- }
79
- await sleep(pollIntervalMs);
80
- }
81
- }
82
- //# sourceMappingURL=runner-client.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"runner-client.js","sourceRoot":"","sources":["../../src/hosted/runner-client.ts"],"names":[],"mappings":"AAoBA;sFACsF;AACtF,SAAS,mBAAmB,CAAC,KAAa;IACxC,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;IACvB,OAAO,GAAG,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;QACzC,GAAG,IAAI,CAAC,CAAC;IACX,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC7B,CAAC;AA8BD;+EAC+E;AAC/E,MAAM,UAAU,kCAAkC,CAChD,OAA4C;IAE5C,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,MAAM,SAAS,GAA8B,OAAO,CAAC,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC;IAEnF,KAAK,UAAU,IAAI,CAAC,IAAY,EAAE,IAAa;QAC7C,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,OAAO,GAAG,IAAI,EAAE,EAAE;YAC/C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,OAAO,GACX,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAE,IAA2B,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;YAChH,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,YAAY,OAAO,EAAE,CAAC,CAAC;QACrE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,KAAK,CAAC,cAAc,CAAC,KAAK;YACxB,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAiC,CAAC;YAC7E,OAAO,IAAI,CAAC,MAAM,CAAC;QACrB,CAAC;QACD,KAAK,CAAC,YAAY,CAAC,KAAK;YACtB,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;YACpC,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,YAAY,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAuB,CAAC;YACvG,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC;AACJ,CAAC;AA4BD;;4EAE4E;AAC5E,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAgC,EAChC,MAA0B;IAE1B,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC;IAC7C,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,KAAK,CAAC;IACtD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAExG,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;IAE7G,MAAM,QAAQ,GAAG,GAAG,EAAE,GAAG,SAAS,CAAC;IACnC,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,SAAS,CAAC;QACR,QAAQ,IAAI,CAAC,CAAC;QACd,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC;YACrC,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;SAChD,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACZ,OAAO;gBACL,MAAM,EAAE,IAAI;gBACZ,MAAM;gBACN,QAAQ;gBACR,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK;gBACrB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,KAAK,EAAE,cAAc,MAAM,CAAC,QAAQ,cAAc,IAAI,CAAC,GAAG,CAAC,KAAK,UAAU,QAAQ,UAAU;aAC7F,CAAC;QACJ,CAAC;QAED,IAAI,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC;YACtB,OAAO;gBACL,MAAM,EAAE,KAAK;gBACb,MAAM;gBACN,QAAQ;gBACR,KAAK,EAAE,cAAc,MAAM,CAAC,QAAQ,gCAAgC,SAAS,OAAO,QAAQ,WAAW;aACxG,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,CAAC,cAAc,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC"}