target-supabase-sdk 0.2.13 → 0.2.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.
Files changed (81) hide show
  1. package/README.md +11 -0
  2. package/dist/browser.d.ts +1 -0
  3. package/dist/browser.d.ts.map +1 -1
  4. package/dist/browser.js +1 -1
  5. package/dist/chunks/{enable-DqnfLPsQ.js → enable-C7lFooTG.js} +2 -2
  6. package/dist/chunks/{enable-DqnfLPsQ.js.map → enable-C7lFooTG.js.map} +1 -1
  7. package/dist/chunks/{task-queue-6X3aglJh.js → task-queue-DCY_0Qj0.js} +32 -3
  8. package/dist/chunks/task-queue-DCY_0Qj0.js.map +1 -0
  9. package/dist/node/env/index.d.ts +1 -1
  10. package/dist/node/env/index.d.ts.map +1 -1
  11. package/dist/node/node-runtime.base.d.ts +14 -1
  12. package/dist/node/node-runtime.base.d.ts.map +1 -1
  13. package/dist/node/node.api.d.ts.map +1 -1
  14. package/dist/node/node.constant.d.ts +3 -0
  15. package/dist/node/node.constant.d.ts.map +1 -0
  16. package/dist/node/node.utils.d.ts +0 -2
  17. package/dist/node/node.utils.d.ts.map +1 -1
  18. package/dist/node/readiness/index.d.ts +2 -0
  19. package/dist/node/readiness/index.d.ts.map +1 -1
  20. package/dist/node/{service-guard → readiness}/run-readiness-gate.d.ts +1 -1
  21. package/dist/node/readiness/run-readiness-gate.d.ts.map +1 -0
  22. package/dist/node/readiness/service-ready-gate.d.ts.map +1 -1
  23. package/dist/node/runtime-state/create-service-runtime-state-store.d.ts.map +1 -1
  24. package/dist/node/runtime-state/service-runtime-state.types.d.ts +16 -0
  25. package/dist/node/runtime-state/service-runtime-state.types.d.ts.map +1 -1
  26. package/dist/node/service-guard/index.d.ts +4 -4
  27. package/dist/node/service-guard/index.d.ts.map +1 -1
  28. package/dist/node/service-guard/register-service-guard-runner.d.ts +1 -2
  29. package/dist/node/service-guard/register-service-guard-runner.d.ts.map +1 -1
  30. package/dist/node/service-guard/registry-slot-guard-step.d.ts.map +1 -0
  31. package/dist/node/service-guard/run-service-guard-tick.d.ts.map +1 -1
  32. package/dist/node/service-guard/service-guard-node.d.ts +25 -2
  33. package/dist/node/service-guard/service-guard-node.d.ts.map +1 -1
  34. package/dist/node/service-guard/service-guard.interface.d.ts +25 -10
  35. package/dist/node/service-guard/service-guard.interface.d.ts.map +1 -1
  36. package/dist/node/service-host/claim-registry-slot.d.ts +15 -0
  37. package/dist/node/service-host/claim-registry-slot.d.ts.map +1 -0
  38. package/dist/node/service-host/create-l3-child-launcher.d.ts +38 -0
  39. package/dist/node/service-host/create-l3-child-launcher.d.ts.map +1 -0
  40. package/dist/node/service-host/index.d.ts +2 -5
  41. package/dist/node/service-host/index.d.ts.map +1 -1
  42. package/dist/node/service-host/service-host.d.ts +3 -3
  43. package/dist/node/service-host/service-host.d.ts.map +1 -1
  44. package/dist/node/service-host/single-process-service.d.ts +3 -3
  45. package/dist/node/service-host/single-process-service.d.ts.map +1 -1
  46. package/dist/node.d.ts +8 -6
  47. package/dist/node.d.ts.map +1 -1
  48. package/dist/node.js +627 -264
  49. package/dist/node.js.map +1 -1
  50. package/dist/preload.js +1 -1
  51. package/dist/shared/utils/postgrest.utils.d.ts +23 -0
  52. package/dist/shared/utils/postgrest.utils.d.ts.map +1 -0
  53. package/package.json +1 -1
  54. package/src/browser.ts +1 -0
  55. package/src/node/env/index.ts +0 -4
  56. package/src/node/node-runtime.base.ts +33 -5
  57. package/src/node/node.api.ts +1 -1
  58. package/src/node/node.constant.ts +2 -0
  59. package/src/node/node.utils.ts +2 -2
  60. package/src/node/readiness/index.ts +2 -0
  61. package/src/node/{service-guard → readiness}/run-readiness-gate.ts +2 -2
  62. package/src/node/readiness/service-ready-gate.ts +27 -23
  63. package/src/node/runtime-state/create-service-runtime-state-store.ts +11 -0
  64. package/src/node/runtime-state/service-runtime-state.types.ts +12 -0
  65. package/src/node/service-guard/index.ts +7 -8
  66. package/src/node/service-guard/register-service-guard-runner.ts +0 -2
  67. package/src/node/service-guard/run-service-guard-tick.ts +5 -2
  68. package/src/node/service-guard/service-guard-node.ts +229 -6
  69. package/src/node/service-guard/service-guard.interface.ts +35 -10
  70. package/src/node/service-host/claim-registry-slot.ts +33 -0
  71. package/src/node/service-host/create-l3-child-launcher.ts +157 -0
  72. package/src/node/service-host/index.ts +5 -24
  73. package/src/node/service-host/service-host.ts +11 -18
  74. package/src/node/service-host/single-process-service.ts +10 -20
  75. package/src/node.ts +21 -18
  76. package/src/shared/utils/postgrest.utils.ts +28 -0
  77. package/dist/chunks/task-queue-6X3aglJh.js.map +0 -1
  78. package/dist/node/service-guard/run-readiness-gate.d.ts.map +0 -1
  79. package/dist/node/service-host/registry-slot-guard-step.d.ts.map +0 -1
  80. /package/dist/node/{service-host → service-guard}/registry-slot-guard-step.d.ts +0 -0
  81. /package/src/node/{service-host → service-guard}/registry-slot-guard-step.ts +0 -0
@@ -1,8 +1,8 @@
1
- import type { Node } from "../../node/node.interface";
2
1
  import type { RegistrySlotRuntimeState } from "../../service/registry-lifecycle";
3
2
  import type { LoggerWithScope } from "../../shared/log";
4
- import type { TriggerNodeOptions } from "../../trigger/trigger.interface";
3
+ import type { Node } from "../node.interface";
5
4
  import type { ReadinessCheck, ReadinessReport } from "../readiness/readiness.types";
5
+ import type { GuardRuntimeSlice } from "../runtime-state/service-runtime-state.types";
6
6
 
7
7
  /** Default TriggerManager runner key for {@link registerServiceGuardRunner}. */
8
8
  export const SERVICE_GUARD_RUNNER_KEY = "service-guard";
@@ -45,20 +45,45 @@ export interface RegisterServiceGuardRunnerOptions {
45
45
  onRegistryPatch: (
46
46
  patch: Pick<RegistrySlotRuntimeState, "slotOwned" | "lastSlotCheckAt" | "lastSlotCheckError">,
47
47
  ) => Promise<void>;
48
- onGuardPatch: (patch: { nodeId: string; lastCheckAt: string; lastDecision?: string }) => Promise<void>;
48
+ onGuardPatch: (patch: Partial<GuardRuntimeSlice>) => Promise<void>;
49
49
  onDecision?: (decision: string) => Promise<void>;
50
50
  }
51
51
 
52
- export interface ServiceGuardNodeOptions extends TriggerNodeOptions {
52
+ export interface ServiceGuardNodeOptions {
53
53
  serviceValue: string;
54
54
  logTopic?: string;
55
55
  readinessChecks: ReadinessCheck[];
56
56
  onReadinessReport: (report: ReadinessReport) => Promise<void>;
57
- guardRunner: Omit<
58
- RegisterServiceGuardRunnerOptions,
59
- "serviceValue" | "logTopic" | "runnerKey" | "intervalMs" | "initialDelayMs"
60
- > &
61
- Pick<RegisterServiceGuardRunnerOptions, "intervalMs" | "initialDelayMs">;
62
- spawnWorker: (reason: string) => Promise<void>;
57
+ guardRunner: Omit<RegisterServiceGuardRunnerOptions, "serviceValue" | "logTopic" | "runnerKey" | "spawnWorker">;
58
+ /**
59
+ * Idempotent spawn of all business nodes (scheduler + worker, etc.).
60
+ * Used at bootstrap, silent recovery, and healthy-mode TaskNode respawn.
61
+ */
62
+ spawnBusinessNodes: (reason: string) => Promise<void>;
63
+ /** Stop business nodes only (never the guard process). */
64
+ stopBusinessNodes: () => Promise<void>;
65
+ /** Local runtime gate: all business nodes registered and ready. */
66
+ isBusinessReady: () => Promise<boolean>;
67
+ /** Timeout for {@link isBusinessReady} during bootstrap and recovery. Default 180s. */
68
+ businessReadyTimeoutMs?: number;
69
+ /** Extra hook after the initial business spawn (cooldown is recorded automatically). */
63
70
  onWorkerSpawned?: () => void;
71
+ beforeProcessExit?: () => void | Promise<void>;
72
+ }
73
+
74
+ /** True when the guard slice is serving traffic (`mode` omitted = legacy healthy). */
75
+ export function isGuardAvailable(guard: Pick<GuardRuntimeSlice, "mode">): boolean {
76
+ return guard.mode == null || guard.mode === "healthy";
77
+ }
78
+
79
+ /**
80
+ * Seconds for `Retry-After` when the guard is not serving traffic.
81
+ * `null` when {@link isGuardAvailable} is true.
82
+ */
83
+ export function guardRetryAfterSec(guard: Pick<GuardRuntimeSlice, "mode" | "silentBackoffMs">): number | null {
84
+ if (isGuardAvailable(guard)) {
85
+ return null;
86
+ }
87
+ const backoffMs = guard.silentBackoffMs > 0 ? guard.silentBackoffMs : 15_000;
88
+ return Math.max(1, Math.ceil(backoffMs / 1000));
64
89
  }
@@ -0,0 +1,33 @@
1
+ import { ServiceRegistryError } from "../../service/registry.service";
2
+ import { claimServiceRegistrySlot, type ServiceRegistrySession } from "../../service/registry-lifecycle";
3
+ import type { Service } from "../../service/service.interface";
4
+ import type { LoggerWithScope } from "../../shared/log";
5
+
6
+ export interface ClaimRegistrySlotOrExitInput {
7
+ serviceValue: string;
8
+ createInstance: () => Promise<Service>;
9
+ logger: LoggerWithScope;
10
+ logTopic: string;
11
+ }
12
+
13
+ /**
14
+ * Claim a registry slot, or `process.exit(1)` when no EMPTY slot remains.
15
+ * Other errors propagate.
16
+ */
17
+ export async function claimRegistrySlotOrExit(input: ClaimRegistrySlotOrExitInput): Promise<ServiceRegistrySession> {
18
+ try {
19
+ return await claimServiceRegistrySlot({
20
+ serviceValue: input.serviceValue,
21
+ createInstance: input.createInstance,
22
+ });
23
+ } catch (error) {
24
+ if (error instanceof ServiceRegistryError && error.code === "SERVICE_SLOTS_FULL") {
25
+ input.logger.critical("No EMPTY registry slot — refusing to start", {
26
+ topic: input.logTopic,
27
+ data: { serviceValue: input.serviceValue, code: error.code },
28
+ });
29
+ process.exit(1);
30
+ }
31
+ throw error;
32
+ }
33
+ }
@@ -0,0 +1,157 @@
1
+ import type { ChildProcess } from "node:child_process";
2
+ import type { ManagedChildProcesses } from "../process/managed-child-processes";
3
+ import type {
4
+ GuardRuntimeSlice,
5
+ SchedulerRuntimeSlice,
6
+ WorkerRuntimeSlice,
7
+ } from "../runtime-state/service-runtime-state.types";
8
+
9
+ const WORKER_SCRIPT = "./dist/processes/worker.js";
10
+ const GUARD_SCRIPT = "./dist/processes/guard.js";
11
+ const SCHEDULER_SCRIPT = "./dist/processes/scheduler.js";
12
+
13
+ export interface L3ChildLauncherRuntimeStore {
14
+ readRuntimeState(): Promise<{
15
+ worker: WorkerRuntimeSlice;
16
+ scheduler: SchedulerRuntimeSlice;
17
+ guard: GuardRuntimeSlice;
18
+ }>;
19
+ writeRuntimeState(patch: {
20
+ worker?: Partial<WorkerRuntimeSlice>;
21
+ scheduler?: Partial<SchedulerRuntimeSlice>;
22
+ guard?: Partial<GuardRuntimeSlice>;
23
+ }): Promise<unknown>;
24
+ }
25
+
26
+ export interface CreateL3ChildLauncherOptions {
27
+ childProcesses: ManagedChildProcesses;
28
+ readRuntimeState: L3ChildLauncherRuntimeStore["readRuntimeState"];
29
+ writeRuntimeState: L3ChildLauncherRuntimeStore["writeRuntimeState"];
30
+ /** Merged onto the child env. Default: `{ LOG_PERSIST_PROCESS: label }`. */
31
+ spawnEnv?: (label: string) => Record<string, string>;
32
+ }
33
+
34
+ export interface L3ChildLauncher {
35
+ spawnGuard: () => ChildProcess;
36
+ spawnTaskWorker: (reason: string) => Promise<ChildProcess>;
37
+ spawnScheduler: (reason: string) => Promise<ChildProcess>;
38
+ spawnBusinessNodes: (reason: string) => Promise<void>;
39
+ stopBusinessNodes: () => Promise<void>;
40
+ isBusinessReady: () => Promise<boolean>;
41
+ stopChildProcesses: () => Promise<void>;
42
+ }
43
+
44
+ function defaultSpawnEnv(label: string): Record<string, string> {
45
+ return { LOG_PERSIST_PROCESS: label };
46
+ }
47
+
48
+ /**
49
+ * Guard-owned scheduler + worker spawn/stop, plus main-owned Guard spawn.
50
+ * `stopBusinessNodes` must run in the Guard process (that instance's children only).
51
+ * `stopChildProcesses` is for main shutdown (`extraPids` for Guard-spawned PIDs).
52
+ */
53
+ export function createL3ChildLauncher(options: CreateL3ChildLauncherOptions): L3ChildLauncher {
54
+ const { childProcesses, readRuntimeState, writeRuntimeState } = options;
55
+ const spawnEnv = options.spawnEnv ?? defaultSpawnEnv;
56
+
57
+ function nowIso(): string {
58
+ return new Date().toISOString();
59
+ }
60
+
61
+ async function spawnTaskWorker(reason: string): Promise<ChildProcess> {
62
+ const { child, created } = childProcesses.spawn("worker", WORKER_SCRIPT, {
63
+ env: spawnEnv("worker"),
64
+ });
65
+ if (!created) {
66
+ return child;
67
+ }
68
+
69
+ const current = await readRuntimeState();
70
+ await writeRuntimeState({
71
+ worker: {
72
+ pid: child.pid ?? null,
73
+ spawnedAt: nowIso(),
74
+ ready: false,
75
+ registeredTasks: [],
76
+ readyAt: null,
77
+ },
78
+ guard: {
79
+ lastSpawnAt: nowIso(),
80
+ lastDecision: reason,
81
+ spawnCount: current.guard.spawnCount + 1,
82
+ },
83
+ });
84
+
85
+ return child;
86
+ }
87
+
88
+ function spawnGuard(): ChildProcess {
89
+ return childProcesses.spawn("guard", GUARD_SCRIPT, { env: spawnEnv("guard") }).child;
90
+ }
91
+
92
+ async function spawnScheduler(reason: string): Promise<ChildProcess> {
93
+ const { child, created } = childProcesses.spawn("scheduler", SCHEDULER_SCRIPT, {
94
+ env: spawnEnv("scheduler"),
95
+ });
96
+ if (!created) {
97
+ return child;
98
+ }
99
+
100
+ await writeRuntimeState({
101
+ scheduler: {
102
+ pid: child.pid ?? null,
103
+ spawnedAt: nowIso(),
104
+ ready: false,
105
+ readyAt: null,
106
+ },
107
+ guard: {
108
+ lastDecision: reason,
109
+ },
110
+ });
111
+
112
+ return child;
113
+ }
114
+
115
+ async function spawnBusinessNodes(reason: string): Promise<void> {
116
+ await spawnScheduler(reason);
117
+ await spawnTaskWorker(reason);
118
+ }
119
+
120
+ async function stopBusinessNodes(): Promise<void> {
121
+ await childProcesses.stopAll();
122
+ await writeRuntimeState({
123
+ worker: {
124
+ pid: null,
125
+ ready: false,
126
+ readyAt: null,
127
+ registeredTasks: [],
128
+ },
129
+ scheduler: {
130
+ pid: null,
131
+ ready: false,
132
+ readyAt: null,
133
+ },
134
+ });
135
+ }
136
+
137
+ async function isBusinessReady(): Promise<boolean> {
138
+ const state = await readRuntimeState();
139
+ return state.worker.ready && state.scheduler.ready;
140
+ }
141
+
142
+ async function stopChildProcesses(): Promise<void> {
143
+ const state = await readRuntimeState();
144
+ const extraPids = [state.worker.pid, state.scheduler.pid].filter((pid): pid is number => pid != null);
145
+ await childProcesses.stopAll({ extraPids });
146
+ }
147
+
148
+ return {
149
+ spawnGuard,
150
+ spawnTaskWorker,
151
+ spawnScheduler,
152
+ spawnBusinessNodes,
153
+ stopBusinessNodes,
154
+ isBusinessReady,
155
+ stopChildProcesses,
156
+ };
157
+ }
@@ -1,28 +1,9 @@
1
- export {
2
- COLLECT_LOG_RUNNER_KEY,
3
- registerCollectLogRunner,
4
- } from "../../shared/log/spool/register-collect-log-runner";
5
1
  export type {
6
- RegisterServiceGuardRunnerOptions,
7
- RunReadinessGateInput,
8
- ServiceGuardNodeOptions,
9
- ServiceGuardTickInput,
10
- ServiceGuardTickResult,
11
- } from "../service-guard";
12
- export {
13
- getWorkerSpawnCooldownLastAt,
14
- markWorkerSpawned,
15
- registerServiceGuardRunner,
16
- runReadinessGate,
17
- runServiceGuardTick,
18
- SERVICE_GUARD_RUNNER_KEY,
19
- ServiceGuardNode,
20
- } from "../service-guard";
21
- export type {
22
- ApplyRegistrySlotGuardInput,
23
- ApplyRegistrySlotGuardResult,
24
- } from "./registry-slot-guard-step";
25
- export { applyRegistrySlotGuardStep } from "./registry-slot-guard-step";
2
+ CreateL3ChildLauncherOptions,
3
+ L3ChildLauncher,
4
+ L3ChildLauncherRuntimeStore,
5
+ } from "./create-l3-child-launcher";
6
+ export { createL3ChildLauncher } from "./create-l3-child-launcher";
26
7
  export type {
27
8
  ServiceHost,
28
9
  ServiceHostClosable,
@@ -1,10 +1,12 @@
1
- import { createLogger, type Service, ServiceRegistryError } from "../../browser";
2
- import { claimServiceRegistrySlot, type ServiceRegistrySession } from "../../service/registry-lifecycle";
3
- import type { LoggerWithScope } from "../../shared/log";
1
+ import { ServiceRegistryError } from "../../service/registry.service";
2
+ import type { ServiceRegistrySession } from "../../service/registry-lifecycle";
3
+ import type { Service } from "../../service/service.interface";
4
+ import { createLogger, type LoggerWithScope } from "../../shared/log";
4
5
  import { LOG_SPOOL_SERVICE_ID_ENV } from "../../shared/log/spool/config";
5
6
  import { ensureLogSpoolFromEnv } from "../../shared/log/spool/enable";
6
7
  import { logSpoolEnabledFromEnv } from "../../shared/log/upload/env";
7
8
  import type { ManagedChildProcesses } from "../process/managed-child-processes";
9
+ import { claimRegistrySlotOrExit } from "./claim-registry-slot";
8
10
 
9
11
  export interface ServiceHostClosable {
10
12
  close: () => Promise<void>;
@@ -112,21 +114,12 @@ export function createServiceHost(options: ServiceHostOptions): ServiceHost {
112
114
  await options.prepare();
113
115
  }
114
116
 
115
- try {
116
- session = await claimServiceRegistrySlot({
117
- serviceValue: options.serviceValue,
118
- createInstance: async () => unwrapService(await options.createInstance()),
119
- });
120
- } catch (error) {
121
- if (error instanceof ServiceRegistryError && error.code === "SERVICE_SLOTS_FULL") {
122
- logger.critical("No EMPTY registry slot — refusing to start", {
123
- topic: logTopic,
124
- data: { serviceValue: options.serviceValue, code: error.code },
125
- });
126
- process.exit(1);
127
- }
128
- throw error;
129
- }
117
+ session = await claimRegistrySlotOrExit({
118
+ serviceValue: options.serviceValue,
119
+ createInstance: async () => unwrapService(await options.createInstance()),
120
+ logger,
121
+ logTopic,
122
+ });
130
123
 
131
124
  const hostCtx: ServiceHostContext = { service: session.service, session, serviceId: session.service.id };
132
125
 
@@ -1,6 +1,7 @@
1
- import { createLogger, type Service, ServiceRegistryError } from "../../browser";
2
- import { claimServiceRegistrySlot, type ServiceRegistrySession } from "../../service/registry-lifecycle";
3
- import type { LoggerWithScope } from "../../shared/log";
1
+ import type { ServiceRegistrySession } from "../../service/registry-lifecycle";
2
+ import type { Service } from "../../service/service.interface";
3
+ import { createLogger, type LoggerWithScope } from "../../shared/log";
4
+ import { claimRegistrySlotOrExit } from "./claim-registry-slot";
4
5
 
5
6
  export interface SingleProcessServiceContext {
6
7
  service: Service;
@@ -29,23 +30,12 @@ export async function runSingleProcessService(options: SingleProcessServiceOptio
29
30
  await options.prepare();
30
31
  }
31
32
 
32
- let session: ServiceRegistrySession | null = null;
33
-
34
- try {
35
- session = await claimServiceRegistrySlot({
36
- serviceValue: options.serviceValue,
37
- createInstance: options.createInstance,
38
- });
39
- } catch (error) {
40
- if (error instanceof ServiceRegistryError && error.code === "SERVICE_SLOTS_FULL") {
41
- logger.critical("No EMPTY registry slot — refusing to start", {
42
- topic: logTopic,
43
- data: { serviceValue: options.serviceValue, code: error.code },
44
- });
45
- process.exit(1);
46
- }
47
- throw error;
48
- }
33
+ const session = await claimRegistrySlotOrExit({
34
+ serviceValue: options.serviceValue,
35
+ createInstance: options.createInstance,
36
+ logger,
37
+ logTopic,
38
+ });
49
39
 
50
40
  try {
51
41
  await options.run({ service: session.service, session });
package/src/node.ts CHANGED
@@ -25,9 +25,6 @@ export {
25
25
  envProfileFromProcess,
26
26
  initSupabaseFromStandardEnv,
27
27
  loadEnvFiles,
28
- parseEnvFile,
29
- parseEnvLine,
30
- pinEnvProfileFromArgv,
31
28
  publicBaseUrlFromEnv,
32
29
  readEnv,
33
30
  requireEnv,
@@ -77,6 +74,7 @@ export type {
77
74
  ReadinessCheckResult,
78
75
  ReadinessReport,
79
76
  RequiredEnvCheckOptions,
77
+ RunReadinessGateInput,
80
78
  ServiceReadyGate,
81
79
  ServiceReadySnapshot,
82
80
  SupabaseReachableCheckOptions,
@@ -88,6 +86,7 @@ export {
88
86
  createSupabaseReachableCheck,
89
87
  pollUntil,
90
88
  runReadinessChecks,
89
+ runReadinessGate,
91
90
  waitForServiceReady,
92
91
  } from "./node/readiness";
93
92
  export type {
@@ -109,31 +108,32 @@ export type {
109
108
  ApplyRegistrySlotGuardInput,
110
109
  ApplyRegistrySlotGuardResult,
111
110
  RegisterServiceGuardRunnerOptions,
112
- RunReadinessGateInput,
113
111
  ServiceGuardNodeOptions,
114
112
  ServiceGuardTickInput,
115
113
  ServiceGuardTickResult,
116
- ServiceHost,
117
- ServiceHostClosable,
118
- ServiceHostContext,
119
- ServiceHostOptions,
120
- SingleProcessServiceContext,
121
- SingleProcessServiceOptions,
122
- } from "./node/service-host";
114
+ } from "./node/service-guard";
123
115
  export {
124
116
  applyRegistrySlotGuardStep,
125
- COLLECT_LOG_RUNNER_KEY,
126
- createServiceHost,
127
- getWorkerSpawnCooldownLastAt,
117
+ guardRetryAfterSec,
118
+ isGuardAvailable,
128
119
  markWorkerSpawned,
129
- registerCollectLogRunner,
130
120
  registerServiceGuardRunner,
131
- runReadinessGate,
132
121
  runServiceGuardTick,
133
- runSingleProcessService,
134
122
  SERVICE_GUARD_RUNNER_KEY,
135
123
  ServiceGuardNode,
124
+ } from "./node/service-guard";
125
+ export type {
126
+ CreateL3ChildLauncherOptions,
127
+ L3ChildLauncher,
128
+ L3ChildLauncherRuntimeStore,
129
+ ServiceHost,
130
+ ServiceHostClosable,
131
+ ServiceHostContext,
132
+ ServiceHostOptions,
133
+ SingleProcessServiceContext,
134
+ SingleProcessServiceOptions,
136
135
  } from "./node/service-host";
136
+ export { createL3ChildLauncher, createServiceHost, runSingleProcessService } from "./node/service-host";
137
137
  export { RepoManager } from "./repo/repo-manager";
138
138
  export { runCollectLogTick } from "./shared/log/spool/collector";
139
139
  export { LOG_SPOOL_SERVICE_ID_ENV } from "./shared/log/spool/config";
@@ -154,6 +154,10 @@ export type {
154
154
  LogSpoolWriterStats,
155
155
  } from "./shared/log/spool/interface";
156
156
  export { resolveLogSpoolRoot } from "./shared/log/spool/paths";
157
+ export {
158
+ COLLECT_LOG_RUNNER_KEY,
159
+ registerCollectLogRunner,
160
+ } from "./shared/log/spool/register-collect-log-runner";
157
161
  export {
158
162
  enableLogSpoolFromEnvInChild,
159
163
  getMainLogSpoolWriterStats,
@@ -177,7 +181,6 @@ export {
177
181
  resolvePathFromCwd,
178
182
  toFileImportHref,
179
183
  } from "./shared/utils/config-path.utils";
180
- export { getValueAtPath } from "./shared/utils/get-value-at-path";
181
184
  export type {
182
185
  BootstrapLocalTasksResult,
183
186
  BootstrapLocalTasksStatus,
@@ -0,0 +1,28 @@
1
+ /**
2
+ * PostgREST / Supabase JS client helpers for `target` table filters.
3
+ *
4
+ * @see `.cursor/skills/postgrest-query-filters/SKILL.md`
5
+ */
6
+
7
+ /**
8
+ * Escape `%`, `_`, and `\` for PostgREST `ilike` patterns.
9
+ * Also strips commas — they break `.or()` filter strings when multiple columns are searched.
10
+ */
11
+ export function escapeIlikePattern(raw: string): string {
12
+ return raw.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_").replace(/,/g, "");
13
+ }
14
+
15
+ /**
16
+ * Format a JS string array as a PostgreSQL `text[]` literal for PostgREST filter values.
17
+ *
18
+ * Required when tag values contain `:` or other special characters, and when using
19
+ * `.filter(column, "not.ov", literal)` — `.not("column", "ov", jsArray)` stringifies
20
+ * with `Array#toString()` and produces an invalid array literal.
21
+ *
22
+ * @example
23
+ * toPostgrestTextArrayLiteral(["stop-word:base", "small-word"])
24
+ * // → '{"stop-word:base","small-word"}'
25
+ */
26
+ export function toPostgrestTextArrayLiteral(values: readonly string[]): string {
27
+ return `{${values.map((v) => `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`).join(",")}}`;
28
+ }