target-supabase-sdk 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +24 -18
  2. package/dist/browser.d.ts +11 -4
  3. package/dist/browser.d.ts.map +1 -1
  4. package/dist/browser.js +3 -3
  5. package/dist/chunks/{enable-log-persist-C7GJo_Nc.js → enable-log-persist-B8rg_wXG.js} +5 -6
  6. package/dist/chunks/enable-log-persist-B8rg_wXG.js.map +1 -0
  7. package/dist/chunks/{create-logger-DyH3mZ8p.js → list.api-Ab9v8yOg.js} +66 -57
  8. package/dist/chunks/list.api-Ab9v8yOg.js.map +1 -0
  9. package/dist/chunks/{word.interface-DLgRobKV.js → word.interface-B_fbVFOW.js} +1078 -97
  10. package/dist/chunks/word.interface-B_fbVFOW.js.map +1 -0
  11. package/dist/extraction/extraction.api.d.ts +117 -0
  12. package/dist/extraction/extraction.api.d.ts.map +1 -0
  13. package/dist/extraction/extraction.interface.d.ts +43 -0
  14. package/dist/extraction/extraction.interface.d.ts.map +1 -0
  15. package/dist/list/list.interface.d.ts +2 -2
  16. package/dist/list/list.interface.d.ts.map +1 -1
  17. package/dist/node/node-runtime.base.d.ts +13 -1
  18. package/dist/node/node-runtime.base.d.ts.map +1 -1
  19. package/dist/node/process/create-managed-child-processes.d.ts +12 -0
  20. package/dist/node/process/create-managed-child-processes.d.ts.map +1 -0
  21. package/dist/node/process/index.d.ts +3 -1
  22. package/dist/node/process/index.d.ts.map +1 -1
  23. package/dist/node/process/managed-child-processes.d.ts +15 -2
  24. package/dist/node/process/managed-child-processes.d.ts.map +1 -1
  25. package/dist/node/runtime-state/create-service-runtime-state-store.d.ts +23 -0
  26. package/dist/node/runtime-state/create-service-runtime-state-store.d.ts.map +1 -0
  27. package/dist/node/runtime-state/index.d.ts +4 -0
  28. package/dist/node/runtime-state/index.d.ts.map +1 -0
  29. package/dist/node/runtime-state/service-runtime-state.types.d.ts +57 -0
  30. package/dist/node/runtime-state/service-runtime-state.types.d.ts.map +1 -0
  31. package/dist/node/service-guard/index.d.ts +9 -0
  32. package/dist/node/service-guard/index.d.ts.map +1 -0
  33. package/dist/node/service-guard/register-service-guard-runner.d.ts +9 -0
  34. package/dist/node/service-guard/register-service-guard-runner.d.ts.map +1 -0
  35. package/dist/node/service-guard/run-readiness-gate.d.ts +11 -0
  36. package/dist/node/service-guard/run-readiness-gate.d.ts.map +1 -0
  37. package/dist/node/service-guard/run-service-guard-tick.d.ts +7 -0
  38. package/dist/node/service-guard/run-service-guard-tick.d.ts.map +1 -0
  39. package/dist/node/service-guard/service-guard-node.d.ts +18 -0
  40. package/dist/node/service-guard/service-guard-node.d.ts.map +1 -0
  41. package/dist/node/service-guard/service-guard.interface.d.ts +58 -0
  42. package/dist/node/service-guard/service-guard.interface.d.ts.map +1 -0
  43. package/dist/node/service-guard/worker-spawn-cooldown.d.ts +4 -0
  44. package/dist/node/service-guard/worker-spawn-cooldown.d.ts.map +1 -0
  45. package/dist/node/service-host/index.d.ts +9 -0
  46. package/dist/node/service-host/index.d.ts.map +1 -0
  47. package/dist/node/service-host/registry-slot-guard-step.d.ts +21 -0
  48. package/dist/node/service-host/registry-slot-guard-step.d.ts.map +1 -0
  49. package/dist/node/service-host/service-host.d.ts +36 -0
  50. package/dist/node/service-host/service-host.d.ts.map +1 -0
  51. package/dist/node/service-host/single-process-service.d.ts +21 -0
  52. package/dist/node/service-host/single-process-service.d.ts.map +1 -0
  53. package/dist/node.d.ts +15 -2
  54. package/dist/node.d.ts.map +1 -1
  55. package/dist/node.js +2088 -1495
  56. package/dist/node.js.map +1 -1
  57. package/dist/preload.js +3 -3
  58. package/dist/service/config.api.d.ts +143 -0
  59. package/dist/service/config.api.d.ts.map +1 -0
  60. package/dist/service/config.interface.d.ts +22 -0
  61. package/dist/service/config.interface.d.ts.map +1 -0
  62. package/dist/service/index.d.ts +16 -17
  63. package/dist/service/index.d.ts.map +1 -1
  64. package/dist/service/registry-lifecycle.d.ts +43 -0
  65. package/dist/service/registry-lifecycle.d.ts.map +1 -0
  66. package/dist/service/registry.service.d.ts +94 -0
  67. package/dist/service/registry.service.d.ts.map +1 -0
  68. package/dist/service/service-bootstrap.d.ts +28 -0
  69. package/dist/service/service-bootstrap.d.ts.map +1 -0
  70. package/dist/service/service.api.d.ts +160 -0
  71. package/dist/service/service.api.d.ts.map +1 -1
  72. package/dist/service/service.interface.d.ts +32 -1
  73. package/dist/service/service.interface.d.ts.map +1 -1
  74. package/dist/shared/log/index.d.ts +4 -0
  75. package/dist/shared/log/index.d.ts.map +1 -1
  76. package/dist/shared/log/log-batch.d.ts +44 -0
  77. package/dist/shared/log/log-batch.d.ts.map +1 -0
  78. package/dist/shared/log/log-persist-coordinator.d.ts +37 -0
  79. package/dist/shared/log/log-persist-coordinator.d.ts.map +1 -0
  80. package/dist/shared/log/log-persist-flush.d.ts.map +1 -1
  81. package/dist/shared/log/log-persist.config.d.ts +0 -1
  82. package/dist/shared/log/log-persist.config.d.ts.map +1 -1
  83. package/dist/shared/log/log-persist.interface.d.ts +8 -0
  84. package/dist/shared/log/log-persist.interface.d.ts.map +1 -1
  85. package/dist/shared/utils/config-path.utils.d.ts +21 -0
  86. package/dist/shared/utils/config-path.utils.d.ts.map +1 -1
  87. package/dist/shared/utils/get-value-at-path.d.ts +3 -0
  88. package/dist/shared/utils/get-value-at-path.d.ts.map +1 -0
  89. package/dist/task/index.d.ts +2 -0
  90. package/dist/task/index.d.ts.map +1 -1
  91. package/dist/task/task-manager.d.ts +1 -1
  92. package/dist/task/task-manager.d.ts.map +1 -1
  93. package/dist/task/task-post-retry.api.d.ts +24 -0
  94. package/dist/task/task-post-retry.api.d.ts.map +1 -0
  95. package/dist/task/task-repo-context.d.ts +7 -1
  96. package/dist/task/task-repo-context.d.ts.map +1 -1
  97. package/dist/trigger/trigger-manager.d.ts +1 -1
  98. package/dist/trigger/trigger-manager.d.ts.map +1 -1
  99. package/dist/trigger/trigger-node.d.ts +1 -0
  100. package/dist/trigger/trigger-node.d.ts.map +1 -1
  101. package/dist/trigger/trigger.constant.d.ts +1 -1
  102. package/dist/trigger/trigger.constant.d.ts.map +1 -1
  103. package/dist/trigger/trigger.interface.d.ts +10 -0
  104. package/dist/trigger/trigger.interface.d.ts.map +1 -1
  105. package/package.json +4 -2
  106. package/src/browser.ts +98 -4
  107. package/src/extraction/extraction.api.ts +232 -0
  108. package/src/extraction/extraction.interface.ts +45 -0
  109. package/src/list/list.interface.ts +2 -2
  110. package/src/node/node-runtime.base.ts +37 -6
  111. package/src/node/process/create-managed-child-processes.ts +27 -0
  112. package/src/node/process/index.ts +4 -0
  113. package/src/node/process/managed-child-processes.ts +48 -15
  114. package/src/node/runtime-state/create-service-runtime-state-store.ts +125 -0
  115. package/src/node/runtime-state/index.ts +17 -0
  116. package/src/node/runtime-state/service-runtime-state.types.ts +64 -0
  117. package/src/node/service-guard/index.ts +17 -0
  118. package/src/node/service-guard/register-service-guard-runner.ts +64 -0
  119. package/src/node/service-guard/run-readiness-gate.ts +34 -0
  120. package/src/node/service-guard/run-service-guard-tick.ts +106 -0
  121. package/src/node/service-guard/service-guard-node.ts +52 -0
  122. package/src/node/service-guard/service-guard.interface.ts +64 -0
  123. package/src/node/service-guard/worker-spawn-cooldown.ts +13 -0
  124. package/src/node/service-host/index.ts +30 -0
  125. package/src/node/service-host/registry-slot-guard-step.ts +57 -0
  126. package/src/node/service-host/service-host.ts +168 -0
  127. package/src/node/service-host/single-process-service.ts +58 -0
  128. package/src/node.ts +69 -0
  129. package/src/service/config.api.ts +224 -0
  130. package/src/service/config.interface.ts +25 -0
  131. package/src/service/index.ts +74 -149
  132. package/src/service/registry-lifecycle.ts +144 -0
  133. package/src/service/registry.service.ts +564 -0
  134. package/src/service/service-bootstrap.ts +74 -0
  135. package/src/service/service.api.ts +13 -0
  136. package/src/service/service.interface.ts +36 -1
  137. package/src/shared/log/index.ts +13 -0
  138. package/src/shared/log/log-batch.ts +156 -0
  139. package/src/shared/log/log-persist-coordinator.ts +107 -0
  140. package/src/shared/log/log-persist-flush.ts +3 -3
  141. package/src/shared/log/log-persist.config.ts +0 -2
  142. package/src/shared/log/log-persist.interface.ts +10 -0
  143. package/src/shared/utils/config-path.utils.ts +35 -0
  144. package/src/shared/utils/get-value-at-path.ts +17 -0
  145. package/src/task/index.ts +2 -0
  146. package/src/task/task-manager.ts +10 -4
  147. package/src/task/task-post-retry.api.ts +61 -0
  148. package/src/task/task-repo-context.ts +8 -1
  149. package/src/trigger/trigger-manager.ts +4 -2
  150. package/src/trigger/trigger-node.ts +10 -4
  151. package/src/trigger/trigger.constant.ts +1 -1
  152. package/src/trigger/trigger.interface.ts +10 -0
  153. package/dist/chunks/create-logger-DyH3mZ8p.js.map +0 -1
  154. package/dist/chunks/enable-log-persist-C7GJo_Nc.js.map +0 -1
  155. package/dist/chunks/word.interface-DLgRobKV.js.map +0 -1
@@ -0,0 +1,30 @@
1
+ export type {
2
+ RegisterServiceGuardRunnerOptions,
3
+ RunReadinessGateInput,
4
+ ServiceGuardNodeOptions,
5
+ ServiceGuardTickInput,
6
+ ServiceGuardTickResult,
7
+ } from "../service-guard";
8
+ export {
9
+ getWorkerSpawnCooldownLastAt,
10
+ markWorkerSpawned,
11
+ registerServiceGuardRunner,
12
+ runReadinessGate,
13
+ runServiceGuardTick,
14
+ SERVICE_GUARD_RUNNER_KEY,
15
+ ServiceGuardNode,
16
+ } from "../service-guard";
17
+ export type {
18
+ ApplyRegistrySlotGuardInput,
19
+ ApplyRegistrySlotGuardResult,
20
+ } from "./registry-slot-guard-step";
21
+ export { applyRegistrySlotGuardStep } from "./registry-slot-guard-step";
22
+ export type {
23
+ ServiceHost,
24
+ ServiceHostClosable,
25
+ ServiceHostContext,
26
+ ServiceHostOptions,
27
+ } from "./service-host";
28
+ export { createServiceHost } from "./service-host";
29
+ export type { SingleProcessServiceContext, SingleProcessServiceOptions } from "./single-process-service";
30
+ export { runSingleProcessService } from "./single-process-service";
@@ -0,0 +1,57 @@
1
+ import { registrySlotRuntimePatchFromGuardResult, runRegistrySlotGuardCheck } from "../../service/registry-lifecycle";
2
+ import type { LoggerWithScope } from "../../shared/log";
3
+
4
+ export interface ApplyRegistrySlotGuardInput {
5
+ serviceValue: string;
6
+ serviceId: string;
7
+ checkedAt: string;
8
+ logger: Pick<LoggerWithScope, "critical" | "warn">;
9
+ logTopic?: string;
10
+ traceId?: string;
11
+ }
12
+
13
+ export interface ApplyRegistrySlotGuardResult {
14
+ /** When false, caller should abort the supervisor tick (slot lost shutdown initiated). */
15
+ continueTick: boolean;
16
+ registryPatch: ReturnType<typeof registrySlotRuntimePatchFromGuardResult>;
17
+ }
18
+
19
+ /**
20
+ * Run registry slot ownership check and optionally SIGTERM the parent main process.
21
+ * Used by guard / supervisor TriggerNode runners across L3 services.
22
+ */
23
+ export async function applyRegistrySlotGuardStep(
24
+ input: ApplyRegistrySlotGuardInput,
25
+ ): Promise<ApplyRegistrySlotGuardResult> {
26
+ const result = await runRegistrySlotGuardCheck({
27
+ serviceValue: input.serviceValue,
28
+ serviceId: input.serviceId,
29
+ });
30
+ const registryPatch = registrySlotRuntimePatchFromGuardResult(result, input.checkedAt);
31
+
32
+ if (result.shouldShutdown) {
33
+ input.logger.critical("Registry slot lost — shutting down service", {
34
+ topic: input.logTopic ?? "guard",
35
+ data: {
36
+ traceId: input.traceId,
37
+ serviceId: input.serviceId,
38
+ serviceValue: input.serviceValue,
39
+ },
40
+ });
41
+ process.kill(process.ppid, "SIGTERM");
42
+ return { continueTick: false, registryPatch };
43
+ }
44
+
45
+ if (result.error != null) {
46
+ input.logger.warn("Registry slot check failed (transient) — skipping enforcement this tick", {
47
+ topic: input.logTopic ?? "guard",
48
+ data: {
49
+ traceId: input.traceId,
50
+ serviceId: input.serviceId,
51
+ message: result.error,
52
+ },
53
+ });
54
+ }
55
+
56
+ return { continueTick: true, registryPatch };
57
+ }
@@ -0,0 +1,168 @@
1
+ import { createLogger, type Service, ServiceRegistryError } from "../../browser";
2
+ import { claimServiceRegistrySlot, type ServiceRegistrySession } from "../../service/registry-lifecycle";
3
+ import type { LoggerWithScope } from "../../shared/log";
4
+ import type { ManagedChildProcesses } from "../process/managed-child-processes";
5
+
6
+ export interface ServiceHostClosable {
7
+ close: () => Promise<void>;
8
+ }
9
+
10
+ export interface ServiceHostContext {
11
+ service: Service;
12
+ session: ServiceRegistrySession;
13
+ }
14
+
15
+ export interface ServiceHostOptions {
16
+ serviceValue: string;
17
+ logger?: LoggerWithScope;
18
+ logTopic?: string;
19
+ childProcesses?: ManagedChildProcesses;
20
+ /** Labels that trigger host shutdown when the child exits unexpectedly. */
21
+ criticalSupervisors?: readonly string[];
22
+
23
+ prepare?: () => Promise<void>;
24
+ createInstance: () => Promise<Service | { service: Service; baseUrl?: string }>;
25
+ onRegistryClaimed?: (ctx: ServiceHostContext) => Promise<void>;
26
+ startSupervisors?: () => void | Promise<void>;
27
+ waitUntilReady?: () => Promise<void>;
28
+ startServer?: () => Promise<ServiceHostClosable>;
29
+ /** Stop child processes and other local resources (not registry release). */
30
+ onShutdown?: (signal: string) => Promise<void>;
31
+ }
32
+
33
+ const DEFAULT_CRITICAL_SUPERVISORS = ["guard", "supervisor"] as const;
34
+
35
+ export interface ServiceHost {
36
+ run: () => Promise<void>;
37
+ requestShutdown: (signal: string, exitCode?: number) => void;
38
+ }
39
+
40
+ function unwrapService(created: Service | { service: Service; baseUrl?: string }): Service {
41
+ return typeof created === "object" && created != null && "service" in created ? created.service : created;
42
+ }
43
+
44
+ export function createServiceHost(options: ServiceHostOptions): ServiceHost {
45
+ const logger = options.logger ?? createLogger({ module: "service-host" });
46
+ const logTopic = options.logTopic ?? "startup";
47
+ const criticalSupervisors = options.criticalSupervisors ?? DEFAULT_CRITICAL_SUPERVISORS;
48
+
49
+ let session: ServiceRegistrySession | null = null;
50
+ let httpServer: ServiceHostClosable | null = null;
51
+ let shuttingDown = false;
52
+
53
+ async function shutdown(signal: string, exitCode = 0): Promise<void> {
54
+ if (shuttingDown) {
55
+ return;
56
+ }
57
+ shuttingDown = true;
58
+
59
+ logger.info("shutting down", { topic: logTopic, data: { signal, exitCode } });
60
+
61
+ if (httpServer != null) {
62
+ await httpServer.close().catch(() => undefined);
63
+ httpServer = null;
64
+ }
65
+
66
+ if (options.onShutdown != null) {
67
+ await options.onShutdown(signal).catch(() => undefined);
68
+ }
69
+
70
+ if (session != null) {
71
+ await session.release();
72
+ session = null;
73
+ }
74
+
75
+ process.exit(exitCode);
76
+ }
77
+
78
+ function requestShutdown(signal: string, exitCode = 0): void {
79
+ void shutdown(signal, exitCode);
80
+ }
81
+
82
+ function installProcessHandlers(): void {
83
+ process.on("SIGINT", () => void shutdown("SIGINT"));
84
+ process.on("SIGTERM", () => void shutdown("SIGTERM"));
85
+
86
+ options.childProcesses?.setCriticalExitHandler({
87
+ labels: criticalSupervisors,
88
+ onCriticalExit: (label, code, signal) => {
89
+ if (shuttingDown) {
90
+ return;
91
+ }
92
+ logger.critical("Critical supervisor exited — shutting down service", {
93
+ topic: logTopic,
94
+ data: { label, code, signal },
95
+ });
96
+ void shutdown("supervisor-exit", 1);
97
+ },
98
+ });
99
+ }
100
+
101
+ async function run(): Promise<void> {
102
+ installProcessHandlers();
103
+
104
+ if (options.prepare != null) {
105
+ await options.prepare();
106
+ }
107
+
108
+ try {
109
+ session = await claimServiceRegistrySlot({
110
+ serviceValue: options.serviceValue,
111
+ createInstance: async () => unwrapService(await options.createInstance()),
112
+ });
113
+ } catch (error) {
114
+ if (error instanceof ServiceRegistryError && error.code === "SERVICE_SLOTS_FULL") {
115
+ logger.critical("No EMPTY registry slot — refusing to start", {
116
+ topic: logTopic,
117
+ data: { serviceValue: options.serviceValue, code: error.code },
118
+ });
119
+ process.exit(1);
120
+ }
121
+ throw error;
122
+ }
123
+
124
+ if (options.onRegistryClaimed != null) {
125
+ await options.onRegistryClaimed({ service: session.service, session });
126
+ }
127
+
128
+ if (options.startSupervisors != null) {
129
+ await options.startSupervisors();
130
+ }
131
+
132
+ if (options.waitUntilReady != null) {
133
+ await options.waitUntilReady();
134
+ }
135
+
136
+ if (options.startServer != null) {
137
+ httpServer = await options.startServer();
138
+ }
139
+ }
140
+
141
+ async function runWithFatalHandling(): Promise<void> {
142
+ try {
143
+ await run();
144
+ } catch (error: unknown) {
145
+ const message = error instanceof Error ? error.message : String(error);
146
+ const code = error instanceof ServiceRegistryError ? error.code : undefined;
147
+ logger.error("fatal", { topic: logTopic, data: { message, code } });
148
+
149
+ if (httpServer != null) {
150
+ await httpServer.close().catch(() => undefined);
151
+ httpServer = null;
152
+ }
153
+
154
+ if (options.onShutdown != null) {
155
+ await options.onShutdown("fatal").catch(() => undefined);
156
+ }
157
+
158
+ if (session != null) {
159
+ await session.release().catch(() => undefined);
160
+ session = null;
161
+ }
162
+
163
+ process.exit(1);
164
+ }
165
+ }
166
+
167
+ return { run: runWithFatalHandling, requestShutdown };
168
+ }
@@ -0,0 +1,58 @@
1
+ import { createLogger, type Service, ServiceRegistryError } from "../../browser";
2
+ import { claimServiceRegistrySlot, type ServiceRegistrySession } from "../../service/registry-lifecycle";
3
+ import type { LoggerWithScope } from "../../shared/log";
4
+
5
+ export interface SingleProcessServiceContext {
6
+ service: Service;
7
+ session: ServiceRegistrySession;
8
+ }
9
+
10
+ export interface SingleProcessServiceOptions {
11
+ serviceValue: string;
12
+ logger?: LoggerWithScope;
13
+ logTopic?: string;
14
+
15
+ prepare?: () => Promise<void>;
16
+ createInstance: () => Promise<Service>;
17
+ run: (ctx: SingleProcessServiceContext) => Promise<void>;
18
+ }
19
+
20
+ /**
21
+ * Single-process L3 entry (e.g. log-service): claim registry slot then run the service body.
22
+ * Registry release is the caller's responsibility inside `run` (e.g. TriggerNode `beforeProcessExit`).
23
+ */
24
+ export async function runSingleProcessService(options: SingleProcessServiceOptions): Promise<void> {
25
+ const logger = options.logger ?? createLogger({ module: "single-process-service" });
26
+ const logTopic = options.logTopic ?? "startup";
27
+
28
+ if (options.prepare != null) {
29
+ await options.prepare();
30
+ }
31
+
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
+ }
49
+
50
+ try {
51
+ await options.run({ service: session.service, session });
52
+ } catch (error: unknown) {
53
+ const message = error instanceof Error ? error.message : String(error);
54
+ logger.error("fatal", { topic: logTopic, data: { message } });
55
+ await session.release().catch(() => undefined);
56
+ process.exit(1);
57
+ }
58
+ }
package/src/node.ts CHANGED
@@ -51,16 +51,21 @@ export {
51
51
  nodeBufferToArrayBuffer,
52
52
  readAndVerifySourceFile,
53
53
  } from "./node/fs/read-source-file";
54
+ export type { BaseNodeRuntimeOptions, NodeLoopContext } from "./node/node-runtime.base";
54
55
  export { BaseNodeRuntime } from "./node/node-runtime.base";
55
56
  export type {
56
57
  BuildNodeImportArgsInput,
58
+ CreateManagedChildProcessesOptions,
59
+ CriticalExitHandler,
57
60
  ManagedChildProcessesOptions,
61
+ SpawnChildOptions,
58
62
  SpawnChildResult,
59
63
  SpawnTsxChildOptions,
60
64
  StopAllChildrenOptions,
61
65
  } from "./node/process";
62
66
  export {
63
67
  buildNodeImportArgs,
68
+ createManagedChildProcesses,
64
69
  isChildProcessRunning,
65
70
  ManagedChildProcesses,
66
71
  spawnTsxChild,
@@ -85,6 +90,48 @@ export {
85
90
  runReadinessChecks,
86
91
  waitForServiceReady,
87
92
  } from "./node/readiness";
93
+ export type {
94
+ CreateServiceRuntimeStateStoreOptions,
95
+ FinishRunnerTickOptions,
96
+ GuardRuntimeSlice,
97
+ ReadinessRuntimeSlice,
98
+ ReadinessStatus,
99
+ SchedulerRuntimeSlice,
100
+ ServiceRuntimeCoreNestedKey,
101
+ ServiceRuntimeExtraSlicePatch,
102
+ ServiceRuntimeNestedKeys,
103
+ ServiceRuntimeState,
104
+ ServiceRuntimeStateStore,
105
+ WorkerRuntimeSlice,
106
+ } from "./node/runtime-state";
107
+ export { createServiceRuntimeStateStore } from "./node/runtime-state";
108
+ export type {
109
+ ApplyRegistrySlotGuardInput,
110
+ ApplyRegistrySlotGuardResult,
111
+ RegisterServiceGuardRunnerOptions,
112
+ RunReadinessGateInput,
113
+ ServiceGuardNodeOptions,
114
+ ServiceGuardTickInput,
115
+ ServiceGuardTickResult,
116
+ ServiceHost,
117
+ ServiceHostClosable,
118
+ ServiceHostContext,
119
+ ServiceHostOptions,
120
+ SingleProcessServiceContext,
121
+ SingleProcessServiceOptions,
122
+ } from "./node/service-host";
123
+ export {
124
+ applyRegistrySlotGuardStep,
125
+ createServiceHost,
126
+ getWorkerSpawnCooldownLastAt,
127
+ markWorkerSpawned,
128
+ registerServiceGuardRunner,
129
+ runReadinessGate,
130
+ runServiceGuardTick,
131
+ runSingleProcessService,
132
+ SERVICE_GUARD_RUNNER_KEY,
133
+ ServiceGuardNode,
134
+ } from "./node/service-host";
88
135
  export { RepoManager } from "./repo/repo-manager";
89
136
  export {
90
137
  disableLogPersist,
@@ -105,6 +152,25 @@ export type {
105
152
  LogPersistStats,
106
153
  WaitForLogPersistReadyOptions,
107
154
  } from "./shared/log/log-persist.interface";
155
+ export type { LogPersistCoordinator, LogPersistCoordinatorOptions } from "./shared/log/log-persist-coordinator";
156
+ export { createLogPersistCoordinator } from "./shared/log/log-persist-coordinator";
157
+ export type {
158
+ ConfigSchema,
159
+ LoadCachedJsConfigOptions,
160
+ ResolveFirstExistingPathOptions,
161
+ } from "./shared/utils/config-path.utils";
162
+ export {
163
+ getConfigFileDir,
164
+ importJsConfigModule,
165
+ loadCachedJsConfigModule,
166
+ pathExists,
167
+ resolveFirstExistingPath,
168
+ resolvePathFromBaseDir,
169
+ resolvePathFromConfigFile,
170
+ resolvePathFromCwd,
171
+ toFileImportHref,
172
+ } from "./shared/utils/config-path.utils";
173
+ export { getValueAtPath } from "./shared/utils/get-value-at-path";
108
174
  export type {
109
175
  BootstrapLocalTasksResult,
110
176
  BootstrapLocalTasksStatus,
@@ -132,6 +198,9 @@ export {
132
198
  } from "./task/task-manager";
133
199
  export { TaskNode } from "./task/task-node";
134
200
  export type { PostTaskPayload } from "./task/task-post.api";
201
+ export { postTask, postTaskSchema } from "./task/task-post.api";
202
+ export type { PostTaskWithRetryOptions, PostTaskWithRetryResult } from "./task/task-post-retry.api";
203
+ export { POST_TASK_DEFAULT_MAX_ATTEMPTS, postTaskWithRetry } from "./task/task-post-retry.api";
135
204
  export { postTaskWithValidation } from "./task/task-post-validated.api";
136
205
  export type {
137
206
  TaskRepoValidationFailureReason,
@@ -0,0 +1,224 @@
1
+ import { z } from "zod";
2
+ import {
3
+ createTarget,
4
+ getPossibleTarget,
5
+ getTarget,
6
+ isOptimisticLockError,
7
+ type QueryFilter,
8
+ updateTargetDetails,
9
+ validateWithSchema,
10
+ } from "../core.api";
11
+ import { generateResponse } from "../core.interface";
12
+ import { CategoryConfig, type Config, type ConfigDetails, TARGET_SYSTEM_REGISTRY_KEY } from "./config.interface";
13
+ import { type ServiceSlot, ServiceSlotStatus } from "./service.interface";
14
+
15
+ const targetIdSchema = z.string().trim().min(1);
16
+
17
+ export const getConfigSchema = z
18
+ .object({
19
+ id: targetIdSchema.optional(),
20
+ value: z.string().trim().min(1).optional(),
21
+ })
22
+ .refine(
23
+ (payload) => {
24
+ const hasId = payload.id != null && payload.id !== "";
25
+ const hasValue = payload.value != null && payload.value !== "";
26
+ return hasId !== hasValue;
27
+ },
28
+ { message: "Provide exactly one of id or value" },
29
+ );
30
+
31
+ export type GetConfigPayload = z.infer<typeof getConfigSchema>;
32
+
33
+ /** One declarative EMPTY slot entry for seeding the system registry. */
34
+ export const systemRegistrySeedSlotSchema = z.object({
35
+ serviceValue: z.string().trim().min(1),
36
+ });
37
+
38
+ export type SystemRegistrySeedSlot = z.infer<typeof systemRegistrySeedSlotSchema>;
39
+
40
+ export const postSystemRegistryConfigSchema = z.object({
41
+ /** When omitted, {@link DEFAULT_SYSTEM_REGISTRY_SEED_SLOTS} is used. */
42
+ slots: z.array(systemRegistrySeedSlotSchema).min(1).optional(),
43
+ tagList: z.array(z.string()).optional().default([]),
44
+ });
45
+
46
+ export type PostSystemRegistryConfigPayload = z.infer<typeof postSystemRegistryConfigSchema>;
47
+
48
+ /** Same payload shape as {@link postSystemRegistryConfig} — replaces slots with fresh EMPTY rows. */
49
+ export const resetSystemRegistryConfigSchema = postSystemRegistryConfigSchema;
50
+
51
+ export type ResetSystemRegistryConfigPayload = PostSystemRegistryConfigPayload;
52
+
53
+ const DEFAULT_RESET_RETRY_ATTEMPTS = 5;
54
+ const RESET_RETRY_DELAY_MS = 50;
55
+
56
+ /** Default one EMPTY slot per known L3 service (override via payload or seed file). */
57
+ export const DEFAULT_SYSTEM_REGISTRY_SEED_SLOTS: readonly SystemRegistrySeedSlot[] = [
58
+ { serviceValue: "log-service" },
59
+ { serviceValue: "watch-service" },
60
+ { serviceValue: "download-service" },
61
+ { serviceValue: "storage-service" },
62
+ ] as const;
63
+
64
+ const configCategoryFilter: QueryFilter = {
65
+ field: "category",
66
+ operator: "eq",
67
+ value: CategoryConfig.CONFIG,
68
+ };
69
+
70
+ function buildConfigLookupFilters(payload: GetConfigPayload): QueryFilter[] {
71
+ const filters: QueryFilter[] = [configCategoryFilter];
72
+
73
+ if (payload.id == null || payload.id === "") {
74
+ filters.push({ field: "value", operator: "eq", value: payload.value! });
75
+ }
76
+
77
+ return filters;
78
+ }
79
+
80
+ /** Build EMPTY {@link ServiceSlot} rows from seed entries (one slot per array item). */
81
+ export function buildEmptyServiceSlots(seedSlots: readonly SystemRegistrySeedSlot[]): ServiceSlot[] {
82
+ return seedSlots.map(({ serviceValue }) => ({
83
+ serviceValue,
84
+ serviceId: null,
85
+ status: ServiceSlotStatus.EMPTY,
86
+ }));
87
+ }
88
+
89
+ function parseRegistryRevision(rawMeta: unknown): number {
90
+ const source = typeof rawMeta === "object" && rawMeta !== null ? (rawMeta as Record<string, unknown>) : null;
91
+ const revision = source?.revision;
92
+ return typeof revision === "number" && Number.isFinite(revision) ? revision : 0;
93
+ }
94
+
95
+ function lockOnRegistryRevision(revision: number): QueryFilter[] {
96
+ return [{ field: "details->meta->>revision", operator: "eq", value: String(revision) }];
97
+ }
98
+
99
+ function sleep(ms: number): Promise<void> {
100
+ return new Promise((resolve) => setTimeout(resolve, ms));
101
+ }
102
+
103
+ /** Build `ConfigDetails` for the globally unique system registry row. */
104
+ export function buildSystemRegistryConfigDetails(slots: readonly ServiceSlot[]): ConfigDetails {
105
+ return {
106
+ manifestVersion: 0,
107
+ loaderKey: TARGET_SYSTEM_REGISTRY_KEY,
108
+ meta: { revision: 0 },
109
+ objects: [...slots],
110
+ };
111
+ }
112
+
113
+ /** Fetch a Config by id or by {@link Config.value} key (`category=config`). */
114
+ export const getConfig = validateWithSchema(
115
+ getConfigSchema,
116
+ "getConfigSchema",
117
+ )(async (payload) => {
118
+ const filterList = buildConfigLookupFilters(payload);
119
+
120
+ if (payload.id != null && payload.id !== "") {
121
+ const result = await getTarget({
122
+ id: payload.id,
123
+ filterList,
124
+ });
125
+ return {
126
+ ...result,
127
+ data: result.data as Config,
128
+ };
129
+ }
130
+
131
+ const result = await getPossibleTarget({
132
+ filterList,
133
+ });
134
+
135
+ if (result.data == null) {
136
+ return {
137
+ ...result,
138
+ data: undefined,
139
+ };
140
+ }
141
+
142
+ return {
143
+ ...result,
144
+ data: result.data as Config,
145
+ };
146
+ });
147
+
148
+ /**
149
+ * Insert the globally unique system registry Config (`category=config`,
150
+ * `value=target-system-registry`). Rejects duplicates via `checkRedundancyFilterList`.
151
+ */
152
+ export const postSystemRegistryConfig = validateWithSchema(
153
+ postSystemRegistryConfigSchema,
154
+ "postSystemRegistryConfigSchema",
155
+ )(async ({ slots, tagList }) => {
156
+ const seedSlots = [...(slots ?? DEFAULT_SYSTEM_REGISTRY_SEED_SLOTS)];
157
+ const serviceSlots = buildEmptyServiceSlots(seedSlots);
158
+ const details = buildSystemRegistryConfigDetails(serviceSlots);
159
+
160
+ return createTarget<Config, PostSystemRegistryConfigPayload>({
161
+ payload: { slots: seedSlots, tagList },
162
+ checkRedundancyFilterList: [
163
+ configCategoryFilter,
164
+ { field: "value", operator: "eq", value: TARGET_SYSTEM_REGISTRY_KEY },
165
+ ],
166
+ createFn: () => ({
167
+ name: TARGET_SYSTEM_REGISTRY_KEY,
168
+ value: TARGET_SYSTEM_REGISTRY_KEY,
169
+ category: CategoryConfig.CONFIG,
170
+ tagList,
171
+ details,
172
+ }),
173
+ });
174
+ });
175
+
176
+ /**
177
+ * Replace the system registry slot layout with fresh EMPTY rows.
178
+ * Creates the row when missing (same as {@link postSystemRegistryConfig}).
179
+ * Clears ACTIVE slot bindings — use for dev recovery after crashes or layout changes.
180
+ */
181
+ export const resetSystemRegistryConfig = validateWithSchema(
182
+ resetSystemRegistryConfigSchema,
183
+ "resetSystemRegistryConfigSchema",
184
+ )(async ({ slots, tagList }) => {
185
+ const seedSlots = [...(slots ?? DEFAULT_SYSTEM_REGISTRY_SEED_SLOTS)];
186
+ const serviceSlots = buildEmptyServiceSlots(seedSlots);
187
+
188
+ const existing = await getConfig({ value: TARGET_SYSTEM_REGISTRY_KEY });
189
+ if (existing.data == null) {
190
+ return postSystemRegistryConfig({ slots: seedSlots, tagList });
191
+ }
192
+
193
+ const configId = existing.data.id;
194
+
195
+ for (let attempt = 1; attempt <= DEFAULT_RESET_RETRY_ATTEMPTS; attempt += 1) {
196
+ try {
197
+ const fresh = await getConfig({ id: configId });
198
+ if (fresh.data == null) {
199
+ throw new Error(`System registry config disappeared during reset (id=${configId})`);
200
+ }
201
+
202
+ const revision = parseRegistryRevision(fresh.data.details.meta);
203
+ const updated = await updateTargetDetails<Config, ConfigDetails>({
204
+ id: configId,
205
+ optimisticLockFilterList: lockOnRegistryRevision(revision),
206
+ updateFn: (details) => ({
207
+ ...details,
208
+ meta: { revision: revision + 1 },
209
+ objects: serviceSlots,
210
+ }),
211
+ });
212
+
213
+ return generateResponse.success<Config>(updated);
214
+ } catch (error) {
215
+ if (isOptimisticLockError(error) && attempt < DEFAULT_RESET_RETRY_ATTEMPTS) {
216
+ await sleep(RESET_RETRY_DELAY_MS * attempt);
217
+ continue;
218
+ }
219
+ throw error;
220
+ }
221
+ }
222
+
223
+ throw new Error("[resetSystemRegistryConfig] Optimistic lock retries exhausted");
224
+ });
@@ -0,0 +1,25 @@
1
+ import type { Target } from "../core.interface";
2
+
3
+ export interface Config extends Target {
4
+ /** Human readable name */
5
+ name: string;
6
+ /** Unique key, like TARGET_SYSTEM_REGISTRY_KEY */
7
+ value: string;
8
+ category: CategoryConfig;
9
+ details: ConfigDetails;
10
+ }
11
+
12
+ export enum CategoryConfig {
13
+ CONFIG = "config",
14
+ }
15
+
16
+ /** Globally unique Config key for the declarative system service registry. */
17
+ export const TARGET_SYSTEM_REGISTRY_KEY = "target-system-registry";
18
+
19
+ export interface ConfigDetails {
20
+ manifestVersion: number;
21
+ /** How to resolve the Config */
22
+ loaderKey: string;
23
+ meta: unknown;
24
+ objects: Array<unknown>;
25
+ }