@kici-dev/shared 0.1.14 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1 +1,13 @@
1
- TBD
1
+ # @kici-dev/shared
2
+
3
+ Shared utilities for the KiCI CI/CD stack — logging, zx setup, crypto, telemetry, health and metrics routes. No business logic. Re-exports `@kici-dev/core`.
4
+
5
+ This is an internal support library — other `@kici-dev` packages depend on it; it is not meant to be installed directly.
6
+
7
+ Part of [KiCI](https://kici.dev) — CI/CD workflows as TypeScript code: author them with full language power, dry-run them locally, and run them on your own infrastructure.
8
+
9
+ ## Links
10
+
11
+ - Documentation: <https://docs.kici.dev/architecture/overview/>
12
+ - Source: <https://github.com/kici-dev/kici-public/tree/main/packages/shared>
13
+ - License: Apache-2.0
@@ -187,6 +187,7 @@ export interface SeedEnvironmentOpts {
187
187
  waitTimerSeconds?: number | null;
188
188
  holdExpirySeconds?: number | null;
189
189
  minimumTrust?: string | null;
190
+ globPattern?: string | null;
190
191
  }
191
192
  export interface SeedEnvironmentResult {
192
193
  envId: string;
@@ -198,6 +199,24 @@ export interface SeedEnvironmentResult {
198
199
  * are JSON-serialised server-side; pass them as plain arrays or objects.
199
200
  */
200
201
  export declare function seedEnvironmentDirect(databaseUrl: string, opts: SeedEnvironmentOpts): Promise<SeedEnvironmentResult>;
202
+ export interface DeleteEnvironmentOpts {
203
+ orgId: string;
204
+ name: string;
205
+ }
206
+ /**
207
+ * Delete an environment keyed by (org_id, name). Returns whether a row was
208
+ * removed. The `environment_bindings`, `environment_variables`, and
209
+ * `environment_source_overrides` children all carry
210
+ * `FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE CASCADE`,
211
+ * so a single DELETE on `environments` cascades to those children. The
212
+ * `held_runs` FK uses `ON DELETE SET NULL`, so terminal held-run history
213
+ * survives the delete with a null environment reference. Pending held runs
214
+ * still reference the environment, so this helper pre-checks their count and
215
+ * throws before issuing the DELETE — approve or reject them first.
216
+ */
217
+ export declare function deleteEnvironmentDirect(databaseUrl: string, opts: DeleteEnvironmentOpts): Promise<{
218
+ deleted: boolean;
219
+ }>;
201
220
  export interface SeedEnvironmentBindingOpts {
202
221
  orgId: string;
203
222
  envName: string;
@@ -219,6 +238,7 @@ export interface SetEnvironmentPolicyOpts {
219
238
  holdExpirySeconds?: number | null;
220
239
  minimumTrust?: string | null;
221
240
  enabled?: boolean;
241
+ allowLocalExecution?: boolean;
222
242
  }
223
243
  /**
224
244
  * UPDATE only the policy fields that were explicitly provided. Columns that
@@ -1462,5 +1482,14 @@ export declare function clearPeerCredentialsRevokedAtByIdsDirect(databaseUrl: st
1462
1482
  export declare function countActivePeerCredentialsByInstanceDirect(databaseUrl: string, opts: {
1463
1483
  instanceId: string;
1464
1484
  }): Promise<number>;
1485
+ /**
1486
+ * Terminate every idle backend of the connecting user except our own
1487
+ * connection. Mirrors what a Postgres leader demotion does to idle pooled
1488
+ * connections — used by resilience tests to verify the pg pool error
1489
+ * handlers absorb the termination without a process restart.
1490
+ *
1491
+ * Returns the number of backends terminated.
1492
+ */
1493
+ export declare function terminateIdleDbBackendsDirect(databaseUrl: string): Promise<number>;
1465
1494
  export {};
1466
1495
  //# sourceMappingURL=db-admin.d.ts.map
package/dist/db-admin.js CHANGED
@@ -351,7 +351,8 @@ const ENV_POLICY_COLUMNS = new Set([
351
351
  "wait_timer_seconds",
352
352
  "hold_expiry_seconds",
353
353
  "minimum_trust",
354
- "enabled"
354
+ "enabled",
355
+ "allow_local_execution"
355
356
  ]);
356
357
  /**
357
358
  * Upsert an environment row keyed by (org_id, name). Returns the env id and
@@ -370,9 +371,9 @@ async function seedEnvironmentDirect(databaseUrl, opts) {
370
371
  const reviewersJson = opts.requiredReviewers === void 0 ? null : JSON.stringify(opts.requiredReviewers);
371
372
  const row = (await pool.query(`INSERT INTO environments
372
373
  (org_id, name, type, enabled, branch_restrictions, required_reviewers,
373
- wait_timer_seconds, hold_expiry_seconds, minimum_trust)
374
+ wait_timer_seconds, hold_expiry_seconds, minimum_trust, glob_pattern)
374
375
  VALUES ($1, $2, COALESCE($3, 'fixed'), COALESCE($4, true), $5::jsonb, $6::jsonb,
375
- $7, COALESCE($8, 86400), $9)
376
+ $7, COALESCE($8, 86400), $9, $10)
376
377
  ON CONFLICT (org_id, name) DO UPDATE SET
377
378
  type = COALESCE(EXCLUDED.type, environments.type),
378
379
  enabled = EXCLUDED.enabled,
@@ -381,6 +382,7 @@ async function seedEnvironmentDirect(databaseUrl, opts) {
381
382
  wait_timer_seconds = EXCLUDED.wait_timer_seconds,
382
383
  hold_expiry_seconds = EXCLUDED.hold_expiry_seconds,
383
384
  minimum_trust = EXCLUDED.minimum_trust,
385
+ glob_pattern = COALESCE(EXCLUDED.glob_pattern, environments.glob_pattern),
384
386
  updated_at = now()
385
387
  RETURNING id, (xmax = 0) AS inserted`, [
386
388
  opts.orgId,
@@ -391,7 +393,8 @@ async function seedEnvironmentDirect(databaseUrl, opts) {
391
393
  reviewersJson,
392
394
  opts.waitTimerSeconds ?? null,
393
395
  opts.holdExpirySeconds ?? null,
394
- opts.minimumTrust ?? null
396
+ opts.minimumTrust ?? null,
397
+ opts.globPattern ?? null
395
398
  ])).rows[0];
396
399
  if (!row) throw new Error(`environment: upsert returned no row for ${opts.name}`);
397
400
  return {
@@ -403,6 +406,33 @@ async function seedEnvironmentDirect(databaseUrl, opts) {
403
406
  }
404
407
  }
405
408
  /**
409
+ * Delete an environment keyed by (org_id, name). Returns whether a row was
410
+ * removed. The `environment_bindings`, `environment_variables`, and
411
+ * `environment_source_overrides` children all carry
412
+ * `FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE CASCADE`,
413
+ * so a single DELETE on `environments` cascades to those children. The
414
+ * `held_runs` FK uses `ON DELETE SET NULL`, so terminal held-run history
415
+ * survives the delete with a null environment reference. Pending held runs
416
+ * still reference the environment, so this helper pre-checks their count and
417
+ * throws before issuing the DELETE — approve or reject them first.
418
+ */
419
+ async function deleteEnvironmentDirect(databaseUrl, opts) {
420
+ const pool = new pg.Pool({
421
+ connectionString: databaseUrl,
422
+ max: 1
423
+ });
424
+ try {
425
+ const pending = await pool.query(`SELECT count(*)::text AS count FROM held_runs hr
426
+ JOIN environments e ON e.id = hr.environment_id
427
+ WHERE e.org_id = $1 AND e.name = $2 AND hr.status = 'pending'`, [opts.orgId, opts.name]);
428
+ const pendingCount = Number(pending.rows[0]?.count ?? 0);
429
+ if (pendingCount > 0) throw new Error(`environment has ${pendingCount} pending held run(s) — approve or reject them first`);
430
+ return { deleted: (await pool.query(`DELETE FROM environments WHERE org_id = $1 AND name = $2 RETURNING id`, [opts.orgId, opts.name])).rows.length > 0 };
431
+ } finally {
432
+ await pool.end();
433
+ }
434
+ }
435
+ /**
406
436
  * Upsert an `environment_bindings` row connecting `envName` to `scopePattern`.
407
437
  * Throws if the environment does not exist.
408
438
  */
@@ -449,6 +479,7 @@ async function setEnvironmentPolicyDirect(databaseUrl, opts) {
449
479
  if (opts.holdExpirySeconds !== void 0) addSet("hold_expiry_seconds", opts.holdExpirySeconds);
450
480
  if (opts.minimumTrust !== void 0) addSet("minimum_trust", opts.minimumTrust);
451
481
  if (opts.enabled !== void 0) addSet("enabled", opts.enabled);
482
+ if (opts.allowLocalExecution !== void 0) addSet("allow_local_execution", opts.allowLocalExecution);
452
483
  if (setClauses.length === 0) throw new Error("environment: setEnvironmentPolicy requires at least one policy field");
453
484
  const pool = new pg.Pool({
454
485
  connectionString: databaseUrl,
@@ -2555,7 +2586,27 @@ async function countActivePeerCredentialsByInstanceDirect(databaseUrl, opts) {
2555
2586
  await pool.end();
2556
2587
  }
2557
2588
  }
2589
+ /**
2590
+ * Terminate every idle backend of the connecting user except our own
2591
+ * connection. Mirrors what a Postgres leader demotion does to idle pooled
2592
+ * connections — used by resilience tests to verify the pg pool error
2593
+ * handlers absorb the termination without a process restart.
2594
+ *
2595
+ * Returns the number of backends terminated.
2596
+ */
2597
+ async function terminateIdleDbBackendsDirect(databaseUrl) {
2598
+ const pool = createPool(databaseUrl);
2599
+ try {
2600
+ return (await pool.query(`SELECT pg_terminate_backend(pid)
2601
+ FROM pg_stat_activity
2602
+ WHERE pid <> pg_backend_pid()
2603
+ AND usename = current_user
2604
+ AND state = 'idle'`)).rowCount ?? 0;
2605
+ } finally {
2606
+ await pool.end();
2607
+ }
2608
+ }
2558
2609
  //#endregion
2559
- export { MIGRATION_HASH_TABLE, PROVIDER_HASH_KEY, REGISTERABLE_TRIGGER_TYPES, apiKeyExistsDirect, bumpRegistryVersionDirect, bumpRegistryVersionSimpleDirect, cleanupExecutionRowsDirect, clearDispatchQueueDirect, clearPeerCredentialsRevokedAtByIdsDirect, computeMigrationsHash, countActivePeerCredentialsByInstanceDirect, countCronLastFiredDirect, countHeldRunsByRunIdDirect, countWebhookSourcesByConnectionIdDirect, createDbRole, createEnvironmentTemplateDirect, createJoinTokenDirect, createReadOnlyDbUser, deleteCronLastFiredDirect, deleteCrossRepoTrustDirect, deleteExecutionRunsByWorkflowNameDirect, deleteGenericWebhookSourcesByNameDirect, deleteKiciEventsDirect, deleteOrgSettingsByCustomerIdDirect, deletePeerCredentialsByInstanceIdLikeDirect, deleteWorkflowRegistrationsDirect, describeTableColumnsDirect, dropAndCreateDatabase, dropDatabaseDirect, emitKiciEventDirect, ensureDatabase, ensureOrgOwnerMemberDirect, findAnyUserApiKeyIdDirect, getExecutionRunSecurityDirect, getGenericWebhookSourceByRoutingKeyDirect, getHeldRunByIdDirect, getPeerCredentialRevokedAtDirect, getRegistryVersionDirect, getWebhookSourceByRoutingKeyDirect, getWorkflowRegistrationByIdDirect, insertCronLastFiredNowDirect, insertCrossRepoTrustStrictDirect, insertKiciEventRawDirect, insertPeerCredentialExpiredDirect, insertWorkflowRegistrationRawDirect, insertWorkflowRegistrationStrictDirect, isSchemaCurrent, isSchemaCurrentFromFilesDirect, latestExecutionRunByStatusDirect, listActiveGenericWebhookSourcesDirect, listActivePeerCredentialsExcludingDirect, listCrossRepoTrustBySourceRoutingKeyDirect, listEnvironmentsDirect, listExecutionJobsDirect, listExecutionRunsDirect, listKiciEventsDirect, listQueueDirect, listRegistrationsByRoutingKeyDirect, listRegistrationsDirect, maskDatabaseUrl, parseDatabaseUrl, platformConnectionExistsDirect, pollKiciEventsDirect, prunePeerCredentialsDirect, purgeScopedSecretsDirect, purgeSecretBackendsDirect, purgeStaleExecutionDirect, purgeStaleSourcesDirect, readStoredMigrationContentHash, registerWorkflowManualDirect, resetRaftStateDirect, resolvePlatformWebhookSourceRoutingKeyDirect, restoreSoftDeletedGenericWebhookSourceDirect, seedApiKeyInlineDirect, seedCiSecurityFixturesDirect, seedCrossRepoTrustDirect, seedEnvironmentBindingDirect, seedEnvironmentDirect, seedGenericWebhookSourceDirect, seedSourcePrivateKeyDirect, seedSyntheticGithubSourceDirect, seedUniversalGitSourceDirect, seedWebhookSecretDirect, setEnvironmentPolicyDirect, setEnvironmentSecretDirect, showEnvironmentDirect, showExecutionRunDirect, showKiciEventDirect, showQueueEntryDirect, showRegistrationDirect, storeMigrationContentHash, storeMigrationContentHashInTableDirect, tableExistsDirect, updateGenericWebhookVerificationConfigDirect, updateOrgSettingsDeniedReposDirect, updateSourceRoutingKeyDirect, updateWorkflowRegistrationCommitShaDirect, upsertCronLastFiredDirect, upsertOrgSettingsGlobalWorkflowsDirect, verifyKiciEventNotifyDirect, waitForEventLogRowByDeliveryIdDirect, waitForExecutionRunStatusSinceDirect, waitForLatestExecutionJobStatusDirect, waitForPlatformEventLogDistinctRoutedDirect, waitForPlatformExecutionRunStatusDirect, waitForPlatformRegistrationsDirect, waitForPostgresDirect, waitForRegistrationsByRoutingKeyDirect, waitForRegistrationsUpdatedAtAdvanceDirect, waitForRunCompletionDirect };
2610
+ export { MIGRATION_HASH_TABLE, PROVIDER_HASH_KEY, REGISTERABLE_TRIGGER_TYPES, apiKeyExistsDirect, bumpRegistryVersionDirect, bumpRegistryVersionSimpleDirect, cleanupExecutionRowsDirect, clearDispatchQueueDirect, clearPeerCredentialsRevokedAtByIdsDirect, computeMigrationsHash, countActivePeerCredentialsByInstanceDirect, countCronLastFiredDirect, countHeldRunsByRunIdDirect, countWebhookSourcesByConnectionIdDirect, createDbRole, createEnvironmentTemplateDirect, createJoinTokenDirect, createReadOnlyDbUser, deleteCronLastFiredDirect, deleteCrossRepoTrustDirect, deleteEnvironmentDirect, deleteExecutionRunsByWorkflowNameDirect, deleteGenericWebhookSourcesByNameDirect, deleteKiciEventsDirect, deleteOrgSettingsByCustomerIdDirect, deletePeerCredentialsByInstanceIdLikeDirect, deleteWorkflowRegistrationsDirect, describeTableColumnsDirect, dropAndCreateDatabase, dropDatabaseDirect, emitKiciEventDirect, ensureDatabase, ensureOrgOwnerMemberDirect, findAnyUserApiKeyIdDirect, getExecutionRunSecurityDirect, getGenericWebhookSourceByRoutingKeyDirect, getHeldRunByIdDirect, getPeerCredentialRevokedAtDirect, getRegistryVersionDirect, getWebhookSourceByRoutingKeyDirect, getWorkflowRegistrationByIdDirect, insertCronLastFiredNowDirect, insertCrossRepoTrustStrictDirect, insertKiciEventRawDirect, insertPeerCredentialExpiredDirect, insertWorkflowRegistrationRawDirect, insertWorkflowRegistrationStrictDirect, isSchemaCurrent, isSchemaCurrentFromFilesDirect, latestExecutionRunByStatusDirect, listActiveGenericWebhookSourcesDirect, listActivePeerCredentialsExcludingDirect, listCrossRepoTrustBySourceRoutingKeyDirect, listEnvironmentsDirect, listExecutionJobsDirect, listExecutionRunsDirect, listKiciEventsDirect, listQueueDirect, listRegistrationsByRoutingKeyDirect, listRegistrationsDirect, maskDatabaseUrl, parseDatabaseUrl, platformConnectionExistsDirect, pollKiciEventsDirect, prunePeerCredentialsDirect, purgeScopedSecretsDirect, purgeSecretBackendsDirect, purgeStaleExecutionDirect, purgeStaleSourcesDirect, readStoredMigrationContentHash, registerWorkflowManualDirect, resetRaftStateDirect, resolvePlatformWebhookSourceRoutingKeyDirect, restoreSoftDeletedGenericWebhookSourceDirect, seedApiKeyInlineDirect, seedCiSecurityFixturesDirect, seedCrossRepoTrustDirect, seedEnvironmentBindingDirect, seedEnvironmentDirect, seedGenericWebhookSourceDirect, seedSourcePrivateKeyDirect, seedSyntheticGithubSourceDirect, seedUniversalGitSourceDirect, seedWebhookSecretDirect, setEnvironmentPolicyDirect, setEnvironmentSecretDirect, showEnvironmentDirect, showExecutionRunDirect, showKiciEventDirect, showQueueEntryDirect, showRegistrationDirect, storeMigrationContentHash, storeMigrationContentHashInTableDirect, tableExistsDirect, terminateIdleDbBackendsDirect, updateGenericWebhookVerificationConfigDirect, updateOrgSettingsDeniedReposDirect, updateSourceRoutingKeyDirect, updateWorkflowRegistrationCommitShaDirect, upsertCronLastFiredDirect, upsertOrgSettingsGlobalWorkflowsDirect, verifyKiciEventNotifyDirect, waitForEventLogRowByDeliveryIdDirect, waitForExecutionRunStatusSinceDirect, waitForLatestExecutionJobStatusDirect, waitForPlatformEventLogDistinctRoutedDirect, waitForPlatformExecutionRunStatusDirect, waitForPlatformRegistrationsDirect, waitForPostgresDirect, waitForRegistrationsByRoutingKeyDirect, waitForRegistrationsUpdatedAtAdvanceDirect, waitForRunCompletionDirect };
2560
2611
 
2561
2612
  //# sourceMappingURL=db-admin.js.map
package/dist/db.d.ts CHANGED
@@ -1,9 +1,28 @@
1
1
  import pg from 'pg';
2
2
  import { Kysely } from 'kysely';
3
+ /** Where a pg connection error surfaced. */
4
+ export type PgPoolErrorSource = 'idle-pool' | 'client';
5
+ export interface CreatePoolOptions {
6
+ /** Extra pg.Pool config merged over the connection string (e.g. max, connectionTimeoutMillis). */
7
+ config?: Omit<pg.PoolConfig, 'connectionString'>;
8
+ /**
9
+ * Optional hook invoked after the built-in log line on every absorbed
10
+ * connection error (e.g. to increment a metrics counter). Additive — it
11
+ * never replaces the log.
12
+ */
13
+ onError?: (err: Error, source: PgPoolErrorSource) => void;
14
+ }
3
15
  /**
4
16
  * Create PostgreSQL connection pool.
17
+ *
18
+ * Always attaches error handlers for both idle pooled clients (the pool's
19
+ * own 'error' event) and checked-out clients (per-client 'error' via the
20
+ * 'connect' hook). Without them, a terminated backend — e.g. a Postgres
21
+ * leader switchover — escalates to an uncaughtException and a full process
22
+ * restart. The broken connection is logged and discarded; pg replaces it on
23
+ * the next acquire. In-flight query failures still reject to their callers.
5
24
  */
6
- export declare function createPool(databaseUrl: string): pg.Pool;
25
+ export declare function createPool(databaseUrl: string, options?: CreatePoolOptions): pg.Pool;
7
26
  /**
8
27
  * Create Kysely database instance (PostgreSQL only).
9
28
  *
package/dist/db.js CHANGED
@@ -1,12 +1,44 @@
1
1
  import "./chunk-gOLHoazu.js";
2
2
  import pg from "pg";
3
3
  import { Kysely, PostgresDialect } from "kysely";
4
+ import { createLogger } from "@kici-dev/core";
4
5
  //#region src/db.ts
6
+ let poolLogger;
7
+ function getPoolLogger() {
8
+ poolLogger ??= createLogger({ prefix: "pg-pool" });
9
+ return poolLogger;
10
+ }
5
11
  /**
6
12
  * Create PostgreSQL connection pool.
13
+ *
14
+ * Always attaches error handlers for both idle pooled clients (the pool's
15
+ * own 'error' event) and checked-out clients (per-client 'error' via the
16
+ * 'connect' hook). Without them, a terminated backend — e.g. a Postgres
17
+ * leader switchover — escalates to an uncaughtException and a full process
18
+ * restart. The broken connection is logged and discarded; pg replaces it on
19
+ * the next acquire. In-flight query failures still reject to their callers.
7
20
  */
8
- function createPool(databaseUrl) {
9
- return new pg.Pool({ connectionString: databaseUrl });
21
+ function createPool(databaseUrl, options) {
22
+ const pool = new pg.Pool({
23
+ connectionString: databaseUrl,
24
+ ...options?.config
25
+ });
26
+ const seen = /* @__PURE__ */ new WeakSet();
27
+ const handle = (err, source) => {
28
+ if (seen.has(err)) return;
29
+ seen.add(err);
30
+ getPoolLogger().warn("Discarded broken pg connection", {
31
+ source,
32
+ error: err.message,
33
+ stack: err.stack
34
+ });
35
+ options?.onError?.(err, source);
36
+ };
37
+ pool.on("error", (err) => handle(err, "idle-pool"));
38
+ pool.on("connect", (client) => {
39
+ client.on("error", (err) => handle(err, "client"));
40
+ });
41
+ return pool;
10
42
  }
11
43
  /**
12
44
  * Create Kysely database instance (PostgreSQL only).
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=db.test.d.ts.map
@@ -50,9 +50,21 @@ export interface ShutdownHandle {
50
50
  /**
51
51
  * Wire up SIGTERM / SIGINT (and optionally uncaughtException /
52
52
  * unhandledRejection) handlers that execute the provided teardown
53
- * steps sequentially, then `process.exit(0)`.
53
+ * steps sequentially, then exit.
54
+ *
55
+ * Exit codes: signal-triggered and programmatic shutdowns exit 0;
56
+ * shutdowns triggered by uncaughtException / unhandledRejection exit 1 so
57
+ * `Restart=on-failure`-style supervisor policies and exit-code alerting
58
+ * see the fatal cause. Escalation is sticky — a fatal trigger arriving
59
+ * while a clean shutdown is already in progress still raises the final
60
+ * exit code to 1.
54
61
  *
55
62
  * A force-exit timer ensures the process terminates even if a step hangs.
63
+ * The force-exit honors the same sticky exit code as a clean completion: a
64
+ * slow SIGTERM/SIGINT stop that merely overran the grace period still exits 0,
65
+ * so systemd records an intentional stop rather than marking the unit `failed`
66
+ * (which would break `systemctl restart` recovery). Only a fatal trigger
67
+ * (uncaughtException / unhandledRejection) raises the force-exit code to 1.
56
68
  */
57
69
  export declare function setupGracefulShutdown(options: GracefulShutdownOptions): ShutdownHandle;
58
70
  //# sourceMappingURL=graceful-shutdown.d.ts.map
@@ -4,14 +4,28 @@ import { toErrorMessage } from "@kici-dev/core";
4
4
  /**
5
5
  * Wire up SIGTERM / SIGINT (and optionally uncaughtException /
6
6
  * unhandledRejection) handlers that execute the provided teardown
7
- * steps sequentially, then `process.exit(0)`.
7
+ * steps sequentially, then exit.
8
+ *
9
+ * Exit codes: signal-triggered and programmatic shutdowns exit 0;
10
+ * shutdowns triggered by uncaughtException / unhandledRejection exit 1 so
11
+ * `Restart=on-failure`-style supervisor policies and exit-code alerting
12
+ * see the fatal cause. Escalation is sticky — a fatal trigger arriving
13
+ * while a clean shutdown is already in progress still raises the final
14
+ * exit code to 1.
8
15
  *
9
16
  * A force-exit timer ensures the process terminates even if a step hangs.
17
+ * The force-exit honors the same sticky exit code as a clean completion: a
18
+ * slow SIGTERM/SIGINT stop that merely overran the grace period still exits 0,
19
+ * so systemd records an intentional stop rather than marking the unit `failed`
20
+ * (which would break `systemctl restart` recovery). Only a fatal trigger
21
+ * (uncaughtException / unhandledRejection) raises the force-exit code to 1.
10
22
  */
11
23
  function setupGracefulShutdown(options) {
12
24
  const { logger, steps, timeoutMs = 3e4, onForceExit, skipErrorHandlers = false } = options;
13
25
  let isShuttingDown = false;
14
- async function gracefulShutdown(signal) {
26
+ let exitCode = 0;
27
+ async function gracefulShutdown(signal, code = 0) {
28
+ exitCode = Math.max(exitCode, code);
15
29
  if (isShuttingDown) {
16
30
  logger.warn("Shutdown already in progress, ignoring signal", { signal });
17
31
  return;
@@ -19,8 +33,8 @@ function setupGracefulShutdown(options) {
19
33
  isShuttingDown = true;
20
34
  logger.info(`Received ${signal}, starting graceful shutdown...`);
21
35
  const forceExitTimeout = setTimeout(() => {
22
- logger.error(`Graceful shutdown timed out after ${timeoutMs / 1e3}s, forcing exit`);
23
- if (onForceExit?.() !== true) process.exit(1);
36
+ logger.error(`Graceful shutdown timed out after ${timeoutMs / 1e3}s, forcing exit`, { exitCode });
37
+ if (onForceExit?.() !== true) process.exit(exitCode);
24
38
  }, timeoutMs);
25
39
  try {
26
40
  for (const step of steps) try {
@@ -34,8 +48,8 @@ function setupGracefulShutdown(options) {
34
48
  });
35
49
  }
36
50
  clearTimeout(forceExitTimeout);
37
- logger.info("Graceful shutdown complete");
38
- process.exit(0);
51
+ logger.info("Graceful shutdown complete", { exitCode });
52
+ process.exit(exitCode);
39
53
  } catch (error) {
40
54
  logger.error("Error during graceful shutdown", {
41
55
  error: toErrorMessage(error),
@@ -53,17 +67,17 @@ function setupGracefulShutdown(options) {
53
67
  error: error.message,
54
68
  stack: error.stack
55
69
  });
56
- gracefulShutdown("uncaughtException");
70
+ gracefulShutdown("uncaughtException", 1);
57
71
  });
58
72
  process.on("unhandledRejection", (reason) => {
59
73
  logger.error("Unhandled rejection", {
60
74
  reason: toErrorMessage(reason),
61
75
  stack: reason instanceof Error ? reason.stack : void 0
62
76
  });
63
- gracefulShutdown("unhandledRejection");
77
+ gracefulShutdown("unhandledRejection", 1);
64
78
  });
65
79
  }
66
- return { shutdown: gracefulShutdown };
80
+ return { shutdown: (signal) => gracefulShutdown(signal) };
67
81
  }
68
82
  //#endregion
69
83
  export { setupGracefulShutdown };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export * from '@kici-dev/core';
2
2
  export { RingBuffer } from './ring-buffer.js';
3
- export { createPool, createDb } from './db.js';
4
- export { parseDatabaseUrl, maskDatabaseUrl, dropAndCreateDatabase, dropDatabaseDirect, ensureDatabase, type EnsureDatabaseOpts, createDbRole, createReadOnlyDbUser, computeMigrationsHash, storeMigrationContentHash, readStoredMigrationContentHash, isSchemaCurrent, clearDispatchQueueDirect, purgeStaleExecutionDirect, purgeStaleSourcesDirect, purgeScopedSecretsDirect, seedEnvironmentDirect, seedEnvironmentBindingDirect, setEnvironmentPolicyDirect, listEnvironmentsDirect, showEnvironmentDirect, createEnvironmentTemplateDirect, setEnvironmentSecretDirect, listQueueDirect, showQueueEntryDirect, listExecutionRunsDirect, showExecutionRunDirect, listExecutionJobsDirect, listRegistrationsDirect, showRegistrationDirect, registerWorkflowManualDirect, resetRaftStateDirect, emitKiciEventDirect, seedGenericWebhookSourceDirect, purgeSecretBackendsDirect, apiKeyExistsDirect, seedApiKeyInlineDirect, platformConnectionExistsDirect, countWebhookSourcesByConnectionIdDirect, getWebhookSourceByRoutingKeyDirect, findAnyUserApiKeyIdDirect, seedSyntheticGithubSourceDirect, seedWebhookSecretDirect, seedSourcePrivateKeyDirect, bumpRegistryVersionDirect, pollKiciEventsDirect, waitForPostgresDirect, waitForRunCompletionDirect, cleanupExecutionRowsDirect, isSchemaCurrentFromFilesDirect, storeMigrationContentHashInTableDirect, createJoinTokenDirect, updateSourceRoutingKeyDirect, prunePeerCredentialsDirect, waitForPlatformRegistrationsDirect, seedUniversalGitSourceDirect, seedCiSecurityFixturesDirect, waitForExecutionRunStatusSinceDirect, latestExecutionRunByStatusDirect, waitForLatestExecutionJobStatusDirect, describeTableColumnsDirect, tableExistsDirect, insertKiciEventRawDirect, showKiciEventDirect, listKiciEventsDirect, deleteKiciEventsDirect, verifyKiciEventNotifyDirect, seedCrossRepoTrustDirect, listCrossRepoTrustBySourceRoutingKeyDirect, deleteCrossRepoTrustDirect, insertCrossRepoTrustStrictDirect, deleteWorkflowRegistrationsDirect, getWorkflowRegistrationByIdDirect, listRegistrationsByRoutingKeyDirect, waitForRegistrationsByRoutingKeyDirect, waitForRegistrationsUpdatedAtAdvanceDirect, updateWorkflowRegistrationCommitShaDirect, insertWorkflowRegistrationRawDirect, insertWorkflowRegistrationStrictDirect, getRegistryVersionDirect, bumpRegistryVersionSimpleDirect, upsertCronLastFiredDirect, countCronLastFiredDirect, insertCronLastFiredNowDirect, deleteCronLastFiredDirect, deleteExecutionRunsByWorkflowNameDirect, getGenericWebhookSourceByRoutingKeyDirect, listActiveGenericWebhookSourcesDirect, updateGenericWebhookVerificationConfigDirect, deleteGenericWebhookSourcesByNameDirect, restoreSoftDeletedGenericWebhookSourceDirect, upsertOrgSettingsGlobalWorkflowsDirect, updateOrgSettingsDeniedReposDirect, deleteOrgSettingsByCustomerIdDirect, getExecutionRunSecurityDirect, getHeldRunByIdDirect, countHeldRunsByRunIdDirect, waitForPlatformExecutionRunStatusDirect, waitForPlatformEventLogDistinctRoutedDirect, waitForEventLogRowByDeliveryIdDirect, resolvePlatformWebhookSourceRoutingKeyDirect, ensureOrgOwnerMemberDirect, deletePeerCredentialsByInstanceIdLikeDirect, insertPeerCredentialExpiredDirect, getPeerCredentialRevokedAtDirect, listActivePeerCredentialsExcludingDirect, clearPeerCredentialsRevokedAtByIdsDirect, countActivePeerCredentialsByInstanceDirect, type ColumnInfo, type KiciEventRow, type CrossRepoTrustRow, type WorkflowRegistrationFullRow, type RegistrationsScopedResult, type LatestExecutionRunResult, type WaitForLatestJobResult, type ExecutionRunSecurityRow, type HeldRunSecurityRow, type EventLogRow as PlatformEventLogRow, type UpsertOrgSettingsOpts, type OrgSettingsRepoPatternEntry, type InsertKiciEventRawOpts, type EmitKiciEventOpts, type SeedGenericWebhookSourceOpts, REGISTERABLE_TRIGGER_TYPES, MIGRATION_HASH_TABLE, type PurgeStaleExecutionResult, type PurgeStaleSourcesResult, type SeedEnvironmentOpts, type SeedEnvironmentResult, type SeedEnvironmentBindingOpts, type SetEnvironmentPolicyOpts, type EnvironmentRow, type EnvironmentVariableRow, type EnvironmentBindingRow, type ShowEnvironmentResult, type CreateEnvironmentTemplateOpts, type SetEnvironmentSecretOpts, type DispatchQueueRow, type ListQueueOpts, type ExecutionRunRow, type ExecutionJobRow, type ListExecutionRunsOpts, type WorkflowRegistrationRow, type ListRegistrationsOpts, type ListRegistrationsResult, type ShowRegistrationResult, type RegisterWorkflowManualOpts, type RegisterWorkflowManualResult, } from './db-admin.js';
3
+ export { createPool, createDb, type CreatePoolOptions, type PgPoolErrorSource } from './db.js';
4
+ export { parseDatabaseUrl, maskDatabaseUrl, dropAndCreateDatabase, dropDatabaseDirect, ensureDatabase, type EnsureDatabaseOpts, createDbRole, createReadOnlyDbUser, computeMigrationsHash, storeMigrationContentHash, readStoredMigrationContentHash, isSchemaCurrent, clearDispatchQueueDirect, purgeStaleExecutionDirect, purgeStaleSourcesDirect, purgeScopedSecretsDirect, seedEnvironmentDirect, deleteEnvironmentDirect, seedEnvironmentBindingDirect, setEnvironmentPolicyDirect, listEnvironmentsDirect, showEnvironmentDirect, createEnvironmentTemplateDirect, setEnvironmentSecretDirect, listQueueDirect, showQueueEntryDirect, listExecutionRunsDirect, showExecutionRunDirect, listExecutionJobsDirect, listRegistrationsDirect, showRegistrationDirect, registerWorkflowManualDirect, resetRaftStateDirect, emitKiciEventDirect, seedGenericWebhookSourceDirect, purgeSecretBackendsDirect, apiKeyExistsDirect, seedApiKeyInlineDirect, platformConnectionExistsDirect, countWebhookSourcesByConnectionIdDirect, getWebhookSourceByRoutingKeyDirect, findAnyUserApiKeyIdDirect, seedSyntheticGithubSourceDirect, seedWebhookSecretDirect, seedSourcePrivateKeyDirect, bumpRegistryVersionDirect, pollKiciEventsDirect, waitForPostgresDirect, waitForRunCompletionDirect, cleanupExecutionRowsDirect, isSchemaCurrentFromFilesDirect, storeMigrationContentHashInTableDirect, createJoinTokenDirect, updateSourceRoutingKeyDirect, prunePeerCredentialsDirect, waitForPlatformRegistrationsDirect, seedUniversalGitSourceDirect, seedCiSecurityFixturesDirect, waitForExecutionRunStatusSinceDirect, latestExecutionRunByStatusDirect, waitForLatestExecutionJobStatusDirect, describeTableColumnsDirect, tableExistsDirect, insertKiciEventRawDirect, showKiciEventDirect, listKiciEventsDirect, deleteKiciEventsDirect, verifyKiciEventNotifyDirect, seedCrossRepoTrustDirect, listCrossRepoTrustBySourceRoutingKeyDirect, deleteCrossRepoTrustDirect, insertCrossRepoTrustStrictDirect, deleteWorkflowRegistrationsDirect, getWorkflowRegistrationByIdDirect, listRegistrationsByRoutingKeyDirect, waitForRegistrationsByRoutingKeyDirect, waitForRegistrationsUpdatedAtAdvanceDirect, updateWorkflowRegistrationCommitShaDirect, insertWorkflowRegistrationRawDirect, insertWorkflowRegistrationStrictDirect, getRegistryVersionDirect, bumpRegistryVersionSimpleDirect, upsertCronLastFiredDirect, countCronLastFiredDirect, insertCronLastFiredNowDirect, deleteCronLastFiredDirect, deleteExecutionRunsByWorkflowNameDirect, getGenericWebhookSourceByRoutingKeyDirect, listActiveGenericWebhookSourcesDirect, updateGenericWebhookVerificationConfigDirect, deleteGenericWebhookSourcesByNameDirect, restoreSoftDeletedGenericWebhookSourceDirect, upsertOrgSettingsGlobalWorkflowsDirect, updateOrgSettingsDeniedReposDirect, deleteOrgSettingsByCustomerIdDirect, getExecutionRunSecurityDirect, getHeldRunByIdDirect, countHeldRunsByRunIdDirect, waitForPlatformExecutionRunStatusDirect, waitForPlatformEventLogDistinctRoutedDirect, waitForEventLogRowByDeliveryIdDirect, resolvePlatformWebhookSourceRoutingKeyDirect, ensureOrgOwnerMemberDirect, deletePeerCredentialsByInstanceIdLikeDirect, insertPeerCredentialExpiredDirect, getPeerCredentialRevokedAtDirect, listActivePeerCredentialsExcludingDirect, clearPeerCredentialsRevokedAtByIdsDirect, countActivePeerCredentialsByInstanceDirect, terminateIdleDbBackendsDirect, type ColumnInfo, type KiciEventRow, type CrossRepoTrustRow, type WorkflowRegistrationFullRow, type RegistrationsScopedResult, type LatestExecutionRunResult, type WaitForLatestJobResult, type ExecutionRunSecurityRow, type HeldRunSecurityRow, type EventLogRow as PlatformEventLogRow, type UpsertOrgSettingsOpts, type OrgSettingsRepoPatternEntry, type InsertKiciEventRawOpts, type EmitKiciEventOpts, type SeedGenericWebhookSourceOpts, REGISTERABLE_TRIGGER_TYPES, MIGRATION_HASH_TABLE, type PurgeStaleExecutionResult, type PurgeStaleSourcesResult, type SeedEnvironmentOpts, type SeedEnvironmentResult, type SeedEnvironmentBindingOpts, type SetEnvironmentPolicyOpts, type EnvironmentRow, type EnvironmentVariableRow, type EnvironmentBindingRow, type ShowEnvironmentResult, type CreateEnvironmentTemplateOpts, type SetEnvironmentSecretOpts, type DispatchQueueRow, type ListQueueOpts, type ExecutionRunRow, type ExecutionJobRow, type ListExecutionRunsOpts, type WorkflowRegistrationRow, type ListRegistrationsOpts, type ListRegistrationsResult, type ShowRegistrationResult, type RegisterWorkflowManualOpts, type RegisterWorkflowManualResult, } from './db-admin.js';
5
5
  export { createMetricsRoutes, type MetricsRoutesDeps } from './routes/metrics.js';
6
6
  export { createHealthRoutes, type HealthRoutesDeps } from './routes/health.js';
7
7
  export { getReconnectDelay } from './reconnect-delay.js';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import "./chunk-gOLHoazu.js";
2
2
  import { createDb, createPool } from "./db.js";
3
- import { MIGRATION_HASH_TABLE, REGISTERABLE_TRIGGER_TYPES, apiKeyExistsDirect, bumpRegistryVersionDirect, bumpRegistryVersionSimpleDirect, cleanupExecutionRowsDirect, clearDispatchQueueDirect, clearPeerCredentialsRevokedAtByIdsDirect, computeMigrationsHash, countActivePeerCredentialsByInstanceDirect, countCronLastFiredDirect, countHeldRunsByRunIdDirect, countWebhookSourcesByConnectionIdDirect, createDbRole, createEnvironmentTemplateDirect, createJoinTokenDirect, createReadOnlyDbUser, deleteCronLastFiredDirect, deleteCrossRepoTrustDirect, deleteExecutionRunsByWorkflowNameDirect, deleteGenericWebhookSourcesByNameDirect, deleteKiciEventsDirect, deleteOrgSettingsByCustomerIdDirect, deletePeerCredentialsByInstanceIdLikeDirect, deleteWorkflowRegistrationsDirect, describeTableColumnsDirect, dropAndCreateDatabase, dropDatabaseDirect, emitKiciEventDirect, ensureDatabase, ensureOrgOwnerMemberDirect, findAnyUserApiKeyIdDirect, getExecutionRunSecurityDirect, getGenericWebhookSourceByRoutingKeyDirect, getHeldRunByIdDirect, getPeerCredentialRevokedAtDirect, getRegistryVersionDirect, getWebhookSourceByRoutingKeyDirect, getWorkflowRegistrationByIdDirect, insertCronLastFiredNowDirect, insertCrossRepoTrustStrictDirect, insertKiciEventRawDirect, insertPeerCredentialExpiredDirect, insertWorkflowRegistrationRawDirect, insertWorkflowRegistrationStrictDirect, isSchemaCurrent, isSchemaCurrentFromFilesDirect, latestExecutionRunByStatusDirect, listActiveGenericWebhookSourcesDirect, listActivePeerCredentialsExcludingDirect, listCrossRepoTrustBySourceRoutingKeyDirect, listEnvironmentsDirect, listExecutionJobsDirect, listExecutionRunsDirect, listKiciEventsDirect, listQueueDirect, listRegistrationsByRoutingKeyDirect, listRegistrationsDirect, maskDatabaseUrl, parseDatabaseUrl, platformConnectionExistsDirect, pollKiciEventsDirect, prunePeerCredentialsDirect, purgeScopedSecretsDirect, purgeSecretBackendsDirect, purgeStaleExecutionDirect, purgeStaleSourcesDirect, readStoredMigrationContentHash, registerWorkflowManualDirect, resetRaftStateDirect, resolvePlatformWebhookSourceRoutingKeyDirect, restoreSoftDeletedGenericWebhookSourceDirect, seedApiKeyInlineDirect, seedCiSecurityFixturesDirect, seedCrossRepoTrustDirect, seedEnvironmentBindingDirect, seedEnvironmentDirect, seedGenericWebhookSourceDirect, seedSourcePrivateKeyDirect, seedSyntheticGithubSourceDirect, seedUniversalGitSourceDirect, seedWebhookSecretDirect, setEnvironmentPolicyDirect, setEnvironmentSecretDirect, showEnvironmentDirect, showExecutionRunDirect, showKiciEventDirect, showQueueEntryDirect, showRegistrationDirect, storeMigrationContentHash, storeMigrationContentHashInTableDirect, tableExistsDirect, updateGenericWebhookVerificationConfigDirect, updateOrgSettingsDeniedReposDirect, updateSourceRoutingKeyDirect, updateWorkflowRegistrationCommitShaDirect, upsertCronLastFiredDirect, upsertOrgSettingsGlobalWorkflowsDirect, verifyKiciEventNotifyDirect, waitForEventLogRowByDeliveryIdDirect, waitForExecutionRunStatusSinceDirect, waitForLatestExecutionJobStatusDirect, waitForPlatformEventLogDistinctRoutedDirect, waitForPlatformExecutionRunStatusDirect, waitForPlatformRegistrationsDirect, waitForPostgresDirect, waitForRegistrationsByRoutingKeyDirect, waitForRegistrationsUpdatedAtAdvanceDirect, waitForRunCompletionDirect } from "./db-admin.js";
3
+ import { MIGRATION_HASH_TABLE, REGISTERABLE_TRIGGER_TYPES, apiKeyExistsDirect, bumpRegistryVersionDirect, bumpRegistryVersionSimpleDirect, cleanupExecutionRowsDirect, clearDispatchQueueDirect, clearPeerCredentialsRevokedAtByIdsDirect, computeMigrationsHash, countActivePeerCredentialsByInstanceDirect, countCronLastFiredDirect, countHeldRunsByRunIdDirect, countWebhookSourcesByConnectionIdDirect, createDbRole, createEnvironmentTemplateDirect, createJoinTokenDirect, createReadOnlyDbUser, deleteCronLastFiredDirect, deleteCrossRepoTrustDirect, deleteEnvironmentDirect, deleteExecutionRunsByWorkflowNameDirect, deleteGenericWebhookSourcesByNameDirect, deleteKiciEventsDirect, deleteOrgSettingsByCustomerIdDirect, deletePeerCredentialsByInstanceIdLikeDirect, deleteWorkflowRegistrationsDirect, describeTableColumnsDirect, dropAndCreateDatabase, dropDatabaseDirect, emitKiciEventDirect, ensureDatabase, ensureOrgOwnerMemberDirect, findAnyUserApiKeyIdDirect, getExecutionRunSecurityDirect, getGenericWebhookSourceByRoutingKeyDirect, getHeldRunByIdDirect, getPeerCredentialRevokedAtDirect, getRegistryVersionDirect, getWebhookSourceByRoutingKeyDirect, getWorkflowRegistrationByIdDirect, insertCronLastFiredNowDirect, insertCrossRepoTrustStrictDirect, insertKiciEventRawDirect, insertPeerCredentialExpiredDirect, insertWorkflowRegistrationRawDirect, insertWorkflowRegistrationStrictDirect, isSchemaCurrent, isSchemaCurrentFromFilesDirect, latestExecutionRunByStatusDirect, listActiveGenericWebhookSourcesDirect, listActivePeerCredentialsExcludingDirect, listCrossRepoTrustBySourceRoutingKeyDirect, listEnvironmentsDirect, listExecutionJobsDirect, listExecutionRunsDirect, listKiciEventsDirect, listQueueDirect, listRegistrationsByRoutingKeyDirect, listRegistrationsDirect, maskDatabaseUrl, parseDatabaseUrl, platformConnectionExistsDirect, pollKiciEventsDirect, prunePeerCredentialsDirect, purgeScopedSecretsDirect, purgeSecretBackendsDirect, purgeStaleExecutionDirect, purgeStaleSourcesDirect, readStoredMigrationContentHash, registerWorkflowManualDirect, resetRaftStateDirect, resolvePlatformWebhookSourceRoutingKeyDirect, restoreSoftDeletedGenericWebhookSourceDirect, seedApiKeyInlineDirect, seedCiSecurityFixturesDirect, seedCrossRepoTrustDirect, seedEnvironmentBindingDirect, seedEnvironmentDirect, seedGenericWebhookSourceDirect, seedSourcePrivateKeyDirect, seedSyntheticGithubSourceDirect, seedUniversalGitSourceDirect, seedWebhookSecretDirect, setEnvironmentPolicyDirect, setEnvironmentSecretDirect, showEnvironmentDirect, showExecutionRunDirect, showKiciEventDirect, showQueueEntryDirect, showRegistrationDirect, storeMigrationContentHash, storeMigrationContentHashInTableDirect, tableExistsDirect, terminateIdleDbBackendsDirect, updateGenericWebhookVerificationConfigDirect, updateOrgSettingsDeniedReposDirect, updateSourceRoutingKeyDirect, updateWorkflowRegistrationCommitShaDirect, upsertCronLastFiredDirect, upsertOrgSettingsGlobalWorkflowsDirect, verifyKiciEventNotifyDirect, waitForEventLogRowByDeliveryIdDirect, waitForExecutionRunStatusSinceDirect, waitForLatestExecutionJobStatusDirect, waitForPlatformEventLogDistinctRoutedDirect, waitForPlatformExecutionRunStatusDirect, waitForPlatformRegistrationsDirect, waitForPostgresDirect, waitForRegistrationsByRoutingKeyDirect, waitForRegistrationsUpdatedAtAdvanceDirect, waitForRunCompletionDirect } from "./db-admin.js";
4
4
  import { setupGracefulShutdown } from "./graceful-shutdown.js";
5
5
  import { RingBuffer } from "./ring-buffer.js";
6
6
  import { createMetricsRoutes } from "./routes/metrics.js";
@@ -22,4 +22,4 @@ import { ChunkLru } from "./cold-store/lru.js";
22
22
  import { DEFAULT_TABLE_CONFIG, resolveTableConfig } from "./cold-store/config.js";
23
23
  import "./cold-store/index.js";
24
24
  export * from "@kici-dev/core";
25
- export { BaseColdStore, COLD_BUCKET_NAMES, ChunkLru, DEFAULT_TABLE_CONFIG, MIGRATION_HASH_TABLE, REGISTERABLE_TRIGGER_TYPES, RingBuffer, apiKeyExistsDirect, bumpRegistryVersionDirect, bumpRegistryVersionSimpleDirect, chunkObjectKey, cleanupExecutionRowsDirect, clearDispatchQueueDirect, clearPeerCredentialsRevokedAtByIdsDirect, coldDaysToBucket, coldStoreArchiveBytesTotal, coldStoreArchiveCyclesTotal, coldStoreArchiveDurationSeconds, coldStoreArchiveRowsTotal, coldStorePurgeBytesTotal, coldStorePurgeChunksTotal, coldStorePurgeDurationSeconds, coldStoreRehydrateBytesTotal, coldStoreRehydrateDurationSeconds, coldStoreRehydrateRequestsTotal, coldStoreReplayDurationSeconds, coldStoreReplayRowsTotal, coldStoreVerifyFailuresTotal, collectRuntimeMetricNames, computeChunkId, computeMigrationsHash, countActivePeerCredentialsByInstanceDirect, countCronLastFiredDirect, countHeldRunsByRunIdDirect, countWebhookSourcesByConnectionIdDirect, createDb, createDbRole, createEnvironmentTemplateDirect, createHealthRoutes, createJoinTokenDirect, createMeter, createMetricsRoutes, createPool, createReadOnlyDbUser, createS3Client, decodeChunk, deleteCronLastFiredDirect, deleteCrossRepoTrustDirect, deleteExecutionRunsByWorkflowNameDirect, deleteGenericWebhookSourcesByNameDirect, deleteKiciEventsDirect, deleteOrgSettingsByCustomerIdDirect, deletePeerCredentialsByInstanceIdLikeDirect, deleteWorkflowRegistrationsDirect, describeTableColumnsDirect, dropAndCreateDatabase, dropDatabaseDirect, emitKiciEventDirect, encodeChunk, encodeKeySegment, ensureDatabase, ensureOrgOwnerMemberDirect, findAnyUserApiKeyIdDirect, getExecutionRunSecurityDirect, getGenericWebhookSourceByRoutingKeyDirect, getHeldRunByIdDirect, getPeerCredentialRevokedAtDirect, getPrometheusExporter, getReconnectDelay, getRegistryVersionDirect, getWebhookSourceByRoutingKeyDirect, getWorkflowRegistrationByIdDirect, initTelemetry, insertCronLastFiredNowDirect, insertCrossRepoTrustStrictDirect, insertKiciEventRawDirect, insertPeerCredentialExpiredDirect, insertWorkflowRegistrationRawDirect, insertWorkflowRegistrationStrictDirect, isLongerColdRetention, isSchemaCurrent, isSchemaCurrentFromFilesDirect, latestExecutionRunByStatusDirect, listActiveGenericWebhookSourcesDirect, listActivePeerCredentialsExcludingDirect, listCrossRepoTrustBySourceRoutingKeyDirect, listEnvironmentsDirect, listExecutionJobsDirect, listExecutionRunsDirect, listKiciEventsDirect, listQueueDirect, listRegistrationsByRoutingKeyDirect, listRegistrationsDirect, maskDatabaseUrl, parseDatabaseUrl, parseManifest, platformConnectionExistsDirect, pollKiciEventsDirect, prunePeerCredentialsDirect, purgeScopedSecretsDirect, purgeSecretBackendsDirect, purgeStaleExecutionDirect, purgeStaleSourcesDirect, readStoredMigrationContentHash, registerWorkflowManualDirect, resetRaftStateDirect, resolvePlatformWebhookSourceRoutingKeyDirect, resolveTableConfig, restoreSoftDeletedGenericWebhookSourceDirect, seedApiKeyInlineDirect, seedCiSecurityFixturesDirect, seedCrossRepoTrustDirect, seedEnvironmentBindingDirect, seedEnvironmentDirect, seedGenericWebhookSourceDirect, seedSourcePrivateKeyDirect, seedSyntheticGithubSourceDirect, seedUniversalGitSourceDirect, seedWebhookSecretDirect, serializeManifest, setEnvironmentPolicyDirect, setEnvironmentSecretDirect, setupGracefulShutdown, showEnvironmentDirect, showExecutionRunDirect, showKiciEventDirect, showQueueEntryDirect, showRegistrationDirect, storeMigrationContentHash, storeMigrationContentHashInTableDirect, tableExistsDirect, tablePrefix, tenantDayBucketPrefix, tenantDayPrefix, updateGenericWebhookVerificationConfigDirect, updateOrgSettingsDeniedReposDirect, updateSourceRoutingKeyDirect, updateWorkflowRegistrationCommitShaDirect, upsertCronLastFiredDirect, upsertOrgSettingsGlobalWorkflowsDirect, validateRequiredTools, verifyKiciEventNotifyDirect, waitForEventLogRowByDeliveryIdDirect, waitForExecutionRunStatusSinceDirect, waitForLatestExecutionJobStatusDirect, waitForPlatformEventLogDistinctRoutedDirect, waitForPlatformExecutionRunStatusDirect, waitForPlatformRegistrationsDirect, waitForPostgresDirect, waitForRegistrationsByRoutingKeyDirect, waitForRegistrationsUpdatedAtAdvanceDirect, waitForRunCompletionDirect };
25
+ export { BaseColdStore, COLD_BUCKET_NAMES, ChunkLru, DEFAULT_TABLE_CONFIG, MIGRATION_HASH_TABLE, REGISTERABLE_TRIGGER_TYPES, RingBuffer, apiKeyExistsDirect, bumpRegistryVersionDirect, bumpRegistryVersionSimpleDirect, chunkObjectKey, cleanupExecutionRowsDirect, clearDispatchQueueDirect, clearPeerCredentialsRevokedAtByIdsDirect, coldDaysToBucket, coldStoreArchiveBytesTotal, coldStoreArchiveCyclesTotal, coldStoreArchiveDurationSeconds, coldStoreArchiveRowsTotal, coldStorePurgeBytesTotal, coldStorePurgeChunksTotal, coldStorePurgeDurationSeconds, coldStoreRehydrateBytesTotal, coldStoreRehydrateDurationSeconds, coldStoreRehydrateRequestsTotal, coldStoreReplayDurationSeconds, coldStoreReplayRowsTotal, coldStoreVerifyFailuresTotal, collectRuntimeMetricNames, computeChunkId, computeMigrationsHash, countActivePeerCredentialsByInstanceDirect, countCronLastFiredDirect, countHeldRunsByRunIdDirect, countWebhookSourcesByConnectionIdDirect, createDb, createDbRole, createEnvironmentTemplateDirect, createHealthRoutes, createJoinTokenDirect, createMeter, createMetricsRoutes, createPool, createReadOnlyDbUser, createS3Client, decodeChunk, deleteCronLastFiredDirect, deleteCrossRepoTrustDirect, deleteEnvironmentDirect, deleteExecutionRunsByWorkflowNameDirect, deleteGenericWebhookSourcesByNameDirect, deleteKiciEventsDirect, deleteOrgSettingsByCustomerIdDirect, deletePeerCredentialsByInstanceIdLikeDirect, deleteWorkflowRegistrationsDirect, describeTableColumnsDirect, dropAndCreateDatabase, dropDatabaseDirect, emitKiciEventDirect, encodeChunk, encodeKeySegment, ensureDatabase, ensureOrgOwnerMemberDirect, findAnyUserApiKeyIdDirect, getExecutionRunSecurityDirect, getGenericWebhookSourceByRoutingKeyDirect, getHeldRunByIdDirect, getPeerCredentialRevokedAtDirect, getPrometheusExporter, getReconnectDelay, getRegistryVersionDirect, getWebhookSourceByRoutingKeyDirect, getWorkflowRegistrationByIdDirect, initTelemetry, insertCronLastFiredNowDirect, insertCrossRepoTrustStrictDirect, insertKiciEventRawDirect, insertPeerCredentialExpiredDirect, insertWorkflowRegistrationRawDirect, insertWorkflowRegistrationStrictDirect, isLongerColdRetention, isSchemaCurrent, isSchemaCurrentFromFilesDirect, latestExecutionRunByStatusDirect, listActiveGenericWebhookSourcesDirect, listActivePeerCredentialsExcludingDirect, listCrossRepoTrustBySourceRoutingKeyDirect, listEnvironmentsDirect, listExecutionJobsDirect, listExecutionRunsDirect, listKiciEventsDirect, listQueueDirect, listRegistrationsByRoutingKeyDirect, listRegistrationsDirect, maskDatabaseUrl, parseDatabaseUrl, parseManifest, platformConnectionExistsDirect, pollKiciEventsDirect, prunePeerCredentialsDirect, purgeScopedSecretsDirect, purgeSecretBackendsDirect, purgeStaleExecutionDirect, purgeStaleSourcesDirect, readStoredMigrationContentHash, registerWorkflowManualDirect, resetRaftStateDirect, resolvePlatformWebhookSourceRoutingKeyDirect, resolveTableConfig, restoreSoftDeletedGenericWebhookSourceDirect, seedApiKeyInlineDirect, seedCiSecurityFixturesDirect, seedCrossRepoTrustDirect, seedEnvironmentBindingDirect, seedEnvironmentDirect, seedGenericWebhookSourceDirect, seedSourcePrivateKeyDirect, seedSyntheticGithubSourceDirect, seedUniversalGitSourceDirect, seedWebhookSecretDirect, serializeManifest, setEnvironmentPolicyDirect, setEnvironmentSecretDirect, setupGracefulShutdown, showEnvironmentDirect, showExecutionRunDirect, showKiciEventDirect, showQueueEntryDirect, showRegistrationDirect, storeMigrationContentHash, storeMigrationContentHashInTableDirect, tableExistsDirect, tablePrefix, tenantDayBucketPrefix, tenantDayPrefix, terminateIdleDbBackendsDirect, updateGenericWebhookVerificationConfigDirect, updateOrgSettingsDeniedReposDirect, updateSourceRoutingKeyDirect, updateWorkflowRegistrationCommitShaDirect, upsertCronLastFiredDirect, upsertOrgSettingsGlobalWorkflowsDirect, validateRequiredTools, verifyKiciEventNotifyDirect, waitForEventLogRowByDeliveryIdDirect, waitForExecutionRunStatusSinceDirect, waitForLatestExecutionJobStatusDirect, waitForPlatformEventLogDistinctRoutedDirect, waitForPlatformExecutionRunStatusDirect, waitForPlatformRegistrationsDirect, waitForPostgresDirect, waitForRegistrationsByRoutingKeyDirect, waitForRegistrationsUpdatedAtAdvanceDirect, waitForRunCompletionDirect };
package/dist/s3-client.js CHANGED
@@ -13,7 +13,10 @@ import { S3Client } from "@aws-sdk/client-s3";
13
13
  * for cache-storage variants).
14
14
  */
15
15
  function createS3Client(options) {
16
- const config = {};
16
+ const config = {
17
+ requestChecksumCalculation: "WHEN_REQUIRED",
18
+ responseChecksumValidation: "WHEN_REQUIRED"
19
+ };
17
20
  if (options.region) config.region = options.region;
18
21
  if (options.endpoint) config.endpoint = options.endpoint;
19
22
  if (options.forcePathStyle !== void 0) config.forcePathStyle = options.forcePathStyle;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=s3-client.test.d.ts.map
package/package.json CHANGED
@@ -1,17 +1,21 @@
1
1
  {
2
2
  "name": "@kici-dev/shared",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "Shared utilities for the KiCI CI/CD stack — logging, zx setup, crypto, telemetry, health and metrics routes. No business logic.",
5
5
  "keywords": [
6
- "kici",
7
6
  "ci",
8
- "cd",
9
- "ci-cd",
7
+ "cicd",
8
+ "continuous-integration",
10
9
  "typescript",
11
- "workflows",
12
- "devops",
10
+ "workflow",
13
11
  "utilities"
14
12
  ],
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/kici-dev/kici-public.git",
16
+ "directory": "packages/shared"
17
+ },
18
+ "bugs": "https://github.com/kici-dev/kici-public/issues",
15
19
  "homepage": "https://kici.dev",
16
20
  "author": {
17
21
  "name": "KiCI",
@@ -96,7 +100,7 @@
96
100
  "yaml": "^2.8.3",
97
101
  "zod": "^4.3.6",
98
102
  "zx": "^8.8.5",
99
- "@kici-dev/core": "0.1.14"
103
+ "@kici-dev/core": "0.1.15"
100
104
  },
101
105
  "devDependencies": {
102
106
  "@opentelemetry/sdk-trace-base": "^2.7.0",
package/sbom.spdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "spdxVersion": "SPDX-2.3",
3
3
  "dataLicense": "CC0-1.0",
4
4
  "SPDXID": "SPDXRef-DOCUMENT",
5
- "name": "@kici-dev/shared@0.1.14",
6
- "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fshared/0.1.14/a35018ec-f363-4930-96e3-4e308475eca8",
5
+ "name": "@kici-dev/shared@0.1.15",
6
+ "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fshared/0.1.15/16314d47-0e1a-4be8-bddc-5605b523d24d",
7
7
  "creationInfo": {
8
- "created": "2026-05-30T03:05:47Z",
8
+ "created": "2026-06-11T03:03:13Z",
9
9
  "creators": [
10
10
  "Tool: kici-sbom-generator"
11
11
  ]
@@ -945,9 +945,9 @@
945
945
  "homepage": "https://js-sdsl.org"
946
946
  },
947
947
  {
948
- "SPDXID": "SPDXRef-Package--kici-dev-core-0.1.14",
948
+ "SPDXID": "SPDXRef-Package--kici-dev-core-0.1.15",
949
949
  "name": "@kici-dev/core",
950
- "versionInfo": "0.1.14",
950
+ "versionInfo": "0.1.15",
951
951
  "downloadLocation": "NOASSERTION",
952
952
  "filesAnalyzed": false,
953
953
  "licenseConcluded": "NOASSERTION",
@@ -958,7 +958,7 @@
958
958
  {
959
959
  "referenceCategory": "PACKAGE-MANAGER",
960
960
  "referenceType": "purl",
961
- "referenceLocator": "pkg:npm/%40kici-dev/core@0.1.14"
961
+ "referenceLocator": "pkg:npm/%40kici-dev/core@0.1.15"
962
962
  }
963
963
  ],
964
964
  "description": "Light shared utilities for the KiCI stack (logging, errors, formatting, crypto, zx init, the TypeScript ESM loader hook). No server-side dependencies.",
@@ -967,7 +967,7 @@
967
967
  {
968
968
  "SPDXID": "SPDXRef-RootPackage",
969
969
  "name": "@kici-dev/shared",
970
- "versionInfo": "0.1.14",
970
+ "versionInfo": "0.1.15",
971
971
  "downloadLocation": "NOASSERTION",
972
972
  "filesAnalyzed": false,
973
973
  "licenseConcluded": "NOASSERTION",
@@ -978,7 +978,7 @@
978
978
  {
979
979
  "referenceCategory": "PACKAGE-MANAGER",
980
980
  "referenceType": "purl",
981
- "referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.14"
981
+ "referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.15"
982
982
  }
983
983
  ],
984
984
  "description": "Shared utilities for the KiCI CI/CD stack — logging, zx setup, crypto, telemetry, health and metrics routes. No business logic.",
@@ -6442,32 +6442,32 @@
6442
6442
  "relationshipType": "DEPENDS_ON"
6443
6443
  },
6444
6444
  {
6445
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
6445
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.15",
6446
6446
  "relatedSpdxElement": "SPDXRef-Package-oxc-transform-0.128.0",
6447
6447
  "relationshipType": "DEPENDS_ON"
6448
6448
  },
6449
6449
  {
6450
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
6450
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.15",
6451
6451
  "relatedSpdxElement": "SPDXRef-Package-picocolors-1.1.1",
6452
6452
  "relationshipType": "DEPENDS_ON"
6453
6453
  },
6454
6454
  {
6455
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
6455
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.15",
6456
6456
  "relatedSpdxElement": "SPDXRef-Package-winston-daily-rotate-file-5.0.0",
6457
6457
  "relationshipType": "DEPENDS_ON"
6458
6458
  },
6459
6459
  {
6460
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
6460
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.15",
6461
6461
  "relatedSpdxElement": "SPDXRef-Package-winston-3.19.0",
6462
6462
  "relationshipType": "DEPENDS_ON"
6463
6463
  },
6464
6464
  {
6465
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
6465
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.15",
6466
6466
  "relatedSpdxElement": "SPDXRef-Package-zod-4.3.6",
6467
6467
  "relationshipType": "DEPENDS_ON"
6468
6468
  },
6469
6469
  {
6470
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
6470
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.15",
6471
6471
  "relatedSpdxElement": "SPDXRef-Package-zx-8.8.5",
6472
6472
  "relationshipType": "DEPENDS_ON"
6473
6473
  },
@@ -6478,7 +6478,7 @@
6478
6478
  },
6479
6479
  {
6480
6480
  "spdxElementId": "SPDXRef-RootPackage",
6481
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.14",
6481
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.15",
6482
6482
  "relationshipType": "DEPENDS_ON"
6483
6483
  },
6484
6484
  {