@usepipr/runtime 0.4.3 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +8 -5
  3. package/dist/{commands-DA0Ij4Di.d.mts → commands-BHXh7P28.d.mts} +2 -2
  4. package/dist/{commands-DA0Ij4Di.d.mts.map → commands-BHXh7P28.d.mts.map} +1 -1
  5. package/dist/{commands-B9qNW4pk.mjs → commands-GWHklzvq.mjs} +1612 -466
  6. package/dist/commands-GWHklzvq.mjs.map +1 -0
  7. package/dist/index.d.mts +17 -4
  8. package/dist/index.d.mts.map +1 -1
  9. package/dist/index.mjs +117 -15
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/internal/action-result.d.mts +4 -2
  12. package/dist/internal/action-result.d.mts.map +1 -1
  13. package/dist/internal/action-result.mjs +28 -12
  14. package/dist/internal/action-result.mjs.map +1 -1
  15. package/dist/internal/docs.d.mts +1 -1
  16. package/dist/internal/docs.d.mts.map +1 -1
  17. package/dist/internal/docs.mjs +1 -1
  18. package/dist/internal/pipr-result.d.mts +24 -0
  19. package/dist/internal/pipr-result.d.mts.map +1 -0
  20. package/dist/internal/pipr-result.mjs +126 -0
  21. package/dist/internal/pipr-result.mjs.map +1 -0
  22. package/dist/internal/testing.d.mts +12 -11
  23. package/dist/internal/testing.d.mts.map +1 -1
  24. package/dist/internal/testing.mjs +1 -1
  25. package/dist/main-comment-envelope-DFirHYhW.mjs +69 -0
  26. package/dist/main-comment-envelope-DFirHYhW.mjs.map +1 -0
  27. package/dist/{official-github-workflow-Bjlu-FL3.mjs → official-github-workflow-B3yeaCgq.mjs} +421 -114
  28. package/dist/official-github-workflow-B3yeaCgq.mjs.map +1 -0
  29. package/dist/pi/runtime-tools-extension.d.mts.map +1 -1
  30. package/dist/pi/runtime-tools-extension.mjs +128 -2
  31. package/dist/pi/runtime-tools-extension.mjs.map +1 -1
  32. package/dist/{recipes-w72EpAOi.d.mts → recipes-C1kxJCgQ.d.mts} +2 -1
  33. package/dist/recipes-C1kxJCgQ.d.mts.map +1 -0
  34. package/dist/runtime-tools-core-BF8rSeNS.mjs +476 -0
  35. package/dist/runtime-tools-core-BF8rSeNS.mjs.map +1 -0
  36. package/dist/{types-BAis_Lwm.d.mts → types-w22wbdo9.d.mts} +72 -19
  37. package/dist/types-w22wbdo9.d.mts.map +1 -0
  38. package/package.json +16 -8
  39. package/dist/commands-B9qNW4pk.mjs.map +0 -1
  40. package/dist/official-github-workflow-Bjlu-FL3.mjs.map +0 -1
  41. package/dist/recipes-w72EpAOi.d.mts.map +0 -1
  42. package/dist/runtime-tools-core-D8_WsbL_.mjs +0 -179
  43. package/dist/runtime-tools-core-D8_WsbL_.mjs.map +0 -1
  44. package/dist/types-BAis_Lwm.d.mts.map +0 -1
package/dist/index.d.mts CHANGED
@@ -1,10 +1,23 @@
1
- import { a as runInspectCommand, c as OfficialInitAdapter, i as runInitCommand, l as supportedOfficialInitAdapters, n as runHostRunCommand, o as runLocalReviewCommand, s as runValidateCommand, t as runDryRunCommand } from "./commands-DA0Ij4Di.mjs";
2
- import { a as OfficialInitRecipeFile, i as OfficialInitRecipe, n as listOfficialInitRecipes, r as supportedOfficialInitRecipes, t as OfficialInitRecipeId } from "./recipes-w72EpAOi.mjs";
3
- import { A as RuntimeSettings, C as ChangeRequestEventContext, D as PlatformInfo, E as PiprConfig, O as ProviderConfig, S as PublicationResult, T as DiffManifest, _ as RuntimeLogRecord, a as HostRunCommandResult, c as LocalReviewCommandOptions, i as HostRunCommandOptions, k as RepositoryRef, l as LocalReviewCommandResult, n as DryRunCommandResult, o as InitCommandOptions, s as InspectCommandResult, t as DryRunCommandOptions, u as RuntimeCommandOptions, v as RuntimeLogSink, w as ChangeRequestRef, x as PublicationError } from "./types-BAis_Lwm.mjs";
1
+ import { a as runInspectCommand, c as OfficialInitAdapter, i as runInitCommand, l as supportedOfficialInitAdapters, n as runHostRunCommand, o as runLocalReviewCommand, s as runValidateCommand, t as runDryRunCommand } from "./commands-BHXh7P28.mjs";
2
+ import { a as OfficialInitRecipeFile, i as OfficialInitRecipe, n as listOfficialInitRecipes, r as supportedOfficialInitRecipes, t as OfficialInitRecipeId } from "./recipes-C1kxJCgQ.mjs";
3
+ import { A as RuntimeSettings, C as ChangeRequestEventContext, D as PlatformInfo, E as PiprConfig, O as ProviderConfig, S as PublicationResult, T as DiffManifest, _ as RuntimeLogRecord, a as HostRunCommandResult, c as LocalReviewCommandOptions, i as HostRunCommandOptions, k as RepositoryRef, l as LocalReviewCommandResult, n as DryRunCommandResult, o as InitCommandOptions, s as InspectCommandResult, t as DryRunCommandOptions, u as RuntimeCommandOptions, v as RuntimeLogSink, w as ChangeRequestRef, x as PublicationError } from "./types-w22wbdo9.mjs";
4
+ import { PiprResult } from "@usepipr/sdk";
4
5
  //#region src/hosts/webhook.d.ts
5
6
  type WebhookHost = "gitlab" | "azure-devops" | "bitbucket";
6
7
  //#endregion
7
8
  //#region src/host-run/webhook-server.d.ts
9
+ type WebhookDeliveryStatus = {
10
+ id: string;
11
+ host: string;
12
+ status: string;
13
+ attempts: number;
14
+ resultKind?: string;
15
+ runId?: string;
16
+ updatedAt: string;
17
+ result?: PiprResult;
18
+ resultOmittedReason?: "size-limit" | "retention" | "invalid";
19
+ };
20
+ declare function readWebhookDeliveryStatus(databasePath: string, limit?: number): WebhookDeliveryStatus[];
8
21
  declare function runWebhookServer(options: {
9
22
  host: WebhookHost;
10
23
  workspace: string;
@@ -17,5 +30,5 @@ declare function runWebhookServer(options: {
17
30
  env?: NodeJS.ProcessEnv;
18
31
  }): Promise<void>;
19
32
  //#endregion
20
- export { type ChangeRequestEventContext, type ChangeRequestRef, type DiffManifest, type DryRunCommandOptions, type DryRunCommandResult, type HostRunCommandOptions, type HostRunCommandResult, type InitCommandOptions, type InspectCommandResult, type LocalReviewCommandOptions, type LocalReviewCommandResult, type OfficialInitAdapter, type OfficialInitRecipe, type OfficialInitRecipeFile, type OfficialInitRecipeId, type PiprConfig, type PlatformInfo, type ProviderConfig, PublicationError, type PublicationResult, type RepositoryRef, type RuntimeCommandOptions, type RuntimeLogRecord, type RuntimeLogSink, type RuntimeSettings, type WebhookHost, listOfficialInitRecipes, runDryRunCommand, runHostRunCommand, runInitCommand, runInspectCommand, runLocalReviewCommand, runValidateCommand, runWebhookServer, supportedOfficialInitAdapters, supportedOfficialInitRecipes };
33
+ export { type ChangeRequestEventContext, type ChangeRequestRef, type DiffManifest, type DryRunCommandOptions, type DryRunCommandResult, type HostRunCommandOptions, type HostRunCommandResult, type InitCommandOptions, type InspectCommandResult, type LocalReviewCommandOptions, type LocalReviewCommandResult, type OfficialInitAdapter, type OfficialInitRecipe, type OfficialInitRecipeFile, type OfficialInitRecipeId, type PiprConfig, type PlatformInfo, type ProviderConfig, PublicationError, type PublicationResult, type RepositoryRef, type RuntimeCommandOptions, type RuntimeLogRecord, type RuntimeLogSink, type RuntimeSettings, type WebhookDeliveryStatus, type WebhookHost, listOfficialInitRecipes, readWebhookDeliveryStatus, runDryRunCommand, runHostRunCommand, runInitCommand, runInspectCommand, runLocalReviewCommand, runValidateCommand, runWebhookServer, supportedOfficialInitAdapters, supportedOfficialInitRecipes };
21
34
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/hosts/webhook.ts","../src/host-run/webhook-server.ts"],"mappings":";;;;KAIY;;;iBCwIU,iBAAiB;EACrC,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAM,OAAO;IACX"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/hosts/webhook.ts","../src/host-run/webhook-server.ts"],"mappings":";;;;;KAIY;;;KC0BA;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS;EACT;;iBAGc,0BACd,sBACA,iBACC;iBA4LmB,iBAAiB;EACrC,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAM,OAAO;IACX"}
package/dist/index.mjs CHANGED
@@ -1,9 +1,12 @@
1
- import { a as runInspectCommand, c as createGitLabClient, d as PublicationError, f as createAzureDevOpsClient, h as supportedOfficialInitAdapters, i as runInitCommand, n as runHostRunCommand, o as runLocalReviewCommand, p as azureOrganizationFromUrl, s as runValidateCommand, t as runDryRunCommand, u as createBitbucketClient } from "./commands-B9qNW4pk.mjs";
2
- import { n as listOfficialInitRecipes, o as supportedOfficialInitRecipes } from "./official-github-workflow-Bjlu-FL3.mjs";
1
+ import { a as runInspectCommand, c as createGitLabClient, d as createAzureDevOpsClient, f as azureOrganizationFromUrl, h as supportedOfficialInitAdapters, i as runInitCommand, n as runHostRunCommand, o as runLocalReviewCommand, p as PublicationError, s as runValidateCommand, t as runDryRunCommand, u as createBitbucketClient } from "./commands-GWHklzvq.mjs";
2
+ import { n as listOfficialInitRecipes, o as supportedOfficialInitRecipes } from "./official-github-workflow-B3yeaCgq.mjs";
3
+ import { toPiprErrorResult, toPiprResult } from "./internal/pipr-result.mjs";
3
4
  import { mkdir, mkdtemp, rm } from "node:fs/promises";
4
5
  import path from "node:path";
5
6
  import { z } from "zod";
7
+ import { parsePiprResult } from "@usepipr/sdk";
6
8
  import os from "node:os";
9
+ import { chmodSync, existsSync } from "node:fs";
7
10
  import { Database } from "bun:sqlite";
8
11
  import { createHmac, timingSafeEqual } from "node:crypto";
9
12
  //#region src/hosts/webhook-shared.ts
@@ -174,6 +177,51 @@ function createCodeHostWebhookProtocol(host) {
174
177
  //#endregion
175
178
  //#region src/host-run/webhook-server.ts
176
179
  const MAX_WEBHOOK_PAYLOAD_BYTES = 2 * 1024 * 1024;
180
+ function readWebhookDeliveryStatus(databasePath, limit = 20) {
181
+ if (!Number.isInteger(limit) || limit < 1 || limit > 200) throw new Error("--limit must be an integer from 1 to 200");
182
+ if (!existsSync(databasePath)) throw new Error(`Webhook database not found: ${databasePath}`);
183
+ const database = new Database(databasePath, {
184
+ readonly: true,
185
+ strict: true
186
+ });
187
+ try {
188
+ const columns = new Set(database.query("PRAGMA table_info(webhook_deliveries)").all().map((column) => column.name));
189
+ if (columns.size === 0) throw new Error("Webhook database is missing webhook_deliveries");
190
+ const field = (name, alias) => columns.has(name) ? `${name} AS ${alias}` : `NULL AS ${alias}`;
191
+ return database.query(`SELECT id, host, status, attempts, ${field("result_kind", "resultKind")}, ${field("run_id", "runId")}, ${field("result_json", "resultJson")}, ${field("result_omitted_reason", "omittedReason")}, updated_at AS updatedAt FROM webhook_deliveries ORDER BY updated_at DESC, id DESC LIMIT ?`).all(limit).map((row) => deliveryStatus(row));
192
+ } finally {
193
+ database.close();
194
+ }
195
+ }
196
+ function deliveryStatus(row) {
197
+ const common = {
198
+ id: row.id,
199
+ host: row.host,
200
+ status: row.status,
201
+ attempts: row.attempts,
202
+ ...row.resultKind ? { resultKind: row.resultKind } : {},
203
+ ...row.runId ? { runId: row.runId } : {},
204
+ updatedAt: row.updatedAt
205
+ };
206
+ if (!row.resultJson) {
207
+ const reason = row.omittedReason;
208
+ return reason === "size-limit" || reason === "retention" ? {
209
+ ...common,
210
+ resultOmittedReason: reason
211
+ } : common;
212
+ }
213
+ try {
214
+ return {
215
+ ...common,
216
+ result: parsePiprResult(JSON.parse(row.resultJson))
217
+ };
218
+ } catch {
219
+ return {
220
+ ...common,
221
+ resultOmittedReason: "invalid"
222
+ };
223
+ }
224
+ }
177
225
  function createWebhookIngress(options) {
178
226
  const maxPayloadBytes = options.maxPayloadBytes ?? MAX_WEBHOOK_PAYLOAD_BYTES;
179
227
  const protocol = createCodeHostWebhookProtocol(options.host);
@@ -213,12 +261,14 @@ async function processNextWebhookDelivery(options) {
213
261
  const delivery = options.store.next();
214
262
  if (!delivery) return false;
215
263
  try {
216
- await options.run(delivery);
217
- options.store.complete(delivery.id);
264
+ const result = await options.run(delivery);
265
+ options.store.complete(delivery.id, toPiprResult({
266
+ source: "host",
267
+ result
268
+ }));
218
269
  options.log?.(`webhook delivery completed: ${delivery.id.slice(0, 200)}`);
219
270
  } catch (error) {
220
- const message = error instanceof Error ? error.message : String(error);
221
- options.store.fail(delivery.id, message.slice(0, 1e3));
271
+ options.store.fail(delivery.id, toPiprErrorResult(error));
222
272
  options.log?.(`webhook delivery failed and was retained for retry or inspection: ${delivery.id.slice(0, 200)}`);
223
273
  }
224
274
  return true;
@@ -302,6 +352,8 @@ var SqliteWebhookDeliveryStore = class {
302
352
  maxPendingDeliveries;
303
353
  maxRetainedPayloadBytes;
304
354
  maxRetainedDeliveries;
355
+ maxResultBytes;
356
+ maxRetainedResultBytes;
305
357
  constructor(databasePath, options = {}) {
306
358
  this.database = new Database(databasePath, {
307
359
  create: true,
@@ -310,7 +362,11 @@ var SqliteWebhookDeliveryStore = class {
310
362
  this.maxPendingDeliveries = options.maxPendingDeliveries ?? 1e3;
311
363
  this.maxRetainedPayloadBytes = options.maxRetainedPayloadBytes ?? 32 * 1024 * 1024;
312
364
  this.maxRetainedDeliveries = options.maxRetainedDeliveries ?? 1e4;
365
+ this.maxResultBytes = options.maxResultBytes ?? 512 * 1024;
366
+ this.maxRetainedResultBytes = options.maxRetainedResultBytes ?? 32 * 1024 * 1024;
367
+ secureWebhookDatabaseFiles(databasePath);
313
368
  this.database.exec("PRAGMA journal_mode = WAL");
369
+ secureWebhookDatabaseFiles(databasePath);
314
370
  this.database.transaction(() => {
315
371
  this.database.exec(`
316
372
  CREATE TABLE IF NOT EXISTS webhook_deliveries (
@@ -321,12 +377,27 @@ var SqliteWebhookDeliveryStore = class {
321
377
  status TEXT NOT NULL,
322
378
  attempts INTEGER NOT NULL DEFAULT 0,
323
379
  error TEXT,
380
+ run_id TEXT,
381
+ result_kind TEXT,
382
+ result_json TEXT,
383
+ result_omitted_reason TEXT,
324
384
  created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
325
385
  updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
326
386
  );
327
387
  `);
328
- if (!this.database.query("PRAGMA table_info(webhook_deliveries)").all().some((column) => column.name === "event_name")) this.database.exec("ALTER TABLE webhook_deliveries ADD COLUMN event_name TEXT");
329
- this.database.query("UPDATE webhook_deliveries SET status = CASE WHEN attempts < 3 THEN 'pending' ELSE 'failed' END, payload = CASE WHEN attempts < 3 THEN payload ELSE NULL END, error = CASE WHEN attempts < 3 THEN error ELSE COALESCE(error, 'delivery interrupted during final attempt') END, updated_at = CURRENT_TIMESTAMP WHERE status = 'processing'").run();
388
+ const columns = this.database.query("PRAGMA table_info(webhook_deliveries)").all();
389
+ if (!columns.some((column) => column.name === "event_name")) this.database.exec("ALTER TABLE webhook_deliveries ADD COLUMN event_name TEXT");
390
+ for (const column of [
391
+ "run_id",
392
+ "result_kind",
393
+ "result_json",
394
+ "result_omitted_reason"
395
+ ]) if (!columns.some((candidate) => candidate.name === column)) this.database.exec(`ALTER TABLE webhook_deliveries ADD COLUMN ${column} TEXT`);
396
+ this.database.query("UPDATE webhook_deliveries SET status = 'pending', updated_at = CURRENT_TIMESTAMP WHERE status = 'processing' AND attempts < 3").run();
397
+ const interrupted = toPiprErrorResult(void 0);
398
+ const stored = this.storedResult(interrupted);
399
+ this.database.query("UPDATE webhook_deliveries SET status = 'failed', payload = NULL, error = ?, run_id = ?, result_kind = ?, result_json = ?, result_omitted_reason = ?, updated_at = CURRENT_TIMESTAMP WHERE status = 'processing' AND attempts >= 3").run(interrupted.message, stored.runId, interrupted.kind, stored.json, stored.omittedReason);
400
+ this.enforceResultRetention();
330
401
  })();
331
402
  }
332
403
  enqueue(delivery) {
@@ -343,7 +414,7 @@ var SqliteWebhookDeliveryStore = class {
343
414
  return this.database.transaction(() => {
344
415
  const row = this.database.query("SELECT id, host, payload, event_name AS eventName FROM webhook_deliveries WHERE status = 'pending' AND attempts < 3 ORDER BY created_at, id LIMIT 1").get();
345
416
  if (!row) return void 0;
346
- this.database.query("UPDATE webhook_deliveries SET status = 'processing', attempts = attempts + 1, updated_at = CURRENT_TIMESTAMP WHERE id = ?").run(row.id);
417
+ this.database.query("UPDATE webhook_deliveries SET status = 'processing', attempts = attempts + 1, run_id = NULL, result_kind = NULL, result_json = NULL, result_omitted_reason = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?").run(row.id);
347
418
  return row.eventName ? row : {
348
419
  id: row.id,
349
420
  host: row.host,
@@ -351,15 +422,20 @@ var SqliteWebhookDeliveryStore = class {
351
422
  };
352
423
  })();
353
424
  }
354
- complete(id) {
425
+ complete(id, result) {
355
426
  this.database.transaction(() => {
356
- this.database.query("UPDATE webhook_deliveries SET status = 'completed', payload = NULL, error = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?").run(id);
427
+ const stored = this.storedResult(result);
428
+ this.database.query("UPDATE webhook_deliveries SET status = 'completed', payload = NULL, error = NULL, run_id = ?, result_kind = ?, result_json = ?, result_omitted_reason = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?").run(stored.runId, result.kind, stored.json, stored.omittedReason, id);
429
+ this.enforceResultRetention();
357
430
  this.pruneTerminalDeliveries();
358
431
  })();
359
432
  }
360
- fail(id, error) {
433
+ fail(id, result) {
361
434
  this.database.transaction(() => {
362
- this.database.query("UPDATE webhook_deliveries SET status = CASE WHEN attempts < 3 THEN 'pending' ELSE 'failed' END, payload = CASE WHEN attempts < 3 THEN payload ELSE NULL END, error = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?").run(error, id);
435
+ const stored = this.storedResult(result);
436
+ const message = "message" in result ? result.message : "Pipr failed; see logs for details.";
437
+ this.database.query("UPDATE webhook_deliveries SET status = CASE WHEN attempts < 3 THEN 'pending' ELSE 'failed' END, payload = CASE WHEN attempts < 3 THEN payload ELSE NULL END, error = ?, run_id = ?, result_kind = ?, result_json = ?, result_omitted_reason = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?").run(message, stored.runId, result.kind, stored.json, stored.omittedReason, id);
438
+ this.enforceResultRetention();
363
439
  this.pruneTerminalDeliveries();
364
440
  })();
365
441
  }
@@ -369,14 +445,40 @@ var SqliteWebhookDeliveryStore = class {
369
445
  pruneTerminalDeliveries() {
370
446
  this.database.query("DELETE FROM webhook_deliveries WHERE id IN (SELECT id FROM webhook_deliveries WHERE status IN ('completed', 'failed') ORDER BY updated_at DESC, id DESC LIMIT -1 OFFSET ?)").run(this.maxRetainedDeliveries);
371
447
  }
448
+ storedResult(result) {
449
+ const json = JSON.stringify(result);
450
+ return {
451
+ runId: "run" in result ? result.run.id : null,
452
+ json: Buffer.byteLength(json) <= this.maxResultBytes ? json : null,
453
+ omittedReason: Buffer.byteLength(json) <= this.maxResultBytes ? null : "size-limit"
454
+ };
455
+ }
456
+ enforceResultRetention() {
457
+ let retained = this.database.query("SELECT COALESCE(SUM(length(CAST(result_json AS BLOB))), 0) AS bytes FROM webhook_deliveries").get()?.bytes ?? 0;
458
+ if (retained <= this.maxRetainedResultBytes) return;
459
+ const rows = this.database.query("SELECT id, length(CAST(result_json AS BLOB)) AS bytes FROM webhook_deliveries WHERE result_json IS NOT NULL ORDER BY updated_at, id").all();
460
+ for (const row of rows) {
461
+ if (retained <= this.maxRetainedResultBytes) break;
462
+ this.database.query("UPDATE webhook_deliveries SET result_json = NULL, result_omitted_reason = 'retention' WHERE id = ?").run(row.id);
463
+ retained -= row.bytes;
464
+ }
465
+ }
372
466
  };
467
+ function secureWebhookDatabaseFiles(databasePath) {
468
+ if (databasePath === ":memory:") return;
469
+ for (const candidate of [
470
+ databasePath,
471
+ `${databasePath}-wal`,
472
+ `${databasePath}-shm`
473
+ ]) if (existsSync(candidate)) chmodSync(candidate, 384);
474
+ }
373
475
  async function runWebhookDelivery(delivery, options, runHostRun = runHostRunCommand) {
374
476
  const directory = await mkdtemp(path.join(os.tmpdir(), "pipr-webhook-"));
375
477
  const eventPath = path.join(directory, "event.json");
376
478
  const protocol = createCodeHostWebhookProtocol(delivery.host);
377
479
  try {
378
480
  await Bun.write(eventPath, delivery.payload);
379
- await runHostRun({
481
+ return await runHostRun({
380
482
  rootDir: options.workspace,
381
483
  configDir: options.configDir,
382
484
  host: delivery.host,
@@ -406,6 +508,6 @@ const consoleRuntimeLogSink = {
406
508
  }
407
509
  };
408
510
  //#endregion
409
- export { PublicationError, listOfficialInitRecipes, runDryRunCommand, runHostRunCommand, runInitCommand, runInspectCommand, runLocalReviewCommand, runValidateCommand, runWebhookServer, supportedOfficialInitAdapters, supportedOfficialInitRecipes };
511
+ export { PublicationError, listOfficialInitRecipes, readWebhookDeliveryStatus, runDryRunCommand, runHostRunCommand, runInitCommand, runInspectCommand, runLocalReviewCommand, runValidateCommand, runWebhookServer, supportedOfficialInitAdapters, supportedOfficialInitRecipes };
410
512
 
411
513
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["eventSchema","isExpectedRepository"],"sources":["../src/hosts/webhook-shared.ts","../src/hosts/azure-devops/webhook.ts","../src/hosts/bitbucket/webhook.ts","../src/hosts/gitlab/webhook.ts","../src/hosts/webhook.ts","../src/host-run/webhook-server.ts"],"sourcesContent":["import { timingSafeEqual } from \"node:crypto\";\n\nexport function parseWebhookJson(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nexport function webhookSecretsEqual(supplied: string | null, expected: string): boolean {\n if (!supplied) return false;\n const expectedBytes = Buffer.from(expected);\n const suppliedBytes = Buffer.from(supplied);\n return (\n expectedBytes.length === suppliedBytes.length && timingSafeEqual(expectedBytes, suppliedBytes)\n );\n}\n","import { z } from \"zod\";\nimport type { CodeHostWebhookProtocol } from \"../webhook.js\";\nimport { parseWebhookJson, webhookSecretsEqual } from \"../webhook-shared.js\";\nimport { createAzureDevOpsClient } from \"./client.js\";\nimport { azureOrganizationFromUrl } from \"./coordinates.js\";\n\nconst eventSchema = z.looseObject({\n id: z.string().min(1),\n eventType: z.enum([\n \"git.pullrequest.created\",\n \"git.pullrequest.updated\",\n \"ms.vss-code.git-pullrequest-comment-event\",\n ]),\n subscriptionId: z.string().min(1),\n notificationId: z.union([z.number(), z.string()]).transform(String).optional(),\n resource: z.looseObject({\n repository: z\n .looseObject({ id: z.string().min(1), project: z.looseObject({ id: z.string().min(1) }) })\n .optional(),\n pullRequest: z\n .looseObject({\n repository: z.looseObject({\n id: z.string().min(1),\n project: z.looseObject({ id: z.string().min(1) }),\n }),\n })\n .optional(),\n }),\n resourceContainers: z.looseObject({\n account: z.looseObject({ baseUrl: z.string().url() }),\n project: z.looseObject({ id: z.string().min(1) }),\n }),\n});\n\ntype ExpectedRepository = {\n organization: string;\n projectId: string;\n repositoryId: string;\n subscriptionId: string;\n};\n\nexport function createAzureDevOpsWebhookProtocol(): CodeHostWebhookProtocol {\n return {\n host: \"azure-devops\",\n async resolveExpectedRepository(env, repository) {\n const client = createAzureDevOpsClient(env);\n const resolved = await client.getRepository(repository);\n const subscriptionId = env.PIPR_AZURE_SUBSCRIPTION_ID;\n if (!subscriptionId)\n throw new Error(\"PIPR_AZURE_SUBSCRIPTION_ID is required for Azure DevOps webhooks\");\n return {\n organization: client.organization,\n projectId: resolved.projectId,\n repositoryId: resolved.id,\n subscriptionId,\n };\n },\n verifySecret(headers, secret, _payload) {\n return webhookSecretsEqual(\n headers.get(\"X-Pipr-Webhook-Secret\") ?? basicPassword(headers.get(\"Authorization\")),\n secret,\n );\n },\n matchesExpectedRepository(payload, expected) {\n if (!isExpectedRepository(expected)) return false;\n const event = eventSchema.safeParse(parseWebhookJson(payload));\n if (!event.success) return false;\n const repository =\n event.data.resource.repository ?? event.data.resource.pullRequest?.repository;\n return (\n azureOrganizationFromUrl(event.data.resourceContainers.account.baseUrl) ===\n expected.organization &&\n event.data.resourceContainers.project.id === expected.projectId &&\n repository?.project.id === expected.projectId &&\n repository.id === expected.repositoryId &&\n event.data.subscriptionId === expected.subscriptionId\n );\n },\n deliveryId(_headers, payload) {\n const event = eventSchema.safeParse(parseWebhookJson(payload));\n return event.success\n ? `azure-devops:${event.data.subscriptionId}:${event.data.id}:${event.data.notificationId ?? \"initial\"}`\n : undefined;\n },\n };\n}\n\nfunction isExpectedRepository(value: unknown): value is ExpectedRepository {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"organization\" in value &&\n \"projectId\" in value &&\n \"repositoryId\" in value &&\n \"subscriptionId\" in value\n );\n}\n\nfunction basicPassword(value: string | null): string | null {\n if (!value?.startsWith(\"Basic \")) return null;\n try {\n return Buffer.from(value.slice(6), \"base64\").toString().split(\":\").slice(1).join(\":\") || null;\n } catch {\n return null;\n }\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { z } from \"zod\";\nimport type { CodeHostWebhookProtocol } from \"../webhook.js\";\nimport { parseWebhookJson } from \"../webhook-shared.js\";\nimport { createBitbucketClient } from \"./client.js\";\n\nconst eventSchema = z.looseObject({\n repository: z.looseObject({ uuid: z.string().min(1), full_name: z.string().min(1) }),\n pullrequest: z.looseObject({ id: z.number().int().positive() }),\n});\n\nexport function createBitbucketWebhookProtocol(): CodeHostWebhookProtocol {\n return {\n host: \"bitbucket\",\n async resolveExpectedRepository(env, expectedRepository) {\n const client = createBitbucketClient(env);\n if (expectedRepository !== client.repository)\n throw new Error(\n `Bitbucket --repository '${expectedRepository}' does not match BITBUCKET_REPO_SLUG '${client.repository}'`,\n );\n const repository = await client.getRepository();\n return { uuid: repository.uuid, fullName: repository.fullName };\n },\n verifySecret(headers, secret, payload) {\n return verifyBitbucketSignature(payload, headers.get(\"X-Hub-Signature\"), secret);\n },\n matchesExpectedRepository(payload, expected) {\n const event = eventSchema.safeParse(parseWebhookJson(payload));\n return (\n event.success &&\n typeof expected === \"object\" &&\n expected !== null &&\n \"uuid\" in expected &&\n \"fullName\" in expected &&\n event.data.repository.uuid === expected.uuid &&\n event.data.repository.full_name === expected.fullName\n );\n },\n deliveryId(headers, payload) {\n const request = headers.get(\"X-Request-UUID\");\n const hook = headers.get(\"X-Hook-UUID\");\n if (!request || !hook) return undefined;\n const digest = createHmac(\"sha256\", hook).update(payload).digest(\"hex\").slice(0, 16);\n return `bitbucket:${hook}:${request}:${digest}`;\n },\n eventName(headers) {\n return headers.get(\"X-Event-Key\") ?? undefined;\n },\n runtimeEnv(eventName) {\n return eventName ? { BITBUCKET_EVENT_KEY: eventName } : {};\n },\n };\n}\n\nfunction verifyBitbucketSignature(payload: string, signature: string | null, secret: string) {\n if (!signature?.startsWith(\"sha256=\")) return false;\n const supplied = Buffer.from(signature.slice(7), \"hex\");\n const expected = createHmac(\"sha256\", secret).update(payload).digest();\n return supplied.length === expected.length && timingSafeEqual(supplied, expected);\n}\n","import { z } from \"zod\";\nimport type { CodeHostWebhookProtocol } from \"../webhook.js\";\nimport { parseWebhookJson, webhookSecretsEqual } from \"../webhook-shared.js\";\nimport { createGitLabClient } from \"./client.js\";\n\nconst projectSchema = z.looseObject({\n project: z.looseObject({\n id: z.union([z.number(), z.string()]).transform(String),\n path_with_namespace: z.string().min(1),\n }),\n});\n\ntype ExpectedRepository = { id: string; path: string };\n\nexport function createGitLabWebhookProtocol(): CodeHostWebhookProtocol {\n return {\n host: \"gitlab\",\n resolveExpectedRepository: (env, repository) => createGitLabClient(env).getProject(repository),\n verifySecret(headers, secret, _payload) {\n return webhookSecretsEqual(headers.get(\"X-Gitlab-Token\"), secret);\n },\n matchesExpectedRepository(payload, expected) {\n if (!isExpectedRepository(expected)) return false;\n const event = projectSchema.safeParse(parseWebhookJson(payload));\n return (\n event.success &&\n event.data.project.id === expected.id &&\n event.data.project.path_with_namespace === expected.path\n );\n },\n deliveryId(headers) {\n const id = headers.get(\"X-Gitlab-Webhook-UUID\") ?? headers.get(\"X-Gitlab-Event-UUID\");\n return id ? `gitlab:${id}` : undefined;\n },\n };\n}\n\nfunction isExpectedRepository(value: unknown): value is ExpectedRepository {\n return typeof value === \"object\" && value !== null && \"id\" in value && \"path\" in value;\n}\n","import { createAzureDevOpsWebhookProtocol } from \"./azure-devops/webhook.js\";\nimport { createBitbucketWebhookProtocol } from \"./bitbucket/webhook.js\";\nimport { createGitLabWebhookProtocol } from \"./gitlab/webhook.js\";\n\nexport type WebhookHost = \"gitlab\" | \"azure-devops\" | \"bitbucket\";\n\nexport type CodeHostWebhookProtocol = {\n host: WebhookHost;\n resolveExpectedRepository(env: NodeJS.ProcessEnv, repository: string): Promise<unknown>;\n verifySecret(headers: Headers, secret: string, payload: string): boolean;\n matchesExpectedRepository(payload: string, expected: unknown): boolean;\n deliveryId(headers: Headers, payload: string): string | undefined;\n eventName?(headers: Headers): string | undefined;\n runtimeEnv?(eventName: string | undefined): NodeJS.ProcessEnv;\n};\n\nexport function createCodeHostWebhookProtocol(host: WebhookHost): CodeHostWebhookProtocol {\n if (host === \"gitlab\") return createGitLabWebhookProtocol();\n if (host === \"azure-devops\") return createAzureDevOpsWebhookProtocol();\n if (host === \"bitbucket\") return createBitbucketWebhookProtocol();\n throw new Error(`Unsupported webhook host: ${host}`);\n}\n","import { Database } from \"bun:sqlite\";\nimport { mkdir, mkdtemp, rm } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { createCodeHostWebhookProtocol, type WebhookHost } from \"../hosts/webhook.js\";\nimport type { RuntimeLogSink } from \"../shared/logging.js\";\nimport { runHostRunCommand } from \"./commands.js\";\n\nconst MAX_WEBHOOK_PAYLOAD_BYTES = 2 * 1024 * 1024;\n\nexport type { WebhookHost } from \"../hosts/webhook.js\";\n\nexport type WebhookDelivery = {\n id: string;\n host: WebhookHost;\n payload: string;\n eventName?: string;\n};\n\nexport type WebhookDeliveryStore = {\n enqueue(delivery: WebhookDelivery): \"created\" | \"duplicate\" | \"full\";\n next(): WebhookDelivery | undefined;\n complete(id: string): void;\n fail(id: string, error: string): void;\n};\n\nexport function createWebhookIngress(options: {\n host: WebhookHost;\n secret: string;\n expectedRepository: unknown;\n store: WebhookDeliveryStore;\n maxPayloadBytes?: number;\n}) {\n const maxPayloadBytes = options.maxPayloadBytes ?? MAX_WEBHOOK_PAYLOAD_BYTES;\n const protocol = createCodeHostWebhookProtocol(options.host);\n return async (request: Request): Promise<Response> => {\n const healthResponse = webhookHealthResponse(request);\n if (healthResponse) return healthResponse;\n const authenticated = await readAuthenticatedWebhookPayload(\n request,\n maxPayloadBytes,\n options.secret,\n protocol.verifySecret,\n );\n if (authenticated instanceof Response) return authenticated;\n const payload = authenticated;\n if (!protocol.matchesExpectedRepository(payload, options.expectedRepository)) {\n return new Response(\"Repository mismatch\", { status: 403 });\n }\n const id = protocol.deliveryId(request.headers, payload);\n if (!id) {\n return new Response(\"Missing delivery id\", { status: 400 });\n }\n const result = options.store.enqueue({\n id,\n host: options.host,\n payload,\n eventName: protocol.eventName?.(request.headers),\n });\n if (result === \"full\") {\n return new Response(\"Queue Full\", { status: 503, headers: { \"Retry-After\": \"30\" } });\n }\n return new Response(result === \"created\" ? \"Accepted\" : \"Duplicate\", {\n status: result === \"created\" ? 202 : 200,\n });\n };\n}\n\nfunction webhookHealthResponse(request: Request): Response | undefined {\n if (request.method !== \"GET\" && request.method !== \"HEAD\") return undefined;\n return new URL(request.url).pathname === \"/healthz\" ? new Response(\"OK\") : undefined;\n}\n\nasync function readAuthenticatedWebhookPayload(\n request: Request,\n maxPayloadBytes: number,\n secret: string,\n verify: (headers: Headers, secret: string, payload: string) => boolean,\n): Promise<string | Response> {\n if (request.method !== \"POST\") return new Response(\"Method Not Allowed\", { status: 405 });\n const payload = await request.text();\n if (new TextEncoder().encode(payload).byteLength > maxPayloadBytes)\n return new Response(\"Payload Too Large\", { status: 413 });\n return verify(request.headers, secret, payload)\n ? payload\n : new Response(\"Unauthorized\", { status: 401 });\n}\n\nexport async function processNextWebhookDelivery(options: {\n store: WebhookDeliveryStore;\n run: (delivery: WebhookDelivery) => Promise<unknown>;\n log?: (message: string) => void;\n}): Promise<boolean> {\n const delivery = options.store.next();\n if (!delivery) return false;\n try {\n await options.run(delivery);\n options.store.complete(delivery.id);\n options.log?.(`webhook delivery completed: ${delivery.id.slice(0, 200)}`);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n options.store.fail(delivery.id, message.slice(0, 1_000));\n options.log?.(\n `webhook delivery failed and was retained for retry or inspection: ${delivery.id.slice(0, 200)}`,\n );\n }\n return true;\n}\n\nexport function createWebhookQueueProcessor(options: {\n store: WebhookDeliveryStore;\n run: (delivery: WebhookDelivery) => Promise<unknown>;\n log?: (message: string) => void;\n}) {\n let active: Promise<void> | undefined;\n let stopped = false;\n\n return {\n run(): Promise<void> {\n if (stopped) return Promise.resolve();\n active ??= (async () => {\n try {\n while (await processNextWebhookDelivery(options)) {\n // Deliveries run serially because each checkout mutates the shared workspace.\n }\n } catch {\n options.log?.(\"webhook queue processing failed; the next interval will retry\");\n }\n })().finally(() => {\n active = undefined;\n });\n return active;\n },\n async stop(): Promise<void> {\n stopped = true;\n await active;\n },\n };\n}\n\nexport async function runWebhookServer(options: {\n host: WebhookHost;\n workspace: string;\n configDir: string;\n databasePath: string;\n expectedRepository: string;\n secret: string;\n port: number;\n hostname?: string;\n env?: NodeJS.ProcessEnv;\n}): Promise<void> {\n await mkdir(path.dirname(path.resolve(options.databasePath)), { recursive: true });\n const env = { ...process.env, ...options.env };\n const protocol = createCodeHostWebhookProtocol(options.host);\n const expectedRepository = await protocol.resolveExpectedRepository(\n env,\n options.expectedRepository,\n );\n const store = new SqliteWebhookDeliveryStore(options.databasePath);\n const ingress = createWebhookIngress({\n host: options.host,\n secret: options.secret,\n expectedRepository,\n store,\n });\n const processor = createWebhookQueueProcessor({\n store,\n run: (delivery) => runWebhookDelivery(delivery, { ...options, env }),\n log: console.error,\n });\n const server = Bun.serve({\n hostname: options.hostname ?? \"127.0.0.1\",\n port: options.port,\n maxRequestBodySize: MAX_WEBHOOK_PAYLOAD_BYTES,\n fetch: ingress,\n });\n const interval = setInterval(() => void processor.run(), 250);\n const shutdown = Promise.withResolvers<void>();\n let stopping: Promise<void> | undefined;\n const stop = () => {\n stopping ??= (async () => {\n clearInterval(interval);\n server.stop();\n await processor.stop();\n store.close();\n })();\n void stopping.then(shutdown.resolve, shutdown.reject);\n };\n process.once(\"SIGINT\", stop);\n process.once(\"SIGTERM\", stop);\n try {\n console.error(`pipr webhook server listening on ${server.hostname}:${server.port}`);\n await processor.run();\n await shutdown.promise;\n } finally {\n process.off(\"SIGINT\", stop);\n process.off(\"SIGTERM\", stop);\n }\n}\n\nexport class SqliteWebhookDeliveryStore implements WebhookDeliveryStore {\n private readonly database: Database;\n private readonly maxPendingDeliveries: number;\n private readonly maxRetainedPayloadBytes: number;\n private readonly maxRetainedDeliveries: number;\n\n constructor(\n databasePath: string,\n options: {\n maxPendingDeliveries?: number;\n maxRetainedPayloadBytes?: number;\n maxRetainedDeliveries?: number;\n } = {},\n ) {\n this.database = new Database(databasePath, { create: true, strict: true });\n this.maxPendingDeliveries = options.maxPendingDeliveries ?? 1_000;\n this.maxRetainedPayloadBytes = options.maxRetainedPayloadBytes ?? 32 * 1024 * 1024;\n this.maxRetainedDeliveries = options.maxRetainedDeliveries ?? 10_000;\n this.database.exec(\"PRAGMA journal_mode = WAL\");\n this.database.transaction(() => {\n this.database.exec(`\n CREATE TABLE IF NOT EXISTS webhook_deliveries (\n id TEXT PRIMARY KEY,\n host TEXT NOT NULL,\n payload TEXT,\n event_name TEXT,\n status TEXT NOT NULL,\n attempts INTEGER NOT NULL DEFAULT 0,\n error TEXT,\n created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,\n updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP\n );\n `);\n const columns = this.database\n .query<{ name: string }, []>(\"PRAGMA table_info(webhook_deliveries)\")\n .all();\n if (!columns.some((column) => column.name === \"event_name\")) {\n this.database.exec(\"ALTER TABLE webhook_deliveries ADD COLUMN event_name TEXT\");\n }\n this.database\n .query(\n \"UPDATE webhook_deliveries SET status = CASE WHEN attempts < 3 THEN 'pending' ELSE 'failed' END, payload = CASE WHEN attempts < 3 THEN payload ELSE NULL END, error = CASE WHEN attempts < 3 THEN error ELSE COALESCE(error, 'delivery interrupted during final attempt') END, updated_at = CURRENT_TIMESTAMP WHERE status = 'processing'\",\n )\n .run();\n })();\n }\n\n enqueue(delivery: WebhookDelivery): \"created\" | \"duplicate\" | \"full\" {\n return this.database.transaction(() => {\n const existing = this.database\n .query<{ id: string }, [string]>(\"SELECT id FROM webhook_deliveries WHERE id = ?\")\n .get(delivery.id);\n if (existing) return \"duplicate\";\n const retained = this.database\n .query<{ count: number; bytes: number }, []>(\n \"SELECT COALESCE(SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END), 0) AS count, COALESCE(SUM(length(CAST(payload AS BLOB))), 0) AS bytes FROM webhook_deliveries WHERE payload IS NOT NULL\",\n )\n .get();\n const payloadBytes = Buffer.byteLength(delivery.payload);\n if (\n !retained ||\n retained.count >= this.maxPendingDeliveries ||\n retained.bytes + payloadBytes > this.maxRetainedPayloadBytes\n ) {\n return \"full\";\n }\n this.database\n .query(\n \"INSERT INTO webhook_deliveries (id, host, payload, event_name, status) VALUES (?, ?, ?, ?, 'pending')\",\n )\n .run(delivery.id, delivery.host, delivery.payload, delivery.eventName ?? null);\n return \"created\";\n })();\n }\n\n next(): WebhookDelivery | undefined {\n return this.database.transaction(() => {\n const row = this.database\n .query<{ id: string; host: WebhookHost; payload: string; eventName?: string }, []>(\n \"SELECT id, host, payload, event_name AS eventName FROM webhook_deliveries WHERE status = 'pending' AND attempts < 3 ORDER BY created_at, id LIMIT 1\",\n )\n .get();\n if (!row) return undefined;\n this.database\n .query(\n \"UPDATE webhook_deliveries SET status = 'processing', attempts = attempts + 1, updated_at = CURRENT_TIMESTAMP WHERE id = ?\",\n )\n .run(row.id);\n return row.eventName ? row : { id: row.id, host: row.host, payload: row.payload };\n })();\n }\n\n complete(id: string): void {\n this.database.transaction(() => {\n this.database\n .query(\n \"UPDATE webhook_deliveries SET status = 'completed', payload = NULL, error = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?\",\n )\n .run(id);\n this.pruneTerminalDeliveries();\n })();\n }\n\n fail(id: string, error: string): void {\n this.database.transaction(() => {\n this.database\n .query(\n \"UPDATE webhook_deliveries SET status = CASE WHEN attempts < 3 THEN 'pending' ELSE 'failed' END, payload = CASE WHEN attempts < 3 THEN payload ELSE NULL END, error = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?\",\n )\n .run(error, id);\n this.pruneTerminalDeliveries();\n })();\n }\n\n close(): void {\n this.database.close();\n }\n\n private pruneTerminalDeliveries(): void {\n // SQLite uses LIMIT -1 to leave the result unbounded after skipping the retained rows.\n this.database\n .query(\n \"DELETE FROM webhook_deliveries WHERE id IN (SELECT id FROM webhook_deliveries WHERE status IN ('completed', 'failed') ORDER BY updated_at DESC, id DESC LIMIT -1 OFFSET ?)\",\n )\n .run(this.maxRetainedDeliveries);\n }\n}\n\nexport async function runWebhookDelivery(\n delivery: WebhookDelivery,\n options: {\n workspace: string;\n configDir: string;\n env?: NodeJS.ProcessEnv;\n },\n runHostRun: typeof runHostRunCommand = runHostRunCommand,\n): Promise<void> {\n const directory = await mkdtemp(path.join(os.tmpdir(), \"pipr-webhook-\"));\n const eventPath = path.join(directory, \"event.json\");\n const protocol = createCodeHostWebhookProtocol(delivery.host);\n try {\n await Bun.write(eventPath, delivery.payload);\n await runHostRun({\n rootDir: options.workspace,\n configDir: options.configDir,\n host: delivery.host,\n eventPath,\n env: {\n ...process.env,\n ...options.env,\n PIPR_CODE_HOST: delivery.host,\n ...protocol.runtimeEnv?.(delivery.eventName),\n },\n dryRun: false,\n logSink: consoleRuntimeLogSink,\n });\n } finally {\n await rm(directory, { recursive: true, force: true });\n }\n}\n\nconst consoleRuntimeLogSink: RuntimeLogSink = {\n log(record) {\n console.log(JSON.stringify(record));\n },\n async group(_name, run) {\n return await run();\n },\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["eventSchema","isExpectedRepository"],"sources":["../src/hosts/webhook-shared.ts","../src/hosts/azure-devops/webhook.ts","../src/hosts/bitbucket/webhook.ts","../src/hosts/gitlab/webhook.ts","../src/hosts/webhook.ts","../src/host-run/webhook-server.ts"],"sourcesContent":["import { timingSafeEqual } from \"node:crypto\";\n\nexport function parseWebhookJson(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nexport function webhookSecretsEqual(supplied: string | null, expected: string): boolean {\n if (!supplied) return false;\n const expectedBytes = Buffer.from(expected);\n const suppliedBytes = Buffer.from(supplied);\n return (\n expectedBytes.length === suppliedBytes.length && timingSafeEqual(expectedBytes, suppliedBytes)\n );\n}\n","import { z } from \"zod\";\nimport type { CodeHostWebhookProtocol } from \"../webhook.js\";\nimport { parseWebhookJson, webhookSecretsEqual } from \"../webhook-shared.js\";\nimport { createAzureDevOpsClient } from \"./client.js\";\nimport { azureOrganizationFromUrl } from \"./coordinates.js\";\n\nconst eventSchema = z.looseObject({\n id: z.string().min(1),\n eventType: z.enum([\n \"git.pullrequest.created\",\n \"git.pullrequest.updated\",\n \"ms.vss-code.git-pullrequest-comment-event\",\n ]),\n subscriptionId: z.string().min(1),\n notificationId: z.union([z.number(), z.string()]).transform(String).optional(),\n resource: z.looseObject({\n repository: z\n .looseObject({ id: z.string().min(1), project: z.looseObject({ id: z.string().min(1) }) })\n .optional(),\n pullRequest: z\n .looseObject({\n repository: z.looseObject({\n id: z.string().min(1),\n project: z.looseObject({ id: z.string().min(1) }),\n }),\n })\n .optional(),\n }),\n resourceContainers: z.looseObject({\n account: z.looseObject({ baseUrl: z.string().url() }),\n project: z.looseObject({ id: z.string().min(1) }),\n }),\n});\n\ntype ExpectedRepository = {\n organization: string;\n projectId: string;\n repositoryId: string;\n subscriptionId: string;\n};\n\nexport function createAzureDevOpsWebhookProtocol(): CodeHostWebhookProtocol {\n return {\n host: \"azure-devops\",\n async resolveExpectedRepository(env, repository) {\n const client = createAzureDevOpsClient(env);\n const resolved = await client.getRepository(repository);\n const subscriptionId = env.PIPR_AZURE_SUBSCRIPTION_ID;\n if (!subscriptionId)\n throw new Error(\"PIPR_AZURE_SUBSCRIPTION_ID is required for Azure DevOps webhooks\");\n return {\n organization: client.organization,\n projectId: resolved.projectId,\n repositoryId: resolved.id,\n subscriptionId,\n };\n },\n verifySecret(headers, secret, _payload) {\n return webhookSecretsEqual(\n headers.get(\"X-Pipr-Webhook-Secret\") ?? basicPassword(headers.get(\"Authorization\")),\n secret,\n );\n },\n matchesExpectedRepository(payload, expected) {\n if (!isExpectedRepository(expected)) return false;\n const event = eventSchema.safeParse(parseWebhookJson(payload));\n if (!event.success) return false;\n const repository =\n event.data.resource.repository ?? event.data.resource.pullRequest?.repository;\n return (\n azureOrganizationFromUrl(event.data.resourceContainers.account.baseUrl) ===\n expected.organization &&\n event.data.resourceContainers.project.id === expected.projectId &&\n repository?.project.id === expected.projectId &&\n repository.id === expected.repositoryId &&\n event.data.subscriptionId === expected.subscriptionId\n );\n },\n deliveryId(_headers, payload) {\n const event = eventSchema.safeParse(parseWebhookJson(payload));\n return event.success\n ? `azure-devops:${event.data.subscriptionId}:${event.data.id}:${event.data.notificationId ?? \"initial\"}`\n : undefined;\n },\n };\n}\n\nfunction isExpectedRepository(value: unknown): value is ExpectedRepository {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"organization\" in value &&\n \"projectId\" in value &&\n \"repositoryId\" in value &&\n \"subscriptionId\" in value\n );\n}\n\nfunction basicPassword(value: string | null): string | null {\n if (!value?.startsWith(\"Basic \")) return null;\n try {\n return Buffer.from(value.slice(6), \"base64\").toString().split(\":\").slice(1).join(\":\") || null;\n } catch {\n return null;\n }\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { z } from \"zod\";\nimport type { CodeHostWebhookProtocol } from \"../webhook.js\";\nimport { parseWebhookJson } from \"../webhook-shared.js\";\nimport { createBitbucketClient } from \"./client.js\";\n\nconst eventSchema = z.looseObject({\n repository: z.looseObject({ uuid: z.string().min(1), full_name: z.string().min(1) }),\n pullrequest: z.looseObject({ id: z.number().int().positive() }),\n});\n\nexport function createBitbucketWebhookProtocol(): CodeHostWebhookProtocol {\n return {\n host: \"bitbucket\",\n async resolveExpectedRepository(env, expectedRepository) {\n const client = createBitbucketClient(env);\n if (expectedRepository !== client.repository)\n throw new Error(\n `Bitbucket --repository '${expectedRepository}' does not match BITBUCKET_REPO_SLUG '${client.repository}'`,\n );\n const repository = await client.getRepository();\n return { uuid: repository.uuid, fullName: repository.fullName };\n },\n verifySecret(headers, secret, payload) {\n return verifyBitbucketSignature(payload, headers.get(\"X-Hub-Signature\"), secret);\n },\n matchesExpectedRepository(payload, expected) {\n const event = eventSchema.safeParse(parseWebhookJson(payload));\n return (\n event.success &&\n typeof expected === \"object\" &&\n expected !== null &&\n \"uuid\" in expected &&\n \"fullName\" in expected &&\n event.data.repository.uuid === expected.uuid &&\n event.data.repository.full_name === expected.fullName\n );\n },\n deliveryId(headers, payload) {\n const request = headers.get(\"X-Request-UUID\");\n const hook = headers.get(\"X-Hook-UUID\");\n if (!request || !hook) return undefined;\n const digest = createHmac(\"sha256\", hook).update(payload).digest(\"hex\").slice(0, 16);\n return `bitbucket:${hook}:${request}:${digest}`;\n },\n eventName(headers) {\n return headers.get(\"X-Event-Key\") ?? undefined;\n },\n runtimeEnv(eventName) {\n return eventName ? { BITBUCKET_EVENT_KEY: eventName } : {};\n },\n };\n}\n\nfunction verifyBitbucketSignature(payload: string, signature: string | null, secret: string) {\n if (!signature?.startsWith(\"sha256=\")) return false;\n const supplied = Buffer.from(signature.slice(7), \"hex\");\n const expected = createHmac(\"sha256\", secret).update(payload).digest();\n return supplied.length === expected.length && timingSafeEqual(supplied, expected);\n}\n","import { z } from \"zod\";\nimport type { CodeHostWebhookProtocol } from \"../webhook.js\";\nimport { parseWebhookJson, webhookSecretsEqual } from \"../webhook-shared.js\";\nimport { createGitLabClient } from \"./client.js\";\n\nconst projectSchema = z.looseObject({\n project: z.looseObject({\n id: z.union([z.number(), z.string()]).transform(String),\n path_with_namespace: z.string().min(1),\n }),\n});\n\ntype ExpectedRepository = { id: string; path: string };\n\nexport function createGitLabWebhookProtocol(): CodeHostWebhookProtocol {\n return {\n host: \"gitlab\",\n resolveExpectedRepository: (env, repository) => createGitLabClient(env).getProject(repository),\n verifySecret(headers, secret, _payload) {\n return webhookSecretsEqual(headers.get(\"X-Gitlab-Token\"), secret);\n },\n matchesExpectedRepository(payload, expected) {\n if (!isExpectedRepository(expected)) return false;\n const event = projectSchema.safeParse(parseWebhookJson(payload));\n return (\n event.success &&\n event.data.project.id === expected.id &&\n event.data.project.path_with_namespace === expected.path\n );\n },\n deliveryId(headers) {\n const id = headers.get(\"X-Gitlab-Webhook-UUID\") ?? headers.get(\"X-Gitlab-Event-UUID\");\n return id ? `gitlab:${id}` : undefined;\n },\n };\n}\n\nfunction isExpectedRepository(value: unknown): value is ExpectedRepository {\n return typeof value === \"object\" && value !== null && \"id\" in value && \"path\" in value;\n}\n","import { createAzureDevOpsWebhookProtocol } from \"./azure-devops/webhook.js\";\nimport { createBitbucketWebhookProtocol } from \"./bitbucket/webhook.js\";\nimport { createGitLabWebhookProtocol } from \"./gitlab/webhook.js\";\n\nexport type WebhookHost = \"gitlab\" | \"azure-devops\" | \"bitbucket\";\n\nexport type CodeHostWebhookProtocol = {\n host: WebhookHost;\n resolveExpectedRepository(env: NodeJS.ProcessEnv, repository: string): Promise<unknown>;\n verifySecret(headers: Headers, secret: string, payload: string): boolean;\n matchesExpectedRepository(payload: string, expected: unknown): boolean;\n deliveryId(headers: Headers, payload: string): string | undefined;\n eventName?(headers: Headers): string | undefined;\n runtimeEnv?(eventName: string | undefined): NodeJS.ProcessEnv;\n};\n\nexport function createCodeHostWebhookProtocol(host: WebhookHost): CodeHostWebhookProtocol {\n if (host === \"gitlab\") return createGitLabWebhookProtocol();\n if (host === \"azure-devops\") return createAzureDevOpsWebhookProtocol();\n if (host === \"bitbucket\") return createBitbucketWebhookProtocol();\n throw new Error(`Unsupported webhook host: ${host}`);\n}\n","import { Database } from \"bun:sqlite\";\nimport { chmodSync, existsSync } from \"node:fs\";\nimport { mkdir, mkdtemp, rm } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { type PiprResult, parsePiprResult } from \"@usepipr/sdk\";\nimport { createCodeHostWebhookProtocol, type WebhookHost } from \"../hosts/webhook.js\";\nimport { toPiprErrorResult, toPiprResult } from \"../internal/pipr-result.js\";\nimport type { RuntimeLogSink } from \"../shared/logging.js\";\nimport { runHostRunCommand } from \"./commands.js\";\nimport type { HostRunCommandResult } from \"./types.js\";\n\nconst MAX_WEBHOOK_PAYLOAD_BYTES = 2 * 1024 * 1024;\n\nexport type { WebhookHost } from \"../hosts/webhook.js\";\n\nexport type WebhookDelivery = {\n id: string;\n host: WebhookHost;\n payload: string;\n eventName?: string;\n};\n\nexport type WebhookDeliveryStore = {\n enqueue(delivery: WebhookDelivery): \"created\" | \"duplicate\" | \"full\";\n next(): WebhookDelivery | undefined;\n complete(id: string, result: PiprResult): void;\n fail(id: string, result: PiprResult): void;\n};\n\nexport type WebhookDeliveryStatus = {\n id: string;\n host: string;\n status: string;\n attempts: number;\n resultKind?: string;\n runId?: string;\n updatedAt: string;\n result?: PiprResult;\n resultOmittedReason?: \"size-limit\" | \"retention\" | \"invalid\";\n};\n\nexport function readWebhookDeliveryStatus(\n databasePath: string,\n limit = 20,\n): WebhookDeliveryStatus[] {\n if (!Number.isInteger(limit) || limit < 1 || limit > 200) {\n throw new Error(\"--limit must be an integer from 1 to 200\");\n }\n if (!existsSync(databasePath)) {\n throw new Error(`Webhook database not found: ${databasePath}`);\n }\n const database = new Database(databasePath, { readonly: true, strict: true });\n try {\n const columns = new Set(\n database\n .query<{ name: string }, []>(\"PRAGMA table_info(webhook_deliveries)\")\n .all()\n .map((column) => column.name),\n );\n if (columns.size === 0) throw new Error(\"Webhook database is missing webhook_deliveries\");\n const field = (name: string, alias: string) =>\n columns.has(name) ? `${name} AS ${alias}` : `NULL AS ${alias}`;\n const rows = database\n .query<\n {\n id: string;\n host: string;\n status: string;\n attempts: number;\n resultKind: string | null;\n runId: string | null;\n resultJson: string | null;\n omittedReason: string | null;\n updatedAt: string;\n },\n [number]\n >(\n `SELECT id, host, status, attempts, ${field(\"result_kind\", \"resultKind\")}, ${field(\"run_id\", \"runId\")}, ${field(\"result_json\", \"resultJson\")}, ${field(\"result_omitted_reason\", \"omittedReason\")}, updated_at AS updatedAt FROM webhook_deliveries ORDER BY updated_at DESC, id DESC LIMIT ?`,\n )\n .all(limit);\n return rows.map((row) => deliveryStatus(row));\n } finally {\n database.close();\n }\n}\n\nfunction deliveryStatus(row: {\n id: string;\n host: string;\n status: string;\n attempts: number;\n resultKind: string | null;\n runId: string | null;\n resultJson: string | null;\n omittedReason: string | null;\n updatedAt: string;\n}): WebhookDeliveryStatus {\n const common = {\n id: row.id,\n host: row.host,\n status: row.status,\n attempts: row.attempts,\n ...(row.resultKind ? { resultKind: row.resultKind } : {}),\n ...(row.runId ? { runId: row.runId } : {}),\n updatedAt: row.updatedAt,\n };\n if (!row.resultJson) {\n const reason = row.omittedReason;\n return reason === \"size-limit\" || reason === \"retention\"\n ? { ...common, resultOmittedReason: reason }\n : common;\n }\n try {\n return { ...common, result: parsePiprResult(JSON.parse(row.resultJson)) };\n } catch {\n return { ...common, resultOmittedReason: \"invalid\" };\n }\n}\n\nexport function createWebhookIngress(options: {\n host: WebhookHost;\n secret: string;\n expectedRepository: unknown;\n store: WebhookDeliveryStore;\n maxPayloadBytes?: number;\n}) {\n const maxPayloadBytes = options.maxPayloadBytes ?? MAX_WEBHOOK_PAYLOAD_BYTES;\n const protocol = createCodeHostWebhookProtocol(options.host);\n return async (request: Request): Promise<Response> => {\n const healthResponse = webhookHealthResponse(request);\n if (healthResponse) return healthResponse;\n const authenticated = await readAuthenticatedWebhookPayload(\n request,\n maxPayloadBytes,\n options.secret,\n protocol.verifySecret,\n );\n if (authenticated instanceof Response) return authenticated;\n const payload = authenticated;\n if (!protocol.matchesExpectedRepository(payload, options.expectedRepository)) {\n return new Response(\"Repository mismatch\", { status: 403 });\n }\n const id = protocol.deliveryId(request.headers, payload);\n if (!id) {\n return new Response(\"Missing delivery id\", { status: 400 });\n }\n const result = options.store.enqueue({\n id,\n host: options.host,\n payload,\n eventName: protocol.eventName?.(request.headers),\n });\n if (result === \"full\") {\n return new Response(\"Queue Full\", { status: 503, headers: { \"Retry-After\": \"30\" } });\n }\n return new Response(result === \"created\" ? \"Accepted\" : \"Duplicate\", {\n status: result === \"created\" ? 202 : 200,\n });\n };\n}\n\nfunction webhookHealthResponse(request: Request): Response | undefined {\n if (request.method !== \"GET\" && request.method !== \"HEAD\") return undefined;\n return new URL(request.url).pathname === \"/healthz\" ? new Response(\"OK\") : undefined;\n}\n\nasync function readAuthenticatedWebhookPayload(\n request: Request,\n maxPayloadBytes: number,\n secret: string,\n verify: (headers: Headers, secret: string, payload: string) => boolean,\n): Promise<string | Response> {\n if (request.method !== \"POST\") return new Response(\"Method Not Allowed\", { status: 405 });\n const payload = await request.text();\n if (new TextEncoder().encode(payload).byteLength > maxPayloadBytes)\n return new Response(\"Payload Too Large\", { status: 413 });\n return verify(request.headers, secret, payload)\n ? payload\n : new Response(\"Unauthorized\", { status: 401 });\n}\n\nexport async function processNextWebhookDelivery(options: {\n store: WebhookDeliveryStore;\n run: (delivery: WebhookDelivery) => Promise<HostRunCommandResult>;\n log?: (message: string) => void;\n}): Promise<boolean> {\n const delivery = options.store.next();\n if (!delivery) return false;\n try {\n const result = await options.run(delivery);\n options.store.complete(delivery.id, toPiprResult({ source: \"host\", result }));\n options.log?.(`webhook delivery completed: ${delivery.id.slice(0, 200)}`);\n } catch (error) {\n options.store.fail(delivery.id, toPiprErrorResult(error));\n options.log?.(\n `webhook delivery failed and was retained for retry or inspection: ${delivery.id.slice(0, 200)}`,\n );\n }\n return true;\n}\n\nexport function createWebhookQueueProcessor(options: {\n store: WebhookDeliveryStore;\n run: (delivery: WebhookDelivery) => Promise<HostRunCommandResult>;\n log?: (message: string) => void;\n}) {\n let active: Promise<void> | undefined;\n let stopped = false;\n\n return {\n run(): Promise<void> {\n if (stopped) return Promise.resolve();\n active ??= (async () => {\n try {\n while (await processNextWebhookDelivery(options)) {\n // Deliveries run serially because each checkout mutates the shared workspace.\n }\n } catch {\n options.log?.(\"webhook queue processing failed; the next interval will retry\");\n }\n })().finally(() => {\n active = undefined;\n });\n return active;\n },\n async stop(): Promise<void> {\n stopped = true;\n await active;\n },\n };\n}\n\nexport async function runWebhookServer(options: {\n host: WebhookHost;\n workspace: string;\n configDir: string;\n databasePath: string;\n expectedRepository: string;\n secret: string;\n port: number;\n hostname?: string;\n env?: NodeJS.ProcessEnv;\n}): Promise<void> {\n await mkdir(path.dirname(path.resolve(options.databasePath)), { recursive: true });\n const env = { ...process.env, ...options.env };\n const protocol = createCodeHostWebhookProtocol(options.host);\n const expectedRepository = await protocol.resolveExpectedRepository(\n env,\n options.expectedRepository,\n );\n const store = new SqliteWebhookDeliveryStore(options.databasePath);\n const ingress = createWebhookIngress({\n host: options.host,\n secret: options.secret,\n expectedRepository,\n store,\n });\n const processor = createWebhookQueueProcessor({\n store,\n run: (delivery) => runWebhookDelivery(delivery, { ...options, env }),\n log: console.error,\n });\n const server = Bun.serve({\n hostname: options.hostname ?? \"127.0.0.1\",\n port: options.port,\n maxRequestBodySize: MAX_WEBHOOK_PAYLOAD_BYTES,\n fetch: ingress,\n });\n const interval = setInterval(() => void processor.run(), 250);\n const shutdown = Promise.withResolvers<void>();\n let stopping: Promise<void> | undefined;\n const stop = () => {\n stopping ??= (async () => {\n clearInterval(interval);\n server.stop();\n await processor.stop();\n store.close();\n })();\n void stopping.then(shutdown.resolve, shutdown.reject);\n };\n process.once(\"SIGINT\", stop);\n process.once(\"SIGTERM\", stop);\n try {\n console.error(`pipr webhook server listening on ${server.hostname}:${server.port}`);\n await processor.run();\n await shutdown.promise;\n } finally {\n process.off(\"SIGINT\", stop);\n process.off(\"SIGTERM\", stop);\n }\n}\n\nexport class SqliteWebhookDeliveryStore implements WebhookDeliveryStore {\n private readonly database: Database;\n private readonly maxPendingDeliveries: number;\n private readonly maxRetainedPayloadBytes: number;\n private readonly maxRetainedDeliveries: number;\n private readonly maxResultBytes: number;\n private readonly maxRetainedResultBytes: number;\n\n constructor(\n databasePath: string,\n options: {\n maxPendingDeliveries?: number;\n maxRetainedPayloadBytes?: number;\n maxRetainedDeliveries?: number;\n maxResultBytes?: number;\n maxRetainedResultBytes?: number;\n } = {},\n ) {\n this.database = new Database(databasePath, { create: true, strict: true });\n this.maxPendingDeliveries = options.maxPendingDeliveries ?? 1_000;\n this.maxRetainedPayloadBytes = options.maxRetainedPayloadBytes ?? 32 * 1024 * 1024;\n this.maxRetainedDeliveries = options.maxRetainedDeliveries ?? 10_000;\n this.maxResultBytes = options.maxResultBytes ?? 512 * 1024;\n this.maxRetainedResultBytes = options.maxRetainedResultBytes ?? 32 * 1024 * 1024;\n secureWebhookDatabaseFiles(databasePath);\n this.database.exec(\"PRAGMA journal_mode = WAL\");\n secureWebhookDatabaseFiles(databasePath);\n this.database.transaction(() => {\n this.database.exec(`\n CREATE TABLE IF NOT EXISTS webhook_deliveries (\n id TEXT PRIMARY KEY,\n host TEXT NOT NULL,\n payload TEXT,\n event_name TEXT,\n status TEXT NOT NULL,\n attempts INTEGER NOT NULL DEFAULT 0,\n error TEXT,\n run_id TEXT,\n result_kind TEXT,\n result_json TEXT,\n result_omitted_reason TEXT,\n created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,\n updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP\n );\n `);\n const columns = this.database\n .query<{ name: string }, []>(\"PRAGMA table_info(webhook_deliveries)\")\n .all();\n if (!columns.some((column) => column.name === \"event_name\")) {\n this.database.exec(\"ALTER TABLE webhook_deliveries ADD COLUMN event_name TEXT\");\n }\n for (const column of [\"run_id\", \"result_kind\", \"result_json\", \"result_omitted_reason\"]) {\n if (!columns.some((candidate) => candidate.name === column)) {\n this.database.exec(`ALTER TABLE webhook_deliveries ADD COLUMN ${column} TEXT`);\n }\n }\n this.database\n .query(\n \"UPDATE webhook_deliveries SET status = 'pending', updated_at = CURRENT_TIMESTAMP WHERE status = 'processing' AND attempts < 3\",\n )\n .run();\n const interrupted = toPiprErrorResult(undefined);\n const stored = this.storedResult(interrupted);\n this.database\n .query(\n \"UPDATE webhook_deliveries SET status = 'failed', payload = NULL, error = ?, run_id = ?, result_kind = ?, result_json = ?, result_omitted_reason = ?, updated_at = CURRENT_TIMESTAMP WHERE status = 'processing' AND attempts >= 3\",\n )\n .run(\n interrupted.message,\n stored.runId,\n interrupted.kind,\n stored.json,\n stored.omittedReason,\n );\n this.enforceResultRetention();\n })();\n }\n\n enqueue(delivery: WebhookDelivery): \"created\" | \"duplicate\" | \"full\" {\n return this.database.transaction(() => {\n const existing = this.database\n .query<{ id: string }, [string]>(\"SELECT id FROM webhook_deliveries WHERE id = ?\")\n .get(delivery.id);\n if (existing) return \"duplicate\";\n const retained = this.database\n .query<{ count: number; bytes: number }, []>(\n \"SELECT COALESCE(SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END), 0) AS count, COALESCE(SUM(length(CAST(payload AS BLOB))), 0) AS bytes FROM webhook_deliveries WHERE payload IS NOT NULL\",\n )\n .get();\n const payloadBytes = Buffer.byteLength(delivery.payload);\n if (\n !retained ||\n retained.count >= this.maxPendingDeliveries ||\n retained.bytes + payloadBytes > this.maxRetainedPayloadBytes\n ) {\n return \"full\";\n }\n this.database\n .query(\n \"INSERT INTO webhook_deliveries (id, host, payload, event_name, status) VALUES (?, ?, ?, ?, 'pending')\",\n )\n .run(delivery.id, delivery.host, delivery.payload, delivery.eventName ?? null);\n return \"created\";\n })();\n }\n\n next(): WebhookDelivery | undefined {\n return this.database.transaction(() => {\n const row = this.database\n .query<{ id: string; host: WebhookHost; payload: string; eventName?: string }, []>(\n \"SELECT id, host, payload, event_name AS eventName FROM webhook_deliveries WHERE status = 'pending' AND attempts < 3 ORDER BY created_at, id LIMIT 1\",\n )\n .get();\n if (!row) return undefined;\n this.database\n .query(\n \"UPDATE webhook_deliveries SET status = 'processing', attempts = attempts + 1, run_id = NULL, result_kind = NULL, result_json = NULL, result_omitted_reason = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?\",\n )\n .run(row.id);\n return row.eventName ? row : { id: row.id, host: row.host, payload: row.payload };\n })();\n }\n\n complete(id: string, result: PiprResult): void {\n this.database.transaction(() => {\n const stored = this.storedResult(result);\n this.database\n .query(\n \"UPDATE webhook_deliveries SET status = 'completed', payload = NULL, error = NULL, run_id = ?, result_kind = ?, result_json = ?, result_omitted_reason = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?\",\n )\n .run(stored.runId, result.kind, stored.json, stored.omittedReason, id);\n this.enforceResultRetention();\n this.pruneTerminalDeliveries();\n })();\n }\n\n fail(id: string, result: PiprResult): void {\n this.database.transaction(() => {\n const stored = this.storedResult(result);\n const message = \"message\" in result ? result.message : \"Pipr failed; see logs for details.\";\n this.database\n .query(\n \"UPDATE webhook_deliveries SET status = CASE WHEN attempts < 3 THEN 'pending' ELSE 'failed' END, payload = CASE WHEN attempts < 3 THEN payload ELSE NULL END, error = ?, run_id = ?, result_kind = ?, result_json = ?, result_omitted_reason = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?\",\n )\n .run(message, stored.runId, result.kind, stored.json, stored.omittedReason, id);\n this.enforceResultRetention();\n this.pruneTerminalDeliveries();\n })();\n }\n\n close(): void {\n this.database.close();\n }\n\n private pruneTerminalDeliveries(): void {\n // SQLite uses LIMIT -1 to leave the result unbounded after skipping the retained rows.\n this.database\n .query(\n \"DELETE FROM webhook_deliveries WHERE id IN (SELECT id FROM webhook_deliveries WHERE status IN ('completed', 'failed') ORDER BY updated_at DESC, id DESC LIMIT -1 OFFSET ?)\",\n )\n .run(this.maxRetainedDeliveries);\n }\n\n private storedResult(result: PiprResult): {\n runId: string | null;\n json: string | null;\n omittedReason: string | null;\n } {\n const json = JSON.stringify(result);\n return {\n runId: \"run\" in result ? result.run.id : null,\n json: Buffer.byteLength(json) <= this.maxResultBytes ? json : null,\n omittedReason: Buffer.byteLength(json) <= this.maxResultBytes ? null : \"size-limit\",\n };\n }\n\n private enforceResultRetention(): void {\n let retained =\n this.database\n .query<{ bytes: number }, []>(\n \"SELECT COALESCE(SUM(length(CAST(result_json AS BLOB))), 0) AS bytes FROM webhook_deliveries\",\n )\n .get()?.bytes ?? 0;\n if (retained <= this.maxRetainedResultBytes) return;\n const rows = this.database\n .query<{ id: string; bytes: number }, []>(\n \"SELECT id, length(CAST(result_json AS BLOB)) AS bytes FROM webhook_deliveries WHERE result_json IS NOT NULL ORDER BY updated_at, id\",\n )\n .all();\n for (const row of rows) {\n if (retained <= this.maxRetainedResultBytes) break;\n this.database\n .query(\n \"UPDATE webhook_deliveries SET result_json = NULL, result_omitted_reason = 'retention' WHERE id = ?\",\n )\n .run(row.id);\n retained -= row.bytes;\n }\n }\n}\n\nfunction secureWebhookDatabaseFiles(databasePath: string): void {\n if (databasePath === \":memory:\") return;\n for (const candidate of [databasePath, `${databasePath}-wal`, `${databasePath}-shm`]) {\n if (existsSync(candidate)) chmodSync(candidate, 0o600);\n }\n}\n\nexport async function runWebhookDelivery(\n delivery: WebhookDelivery,\n options: {\n workspace: string;\n configDir: string;\n env?: NodeJS.ProcessEnv;\n },\n runHostRun: typeof runHostRunCommand = runHostRunCommand,\n): Promise<HostRunCommandResult> {\n const directory = await mkdtemp(path.join(os.tmpdir(), \"pipr-webhook-\"));\n const eventPath = path.join(directory, \"event.json\");\n const protocol = createCodeHostWebhookProtocol(delivery.host);\n try {\n await Bun.write(eventPath, delivery.payload);\n return await runHostRun({\n rootDir: options.workspace,\n configDir: options.configDir,\n host: delivery.host,\n eventPath,\n env: {\n ...process.env,\n ...options.env,\n PIPR_CODE_HOST: delivery.host,\n ...protocol.runtimeEnv?.(delivery.eventName),\n },\n dryRun: false,\n logSink: consoleRuntimeLogSink,\n });\n } finally {\n await rm(directory, { recursive: true, force: true });\n }\n}\n\nconst consoleRuntimeLogSink: RuntimeLogSink = {\n log(record) {\n console.log(JSON.stringify(record));\n },\n async group(_name, run) {\n return await run();\n },\n};\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { a as HostRunCommandResult } from "../types-BAis_Lwm.mjs";
1
+ import { a as HostRunCommandResult, x as PublicationError } from "../types-w22wbdo9.mjs";
2
2
  //#region src/internal/action-result.d.ts
3
3
  type GitHubActionResultPresenter = {
4
4
  info(message: string): void | Promise<void>;
@@ -6,6 +6,8 @@ type GitHubActionResultPresenter = {
6
6
  setOutput(name: string, value: string): void | Promise<void>;
7
7
  };
8
8
  declare function presentGitHubActionResult(result: HostRunCommandResult, presenter: GitHubActionResultPresenter): Promise<void>;
9
+ declare function presentGitHubActionPublicationError(error: PublicationError, presenter: GitHubActionResultPresenter): Promise<void>;
10
+ declare function presentGitHubActionError(presenter: GitHubActionResultPresenter): Promise<void>;
9
11
  //#endregion
10
- export { GitHubActionResultPresenter, presentGitHubActionResult };
12
+ export { GitHubActionResultPresenter, presentGitHubActionError, presentGitHubActionPublicationError, presentGitHubActionResult };
11
13
  //# sourceMappingURL=action-result.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"action-result.d.mts","names":[],"sources":["../../src/internal/action-result.ts"],"mappings":";;KAEY;EACV,KAAK,yBAAyB;EAC9B,QAAQ,yBAAyB;EACjC,UAAU,cAAc,uBAAuB;;iBAG3B,0BACpB,QAAQ,sBACR,WAAW,8BACV"}
1
+ {"version":3,"file":"action-result.d.mts","names":[],"sources":["../../src/internal/action-result.ts"],"mappings":";;KAIY;EACV,KAAK,yBAAyB;EAC9B,QAAQ,yBAAyB;EACjC,UAAU,cAAc,uBAAuB;;iBAG3B,0BACpB,QAAQ,sBACR,WAAW,8BACV;iBA+DmB,oCACpB,OAAO,kBACP,WAAW,8BACV;iBAYmB,yBACpB,WAAW,8BACV"}
@@ -1,7 +1,9 @@
1
+ import { stripPiprMainCommentMarkers, toPiprErrorResult, toPiprResult } from "./pipr-result.mjs";
1
2
  //#region src/internal/action-result.ts
2
3
  async function presentGitHubActionResult(result, presenter) {
3
4
  if (result.kind === "ignored") {
4
5
  await presenter.info(`pipr ignored event: ${result.reason}`);
6
+ await setResultOutput(result, presenter);
5
7
  return;
6
8
  }
7
9
  await presenter.info(`pipr loaded change #${result.event.change.number} for ${result.event.repository.slug}`);
@@ -9,38 +11,52 @@ async function presentGitHubActionResult(result, presenter) {
9
11
  switch (result.kind) {
10
12
  case "dry-run":
11
13
  await presenter.info("PIPR_DRY_RUN=1; stopping before review runtime, model, or GitHub publishing calls");
12
- return;
14
+ break;
13
15
  case "command-help":
14
16
  await presenter.info(`pipr command help: ${result.reason}`);
15
17
  await presenter.setOutput("main-comment", result.body);
16
- return;
18
+ break;
17
19
  case "command-response":
18
20
  await presenter.info(`pipr command '${result.command}' published response comment (${result.publication.action})`);
19
21
  await presenter.setOutput("main-comment", result.response.body);
20
- await presenter.setOutput("publication", JSON.stringify(result.publication));
21
- return;
22
+ break;
22
23
  case "verifier":
23
24
  await presenter.info(`pipr verifier processed review comment reply with ${result.errors.length} publication error(s)`);
24
25
  await warnInlineResolutionErrors(result.errors, presenter);
25
- await presenter.setOutput("publication", JSON.stringify({ inlineResolutionErrors: result.errors }));
26
- return;
26
+ break;
27
27
  case "review":
28
28
  await presenter.info(`pipr review produced ${result.review.validated.validFindings.length} valid inline finding(s), ${result.review.validated.droppedFindings.length} dropped finding(s)`);
29
29
  await presenter.info(`pipr published main comment (${result.publication.mainComment.action}) and ${result.publication.inlineComments.posted} inline comment(s); ${result.publication.inlineComments.skipped} skipped`);
30
30
  await warnInlineResolutionErrors(result.publication.metadata.inlineResolutionErrors, presenter);
31
31
  if (result.review.repairAttempted) await presenter.info("pipr repaired reviewer JSON once before validation");
32
- await presenter.setOutput("main-comment", result.review.mainComment);
33
- await presenter.setOutput("inline-comments", JSON.stringify(result.review.inlineCommentDrafts));
34
- await presenter.setOutput("dropped-findings", JSON.stringify(result.review.validated.droppedFindings));
35
- await presenter.setOutput("publication", JSON.stringify(result.publication));
36
- return;
32
+ await presenter.setOutput("main-comment", stripPiprMainCommentMarkers(result.review.mainComment));
33
+ break;
37
34
  default:
38
35
  }
36
+ await setResultOutput(result, presenter);
37
+ }
38
+ async function presentGitHubActionPublicationError(error, presenter) {
39
+ await presenter.setOutput("result", JSON.stringify(toPiprResult({
40
+ source: "host",
41
+ result: {
42
+ kind: "publication-error",
43
+ publication: error.result
44
+ }
45
+ })));
46
+ }
47
+ async function presentGitHubActionError(presenter) {
48
+ await presenter.setOutput("result", JSON.stringify(toPiprErrorResult(void 0)));
49
+ }
50
+ async function setResultOutput(result, presenter) {
51
+ await presenter.setOutput("result", JSON.stringify(toPiprResult({
52
+ source: "host",
53
+ result
54
+ })));
39
55
  }
40
56
  async function warnInlineResolutionErrors(errors, presenter) {
41
57
  for (const error of errors) await presenter.warning(`pipr inline resolution failed: ${error}`);
42
58
  }
43
59
  //#endregion
44
- export { presentGitHubActionResult };
60
+ export { presentGitHubActionError, presentGitHubActionPublicationError, presentGitHubActionResult };
45
61
 
46
62
  //# sourceMappingURL=action-result.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"action-result.mjs","names":[],"sources":["../../src/internal/action-result.ts"],"sourcesContent":["import type { HostRunCommandResult } from \"../host-run/types.js\";\n\nexport type GitHubActionResultPresenter = {\n info(message: string): void | Promise<void>;\n warning(message: string): void | Promise<void>;\n setOutput(name: string, value: string): void | Promise<void>;\n};\n\nexport async function presentGitHubActionResult(\n result: HostRunCommandResult,\n presenter: GitHubActionResultPresenter,\n): Promise<void> {\n if (result.kind === \"ignored\") {\n await presenter.info(`pipr ignored event: ${result.reason}`);\n return;\n }\n\n await presenter.info(\n `pipr loaded change #${result.event.change.number} for ${result.event.repository.slug}`,\n );\n await presenter.info(`pipr config source: ${result.configSource}`);\n\n switch (result.kind) {\n case \"dry-run\":\n await presenter.info(\n \"PIPR_DRY_RUN=1; stopping before review runtime, model, or GitHub publishing calls\",\n );\n return;\n case \"command-help\":\n await presenter.info(`pipr command help: ${result.reason}`);\n await presenter.setOutput(\"main-comment\", result.body);\n return;\n case \"command-response\":\n await presenter.info(\n `pipr command '${result.command}' published response comment (${result.publication.action})`,\n );\n await presenter.setOutput(\"main-comment\", result.response.body);\n await presenter.setOutput(\"publication\", JSON.stringify(result.publication));\n return;\n case \"verifier\":\n await presenter.info(\n `pipr verifier processed review comment reply with ${result.errors.length} publication error(s)`,\n );\n await warnInlineResolutionErrors(result.errors, presenter);\n await presenter.setOutput(\n \"publication\",\n JSON.stringify({ inlineResolutionErrors: result.errors }),\n );\n return;\n case \"review\":\n await presenter.info(\n `pipr review produced ${result.review.validated.validFindings.length} valid inline finding(s), ` +\n `${result.review.validated.droppedFindings.length} dropped finding(s)`,\n );\n await presenter.info(\n `pipr published main comment (${result.publication.mainComment.action}) and ` +\n `${result.publication.inlineComments.posted} inline comment(s); ` +\n `${result.publication.inlineComments.skipped} skipped`,\n );\n await warnInlineResolutionErrors(\n result.publication.metadata.inlineResolutionErrors,\n presenter,\n );\n if (result.review.repairAttempted) {\n await presenter.info(\"pipr repaired reviewer JSON once before validation\");\n }\n await presenter.setOutput(\"main-comment\", result.review.mainComment);\n await presenter.setOutput(\n \"inline-comments\",\n JSON.stringify(result.review.inlineCommentDrafts),\n );\n await presenter.setOutput(\n \"dropped-findings\",\n JSON.stringify(result.review.validated.droppedFindings),\n );\n await presenter.setOutput(\"publication\", JSON.stringify(result.publication));\n return;\n default:\n result satisfies never;\n }\n}\n\nasync function warnInlineResolutionErrors(\n errors: readonly string[],\n presenter: GitHubActionResultPresenter,\n): Promise<void> {\n for (const error of errors) {\n await presenter.warning(`pipr inline resolution failed: ${error}`);\n }\n}\n"],"mappings":";AAQA,eAAsB,0BACpB,QACA,WACe;CACf,IAAI,OAAO,SAAS,WAAW;EAC7B,MAAM,UAAU,KAAK,uBAAuB,OAAO,QAAQ;EAC3D;CACF;CAEA,MAAM,UAAU,KACd,uBAAuB,OAAO,MAAM,OAAO,OAAO,OAAO,OAAO,MAAM,WAAW,MACnF;CACA,MAAM,UAAU,KAAK,uBAAuB,OAAO,cAAc;CAEjE,QAAQ,OAAO,MAAf;EACE,KAAK;GACH,MAAM,UAAU,KACd,mFACF;GACA;EACF,KAAK;GACH,MAAM,UAAU,KAAK,sBAAsB,OAAO,QAAQ;GAC1D,MAAM,UAAU,UAAU,gBAAgB,OAAO,IAAI;GACrD;EACF,KAAK;GACH,MAAM,UAAU,KACd,iBAAiB,OAAO,QAAQ,gCAAgC,OAAO,YAAY,OAAO,EAC5F;GACA,MAAM,UAAU,UAAU,gBAAgB,OAAO,SAAS,IAAI;GAC9D,MAAM,UAAU,UAAU,eAAe,KAAK,UAAU,OAAO,WAAW,CAAC;GAC3E;EACF,KAAK;GACH,MAAM,UAAU,KACd,qDAAqD,OAAO,OAAO,OAAO,sBAC5E;GACA,MAAM,2BAA2B,OAAO,QAAQ,SAAS;GACzD,MAAM,UAAU,UACd,eACA,KAAK,UAAU,EAAE,wBAAwB,OAAO,OAAO,CAAC,CAC1D;GACA;EACF,KAAK;GACH,MAAM,UAAU,KACd,wBAAwB,OAAO,OAAO,UAAU,cAAc,OAAO,4BAChE,OAAO,OAAO,UAAU,gBAAgB,OAAO,oBACtD;GACA,MAAM,UAAU,KACd,gCAAgC,OAAO,YAAY,YAAY,OAAO,QACjE,OAAO,YAAY,eAAe,OAAO,sBACzC,OAAO,YAAY,eAAe,QAAQ,SACjD;GACA,MAAM,2BACJ,OAAO,YAAY,SAAS,wBAC5B,SACF;GACA,IAAI,OAAO,OAAO,iBAChB,MAAM,UAAU,KAAK,oDAAoD;GAE3E,MAAM,UAAU,UAAU,gBAAgB,OAAO,OAAO,WAAW;GACnE,MAAM,UAAU,UACd,mBACA,KAAK,UAAU,OAAO,OAAO,mBAAmB,CAClD;GACA,MAAM,UAAU,UACd,oBACA,KAAK,UAAU,OAAO,OAAO,UAAU,eAAe,CACxD;GACA,MAAM,UAAU,UAAU,eAAe,KAAK,UAAU,OAAO,WAAW,CAAC;GAC3E;EACF;CAEF;AACF;AAEA,eAAe,2BACb,QACA,WACe;CACf,KAAK,MAAM,SAAS,QAClB,MAAM,UAAU,QAAQ,kCAAkC,OAAO;AAErE"}
1
+ {"version":3,"file":"action-result.mjs","names":[],"sources":["../../src/internal/action-result.ts"],"sourcesContent":["import type { HostRunCommandResult } from \"../host-run/types.js\";\nimport type { PublicationError } from \"../review/publication-result.js\";\nimport { stripPiprMainCommentMarkers, toPiprErrorResult, toPiprResult } from \"./pipr-result.js\";\n\nexport type GitHubActionResultPresenter = {\n info(message: string): void | Promise<void>;\n warning(message: string): void | Promise<void>;\n setOutput(name: string, value: string): void | Promise<void>;\n};\n\nexport async function presentGitHubActionResult(\n result: HostRunCommandResult,\n presenter: GitHubActionResultPresenter,\n): Promise<void> {\n if (result.kind === \"ignored\") {\n await presenter.info(`pipr ignored event: ${result.reason}`);\n await setResultOutput(result, presenter);\n return;\n }\n\n await presenter.info(\n `pipr loaded change #${result.event.change.number} for ${result.event.repository.slug}`,\n );\n await presenter.info(`pipr config source: ${result.configSource}`);\n\n switch (result.kind) {\n case \"dry-run\":\n await presenter.info(\n \"PIPR_DRY_RUN=1; stopping before review runtime, model, or GitHub publishing calls\",\n );\n break;\n case \"command-help\":\n await presenter.info(`pipr command help: ${result.reason}`);\n await presenter.setOutput(\"main-comment\", result.body);\n break;\n case \"command-response\":\n await presenter.info(\n `pipr command '${result.command}' published response comment (${result.publication.action})`,\n );\n await presenter.setOutput(\"main-comment\", result.response.body);\n break;\n case \"verifier\":\n await presenter.info(\n `pipr verifier processed review comment reply with ${result.errors.length} publication error(s)`,\n );\n await warnInlineResolutionErrors(result.errors, presenter);\n break;\n case \"review\":\n await presenter.info(\n `pipr review produced ${result.review.validated.validFindings.length} valid inline finding(s), ` +\n `${result.review.validated.droppedFindings.length} dropped finding(s)`,\n );\n await presenter.info(\n `pipr published main comment (${result.publication.mainComment.action}) and ` +\n `${result.publication.inlineComments.posted} inline comment(s); ` +\n `${result.publication.inlineComments.skipped} skipped`,\n );\n await warnInlineResolutionErrors(\n result.publication.metadata.inlineResolutionErrors,\n presenter,\n );\n if (result.review.repairAttempted) {\n await presenter.info(\"pipr repaired reviewer JSON once before validation\");\n }\n await presenter.setOutput(\n \"main-comment\",\n stripPiprMainCommentMarkers(result.review.mainComment),\n );\n break;\n default:\n result satisfies never;\n }\n\n await setResultOutput(result, presenter);\n}\n\nexport async function presentGitHubActionPublicationError(\n error: PublicationError,\n presenter: GitHubActionResultPresenter,\n): Promise<void> {\n await presenter.setOutput(\n \"result\",\n JSON.stringify(\n toPiprResult({\n source: \"host\",\n result: { kind: \"publication-error\", publication: error.result },\n }),\n ),\n );\n}\n\nexport async function presentGitHubActionError(\n presenter: GitHubActionResultPresenter,\n): Promise<void> {\n await presenter.setOutput(\"result\", JSON.stringify(toPiprErrorResult(undefined)));\n}\n\nasync function setResultOutput(\n result: HostRunCommandResult,\n presenter: GitHubActionResultPresenter,\n): Promise<void> {\n await presenter.setOutput(\"result\", JSON.stringify(toPiprResult({ source: \"host\", result })));\n}\n\nasync function warnInlineResolutionErrors(\n errors: readonly string[],\n presenter: GitHubActionResultPresenter,\n): Promise<void> {\n for (const error of errors) {\n await presenter.warning(`pipr inline resolution failed: ${error}`);\n }\n}\n"],"mappings":";;AAUA,eAAsB,0BACpB,QACA,WACe;CACf,IAAI,OAAO,SAAS,WAAW;EAC7B,MAAM,UAAU,KAAK,uBAAuB,OAAO,QAAQ;EAC3D,MAAM,gBAAgB,QAAQ,SAAS;EACvC;CACF;CAEA,MAAM,UAAU,KACd,uBAAuB,OAAO,MAAM,OAAO,OAAO,OAAO,OAAO,MAAM,WAAW,MACnF;CACA,MAAM,UAAU,KAAK,uBAAuB,OAAO,cAAc;CAEjE,QAAQ,OAAO,MAAf;EACE,KAAK;GACH,MAAM,UAAU,KACd,mFACF;GACA;EACF,KAAK;GACH,MAAM,UAAU,KAAK,sBAAsB,OAAO,QAAQ;GAC1D,MAAM,UAAU,UAAU,gBAAgB,OAAO,IAAI;GACrD;EACF,KAAK;GACH,MAAM,UAAU,KACd,iBAAiB,OAAO,QAAQ,gCAAgC,OAAO,YAAY,OAAO,EAC5F;GACA,MAAM,UAAU,UAAU,gBAAgB,OAAO,SAAS,IAAI;GAC9D;EACF,KAAK;GACH,MAAM,UAAU,KACd,qDAAqD,OAAO,OAAO,OAAO,sBAC5E;GACA,MAAM,2BAA2B,OAAO,QAAQ,SAAS;GACzD;EACF,KAAK;GACH,MAAM,UAAU,KACd,wBAAwB,OAAO,OAAO,UAAU,cAAc,OAAO,4BAChE,OAAO,OAAO,UAAU,gBAAgB,OAAO,oBACtD;GACA,MAAM,UAAU,KACd,gCAAgC,OAAO,YAAY,YAAY,OAAO,QACjE,OAAO,YAAY,eAAe,OAAO,sBACzC,OAAO,YAAY,eAAe,QAAQ,SACjD;GACA,MAAM,2BACJ,OAAO,YAAY,SAAS,wBAC5B,SACF;GACA,IAAI,OAAO,OAAO,iBAChB,MAAM,UAAU,KAAK,oDAAoD;GAE3E,MAAM,UAAU,UACd,gBACA,4BAA4B,OAAO,OAAO,WAAW,CACvD;GACA;EACF;CAEF;CAEA,MAAM,gBAAgB,QAAQ,SAAS;AACzC;AAEA,eAAsB,oCACpB,OACA,WACe;CACf,MAAM,UAAU,UACd,UACA,KAAK,UACH,aAAa;EACX,QAAQ;EACR,QAAQ;GAAE,MAAM;GAAqB,aAAa,MAAM;EAAO;CACjE,CAAC,CACH,CACF;AACF;AAEA,eAAsB,yBACpB,WACe;CACf,MAAM,UAAU,UAAU,UAAU,KAAK,UAAU,kBAAkB,KAAA,CAAS,CAAC,CAAC;AAClF;AAEA,eAAe,gBACb,QACA,WACe;CACf,MAAM,UAAU,UAAU,UAAU,KAAK,UAAU,aAAa;EAAE,QAAQ;EAAQ;CAAO,CAAC,CAAC,CAAC;AAC9F;AAEA,eAAe,2BACb,QACA,WACe;CACf,KAAK,MAAM,SAAS,QAClB,MAAM,UAAU,QAAQ,kCAAkC,OAAO;AAErE"}
@@ -1,4 +1,4 @@
1
- import { n as listOfficialInitRecipes } from "../recipes-w72EpAOi.mjs";
1
+ import { n as listOfficialInitRecipes } from "../recipes-C1kxJCgQ.mjs";
2
2
  //#region src/config/official-github-workflow.d.ts
3
3
  type RenderOfficialGithubWorkflowOptions = {
4
4
  relativeConfigDir?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"docs.d.mts","names":[],"sources":["../../src/config/official-github-workflow.ts"],"mappings":";;KAIY;EACV;EACA;EACA;EACA;;;iBAIc,6BACd,UAAS"}
1
+ {"version":3,"file":"docs.d.mts","names":[],"sources":["../../src/config/official-github-workflow.ts"],"mappings":";;KAOY;EACV;EACA;EACA;EACA;;;iBAIc,6BACd,UAAS"}
@@ -1,2 +1,2 @@
1
- import { n as listOfficialInitRecipes, t as renderOfficialGithubWorkflow } from "../official-github-workflow-Bjlu-FL3.mjs";
1
+ import { n as listOfficialInitRecipes, t as renderOfficialGithubWorkflow } from "../official-github-workflow-B3yeaCgq.mjs";
2
2
  export { listOfficialInitRecipes, renderOfficialGithubWorkflow };
@@ -0,0 +1,24 @@
1
+ import { a as HostRunCommandResult, l as LocalReviewCommandResult, x as PublicationError } from "../types-w22wbdo9.mjs";
2
+ import { PiprResult } from "@usepipr/sdk";
3
+ //#region src/internal/pipr-result.d.ts
4
+ type ResultInput = {
5
+ source: "host";
6
+ result: HostRunCommandResult;
7
+ } | {
8
+ source: "local";
9
+ result: LocalReviewCommandResult;
10
+ } | {
11
+ source: "host";
12
+ result: {
13
+ kind: "publication-error";
14
+ publication: PublicationError["result"];
15
+ };
16
+ };
17
+ declare function toPiprResult(input: ResultInput): PiprResult;
18
+ declare function toPiprErrorResult(_error: unknown): Extract<PiprResult, {
19
+ kind: "error";
20
+ }>;
21
+ declare function stripPiprMainCommentMarkers(mainComment: string): string;
22
+ //#endregion
23
+ export { stripPiprMainCommentMarkers, toPiprErrorResult, toPiprResult };
24
+ //# sourceMappingURL=pipr-result.d.mts.map