target-supabase-sdk 0.2.12 → 0.2.13

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 (144) hide show
  1. package/dist/browser.d.ts +1 -1
  2. package/dist/browser.d.ts.map +1 -1
  3. package/dist/browser.js +1 -1
  4. package/dist/chunks/enable-DqnfLPsQ.js +874 -0
  5. package/dist/chunks/enable-DqnfLPsQ.js.map +1 -0
  6. package/dist/chunks/list.api-BzbTJBsM.js.map +1 -1
  7. package/dist/chunks/{task-queue-H4mpSW8R.js → task-queue-6X3aglJh.js} +108 -3
  8. package/dist/chunks/task-queue-6X3aglJh.js.map +1 -0
  9. package/dist/node/preload/run-service-preload.d.ts.map +1 -1
  10. package/dist/node/preload/service-preload.interface.d.ts +3 -1
  11. package/dist/node/preload/service-preload.interface.d.ts.map +1 -1
  12. package/dist/node/process/managed-child-processes.d.ts.map +1 -1
  13. package/dist/node/service-guard/service-guard-node.d.ts.map +1 -1
  14. package/dist/node/service-host/index.d.ts +1 -0
  15. package/dist/node/service-host/index.d.ts.map +1 -1
  16. package/dist/node/service-host/service-host.d.ts +5 -1
  17. package/dist/node/service-host/service-host.d.ts.map +1 -1
  18. package/dist/node.d.ts +10 -5
  19. package/dist/node.d.ts.map +1 -1
  20. package/dist/node.js +492 -47
  21. package/dist/node.js.map +1 -1
  22. package/dist/preload.js +9 -6
  23. package/dist/preload.js.map +1 -1
  24. package/dist/service/index.d.ts +2 -2
  25. package/dist/service/index.d.ts.map +1 -1
  26. package/dist/service/registry.service.d.ts +19 -0
  27. package/dist/service/registry.service.d.ts.map +1 -1
  28. package/dist/shared/log/core/create-logger.d.ts.map +1 -0
  29. package/dist/shared/log/{log-batch.d.ts → core/log-batch.d.ts} +4 -4
  30. package/dist/shared/log/core/log-batch.d.ts.map +1 -0
  31. package/dist/shared/log/core/log-manager.d.ts.map +1 -0
  32. package/dist/shared/log/core/log-min-level.d.ts.map +1 -0
  33. package/dist/shared/log/core/log-scope.d.ts.map +1 -0
  34. package/dist/shared/log/index.d.ts +13 -13
  35. package/dist/shared/log/index.d.ts.map +1 -1
  36. package/dist/shared/log/spool/collector.d.ts +21 -0
  37. package/dist/shared/log/spool/collector.d.ts.map +1 -0
  38. package/dist/shared/log/spool/config.d.ts +7 -0
  39. package/dist/shared/log/spool/config.d.ts.map +1 -0
  40. package/dist/shared/log/spool/coordinator.d.ts +18 -0
  41. package/dist/shared/log/spool/coordinator.d.ts.map +1 -0
  42. package/dist/shared/log/spool/enable.d.ts +23 -0
  43. package/dist/shared/log/spool/enable.d.ts.map +1 -0
  44. package/dist/shared/log/spool/file.d.ts +21 -0
  45. package/dist/shared/log/spool/file.d.ts.map +1 -0
  46. package/dist/shared/log/spool/interface.d.ts +55 -0
  47. package/dist/shared/log/spool/interface.d.ts.map +1 -0
  48. package/dist/shared/log/spool/paths.d.ts +6 -0
  49. package/dist/shared/log/spool/paths.d.ts.map +1 -0
  50. package/dist/shared/log/spool/process-roles.d.ts +17 -0
  51. package/dist/shared/log/spool/process-roles.d.ts.map +1 -0
  52. package/dist/shared/log/spool/register-collect-log-runner.d.ts +15 -0
  53. package/dist/shared/log/spool/register-collect-log-runner.d.ts.map +1 -0
  54. package/dist/shared/log/spool/service-lifecycle.d.ts +13 -0
  55. package/dist/shared/log/spool/service-lifecycle.d.ts.map +1 -0
  56. package/dist/shared/log/spool/writer.d.ts +32 -0
  57. package/dist/shared/log/spool/writer.d.ts.map +1 -0
  58. package/dist/shared/log/{log-persist-batch-id.d.ts → upload/batch-id.d.ts} +3 -3
  59. package/dist/shared/log/upload/batch-id.d.ts.map +1 -0
  60. package/dist/shared/log/upload/env.d.ts +7 -0
  61. package/dist/shared/log/upload/env.d.ts.map +1 -0
  62. package/dist/shared/log/{log-persist-flush.d.ts → upload/flush.d.ts} +3 -3
  63. package/dist/shared/log/upload/flush.d.ts.map +1 -0
  64. package/dist/shared/log/{log-persist-hook.d.ts → upload/hook.d.ts} +2 -2
  65. package/dist/shared/log/upload/hook.d.ts.map +1 -0
  66. package/dist/shared/log/upload/interface.d.ts +33 -0
  67. package/dist/shared/log/upload/interface.d.ts.map +1 -0
  68. package/dist/shared/log/upload/logger.d.ts +22 -0
  69. package/dist/shared/log/upload/logger.d.ts.map +1 -0
  70. package/package.json +1 -1
  71. package/src/browser.ts +1 -0
  72. package/src/node/preload/run-service-preload.ts +11 -6
  73. package/src/node/preload/service-preload.interface.ts +3 -1
  74. package/src/node/process/create-managed-child-processes.ts +1 -1
  75. package/src/node/process/managed-child-processes.ts +8 -1
  76. package/src/node/service-guard/service-guard-node.ts +5 -0
  77. package/src/node/service-host/index.ts +4 -0
  78. package/src/node/service-host/service-host.ts +22 -3
  79. package/src/node.ts +26 -19
  80. package/src/service/index.ts +3 -0
  81. package/src/service/registry.service.ts +142 -0
  82. package/src/shared/log/README.md +206 -0
  83. package/src/shared/log/{log-batch.ts → core/log-batch.ts} +4 -4
  84. package/src/shared/log/{log-manager.ts → core/log-manager.ts} +3 -3
  85. package/src/shared/log/{log-min-level.ts → core/log-min-level.ts} +1 -1
  86. package/src/shared/log/{log-scope.ts → core/log-scope.ts} +1 -1
  87. package/src/shared/log/index.ts +13 -18
  88. package/src/shared/log/spool/collector.ts +330 -0
  89. package/src/shared/log/spool/config.ts +56 -0
  90. package/src/shared/log/spool/coordinator.ts +55 -0
  91. package/src/shared/log/spool/enable.ts +136 -0
  92. package/src/shared/log/spool/file.ts +75 -0
  93. package/src/shared/log/spool/interface.ts +62 -0
  94. package/src/shared/log/spool/paths.ts +30 -0
  95. package/src/shared/log/spool/process-roles.ts +75 -0
  96. package/src/shared/log/spool/register-collect-log-runner.ts +63 -0
  97. package/src/shared/log/spool/service-lifecycle.ts +35 -0
  98. package/src/shared/log/spool/writer.ts +273 -0
  99. package/src/shared/log/{log-persist-batch-id.ts → upload/batch-id.ts} +2 -2
  100. package/src/shared/log/upload/env.ts +26 -0
  101. package/src/shared/log/{log-persist-flush.ts → upload/flush.ts} +8 -7
  102. package/src/shared/log/{log-persist-hook.ts → upload/hook.ts} +1 -1
  103. package/src/shared/log/upload/interface.ts +38 -0
  104. package/src/shared/log/upload/logger.ts +37 -0
  105. package/dist/chunks/enable-log-persist-Dl55_mv2.js +0 -1674
  106. package/dist/chunks/enable-log-persist-Dl55_mv2.js.map +0 -1
  107. package/dist/chunks/task-queue-H4mpSW8R.js.map +0 -1
  108. package/dist/shared/log/create-logger.d.ts.map +0 -1
  109. package/dist/shared/log/enable-log-persist.d.ts +0 -28
  110. package/dist/shared/log/enable-log-persist.d.ts.map +0 -1
  111. package/dist/shared/log/log-batch.d.ts.map +0 -1
  112. package/dist/shared/log/log-manager.d.ts.map +0 -1
  113. package/dist/shared/log/log-min-level.d.ts.map +0 -1
  114. package/dist/shared/log/log-persist-batch-id.d.ts.map +0 -1
  115. package/dist/shared/log/log-persist-coordinator.d.ts +0 -37
  116. package/dist/shared/log/log-persist-coordinator.d.ts.map +0 -1
  117. package/dist/shared/log/log-persist-errors.d.ts +0 -4
  118. package/dist/shared/log/log-persist-errors.d.ts.map +0 -1
  119. package/dist/shared/log/log-persist-flush.d.ts.map +0 -1
  120. package/dist/shared/log/log-persist-hook.d.ts.map +0 -1
  121. package/dist/shared/log/log-persist-logger.d.ts +0 -16
  122. package/dist/shared/log/log-persist-logger.d.ts.map +0 -1
  123. package/dist/shared/log/log-persist-registry.d.ts +0 -18
  124. package/dist/shared/log/log-persist-registry.d.ts.map +0 -1
  125. package/dist/shared/log/log-persist.config.d.ts +0 -9
  126. package/dist/shared/log/log-persist.config.d.ts.map +0 -1
  127. package/dist/shared/log/log-persist.d.ts +0 -62
  128. package/dist/shared/log/log-persist.d.ts.map +0 -1
  129. package/dist/shared/log/log-persist.interface.d.ts +0 -132
  130. package/dist/shared/log/log-persist.interface.d.ts.map +0 -1
  131. package/dist/shared/log/log-scope.d.ts.map +0 -1
  132. package/src/shared/log/enable-log-persist.ts +0 -225
  133. package/src/shared/log/log-persist-coordinator.ts +0 -107
  134. package/src/shared/log/log-persist-errors.ts +0 -16
  135. package/src/shared/log/log-persist-logger.ts +0 -61
  136. package/src/shared/log/log-persist-registry.ts +0 -252
  137. package/src/shared/log/log-persist.config.ts +0 -115
  138. package/src/shared/log/log-persist.interface.ts +0 -150
  139. package/src/shared/log/log-persist.ts +0 -822
  140. /package/dist/shared/log/{create-logger.d.ts → core/create-logger.d.ts} +0 -0
  141. /package/dist/shared/log/{log-manager.d.ts → core/log-manager.d.ts} +0 -0
  142. /package/dist/shared/log/{log-min-level.d.ts → core/log-min-level.d.ts} +0 -0
  143. /package/dist/shared/log/{log-scope.d.ts → core/log-scope.d.ts} +0 -0
  144. /package/src/shared/log/{create-logger.ts → core/create-logger.ts} +0 -0
@@ -0,0 +1,33 @@
1
+ import type { TargetDraft } from "../../../core.interface";
2
+ import type { List } from "../../../list/list.interface";
3
+ import type { LogEntry } from "../core/log-manager";
4
+ /**
5
+ * `ListDetails.loaderKey` stamped on every persisted log batch (write + read side).
6
+ * Business type: **LogBatch** (transport flush). Pairs with log-service **LogTrace**
7
+ * (`LogTrace.0`) after rekeying by `traceId`.
8
+ */
9
+ export declare const LOG_PERSIST_LOADER_KEY = "LogBatch.0";
10
+ /** Alias for {@link LOG_PERSIST_LOADER_KEY} — preferred when contrasting with LogTrace. */
11
+ export declare const LOG_BATCH_LOADER_KEY = "LogBatch.0";
12
+ /** Legacy transport metadata — fixed `"slow"` for spool uploads; required for downstream decode today. */
13
+ export type LogPersistLane = "fast" | "medium" | "slow";
14
+ export interface LogBatchMeta {
15
+ service: string;
16
+ process: string;
17
+ pid: number;
18
+ lane: LogPersistLane;
19
+ count: number;
20
+ from: number | null;
21
+ to: number | null;
22
+ flushedAt: number;
23
+ idempotencyKey: string;
24
+ }
25
+ export interface BuildLogListDraftInput {
26
+ service: string;
27
+ process: string;
28
+ lane: LogPersistLane;
29
+ idempotencyKey: string;
30
+ entries: LogEntry[];
31
+ }
32
+ export type LogListDraft = TargetDraft<List>;
33
+ //# sourceMappingURL=interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../../../src/shared/log/upload/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,eAAe,CAAC;AAEnD,2FAA2F;AAC3F,eAAO,MAAM,oBAAoB,eAAyB,CAAC;AAE3D,0GAA0G;AAC1G,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,YAAY;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,cAAc,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,22 @@
1
+ /** User-facing / lifecycle logs — may be persisted like normal app logs. */
2
+ export declare const LOG_PERSIST_TOPIC = "log-persist";
3
+ /** Operational logs from the persist pipeline — never re-offered to avoid feedback loops. */
4
+ export declare const LOG_PERSIST_INTERNAL_TOPIC = "log-persist-internal";
5
+ type PipelineLogData = Record<string, unknown>;
6
+ /** Supabase upload path (`postLogBatch`). */
7
+ export declare const persistLogger: {
8
+ debug: (message: string, data?: PipelineLogData) => void;
9
+ info: (message: string, data?: PipelineLogData) => void;
10
+ warn: (message: string, data?: PipelineLogData) => void;
11
+ error: (message: string, data?: PipelineLogData) => void;
12
+ };
13
+ /** File spool writer + collector. */
14
+ export declare const spoolLogger: {
15
+ debug: (message: string, data?: PipelineLogData) => void;
16
+ info: (message: string, data?: PipelineLogData) => void;
17
+ warn: (message: string, data?: PipelineLogData) => void;
18
+ error: (message: string, data?: PipelineLogData) => void;
19
+ };
20
+ export declare function isLogPersistInternalTopic(topic: string | undefined): boolean;
21
+ export {};
22
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../../src/shared/log/upload/logger.ts"],"names":[],"mappings":"AAEA,4EAA4E;AAC5E,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAE/C,6FAA6F;AAC7F,eAAO,MAAM,0BAA0B,yBAAyB,CAAC;AAEjE,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAoB/C,6CAA6C;AAC7C,eAAO,MAAM,aAAa;qBARD,MAAM,SAAS,eAAe;oBAC/B,MAAM,SAAS,eAAe;oBAC9B,MAAM,SAAS,eAAe;qBAC7B,MAAM,SAAS,eAAe;CAKQ,CAAC;AAEhE,qCAAqC;AACrC,eAAO,MAAM,WAAW;qBAXC,MAAM,SAAS,eAAe;oBAC/B,MAAM,SAAS,eAAe;oBAC9B,MAAM,SAAS,eAAe;qBAC7B,MAAM,SAAS,eAAe;CAQK,CAAC;AAE7D,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAE5E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "target-supabase-sdk",
3
- "version": "0.2.12",
3
+ "version": "0.2.13",
4
4
  "description": "Supabase client initializer and data access APIs",
5
5
  "license": "MIT",
6
6
  "author": "KyLoc20",
package/src/browser.ts CHANGED
@@ -171,6 +171,7 @@ export {
171
171
  registerServiceAtStartup,
172
172
  registrySlotRuntimePatchFromGuardResult,
173
173
  releaseSystemRegistrySlots,
174
+ releaseSystemRegistrySlotsByServiceId,
174
175
  resetSystemRegistryConfig,
175
176
  resetSystemRegistryConfigSchema,
176
177
  resolveActiveRegistryServiceId,
@@ -1,14 +1,15 @@
1
1
  import { resolve } from "node:path";
2
- import { validateLogPersistPreloadEnv } from "../../shared/log/enable-log-persist";
3
- import { logManager } from "../../shared/log/log-manager";
4
- import { resolveLogMinLevel } from "../../shared/log/log-min-level";
5
- import { logPersistEnabledFromEnv } from "../../shared/log/log-persist.config";
2
+ import { logManager } from "../../shared/log/core/log-manager";
3
+ import { resolveLogMinLevel } from "../../shared/log/core/log-min-level";
4
+ import { validateLogSpoolPreloadEnv } from "../../shared/log/spool/enable";
5
+ import { mergeLogSpoolExtraProcessRolesEnv } from "../../shared/log/spool/process-roles";
6
+ import { logSpoolEnabledFromEnv } from "../../shared/log/upload/env";
6
7
  import { loadEnvFiles, pinEnvProfileFromArgv } from "../env/load-env";
7
8
  import { resolveProjectRootByPackageName } from "../env/project-root";
8
9
  import type { ServicePreloadOptions } from "./service-preload.interface";
9
10
 
10
11
  function applyServiceEnvDefaults(projectRoot: string, options: ServicePreloadOptions): void {
11
- if (!logPersistEnabledFromEnv()) {
12
+ if (!logSpoolEnabledFromEnv()) {
12
13
  return;
13
14
  }
14
15
 
@@ -22,6 +23,10 @@ function applyServiceEnvDefaults(projectRoot: string, options: ServicePreloadOpt
22
23
  const relative = options.runtimeDataDirRelative ?? "data/runtime";
23
24
  process.env.RUNTIME_DATA_DIR = resolve(projectRoot, relative);
24
25
  }
26
+
27
+ if (options.logSpoolExtraProcessRoles != null && options.logSpoolExtraProcessRoles.length > 0) {
28
+ mergeLogSpoolExtraProcessRolesEnv(process.env, options.logSpoolExtraProcessRoles);
29
+ }
25
30
  }
26
31
 
27
32
  function applyLogMinLevelFromEnv(options: ServicePreloadOptions): void {
@@ -56,7 +61,7 @@ export function runServicePreload(options: ServicePreloadOptions): void {
56
61
 
57
62
  applyLogMinLevelFromEnv(options);
58
63
 
59
- validateLogPersistPreloadEnv();
64
+ validateLogSpoolPreloadEnv();
60
65
 
61
66
  // TODO: Phase 5 — optional unhandledRejection / uncaughtException formatters
62
67
  // (formerly watch-service preload-diagnostics.mjs)
@@ -1,4 +1,4 @@
1
- import type { LogLevel } from "../../shared/log/log-manager";
1
+ import type { LogLevel } from "../../shared/log/core/log-manager";
2
2
 
3
3
  export interface ServicePreloadOptions {
4
4
  /** `import.meta.url` from the service `scripts/preload.mjs`. */
@@ -17,4 +17,6 @@ export interface ServicePreloadOptions {
17
17
  defaultLogMinLevel?: LogLevel;
18
18
  /** Apply `logManager.setOptions({ minLevel })` from env (default true). */
19
19
  applyLogMinLevel?: boolean;
20
+ /** Extra spool roles beyond main|guard|scheduler|worker (e.g. `chrome-sidecar`). Merged into `LOG_SPOOL_EXTRA_PROCESS_ROLES`. */
21
+ logSpoolExtraProcessRoles?: readonly string[];
20
22
  }
@@ -1,4 +1,4 @@
1
- import { createLogger } from "../../shared/log/create-logger";
1
+ import { createLogger } from "../../shared/log/core/create-logger";
2
2
  import type { ManagedChildProcessesOptions } from "./managed-child-processes";
3
3
  import { ManagedChildProcesses } from "./managed-child-processes";
4
4
 
@@ -1,6 +1,7 @@
1
1
  import type { ChildProcess } from "node:child_process";
2
2
  import { resolve } from "node:path";
3
3
  import type { LoggerWithScope } from "../../shared/log";
4
+ import { resolveLogSpoolSpawnEnvForLabel } from "../../shared/log/spool/enable";
4
5
  import { isChildProcessRunning, spawnTsxChild } from "./process-spawn";
5
6
 
6
7
  export interface ManagedChildProcessesOptions {
@@ -80,12 +81,18 @@ export class ManagedChildProcesses {
80
81
  return { child: existing, created: false };
81
82
  }
82
83
 
84
+ const logSpoolEnv = resolveLogSpoolSpawnEnvForLabel(label);
85
+ const childEnv =
86
+ spawnOptions?.env != null
87
+ ? { ...process.env, ...logSpoolEnv, ...spawnOptions.env }
88
+ : { ...process.env, ...logSpoolEnv };
89
+
83
90
  const child = spawnTsxChild({
84
91
  projectRoot: this.projectRoot,
85
92
  entryScript,
86
93
  preloadModules: this.preloadModules,
87
94
  useTsx: spawnOptions?.useTsx ?? this.defaultUseTsx,
88
- env: spawnOptions?.env != null ? { ...process.env, ...spawnOptions.env } : process.env,
95
+ env: childEnv,
89
96
  });
90
97
 
91
98
  child.on("exit", (code: number | null, signal: NodeJS.Signals | null) => {
@@ -1,4 +1,5 @@
1
1
  import type { LoggerWithScope } from "../../shared/log";
2
+ import { registerCollectLogRunner } from "../../shared/log/spool/register-collect-log-runner";
2
3
  import { TriggerNode } from "../../trigger/trigger-node";
3
4
  import { registerServiceGuardRunner } from "./register-service-guard-runner";
4
5
  import { runReadinessGate } from "./run-readiness-gate";
@@ -28,6 +29,10 @@ class ServiceGuardNode extends TriggerNode {
28
29
  logTopic: options.logTopic,
29
30
  ...options.guardRunner,
30
31
  });
32
+ registerCollectLogRunner({
33
+ serviceValue: options.serviceValue,
34
+ getServiceId: options.guardRunner.getServiceId,
35
+ });
31
36
  return new ServiceGuardNode(options);
32
37
  }
33
38
 
@@ -1,3 +1,7 @@
1
+ export {
2
+ COLLECT_LOG_RUNNER_KEY,
3
+ registerCollectLogRunner,
4
+ } from "../../shared/log/spool/register-collect-log-runner";
1
5
  export type {
2
6
  RegisterServiceGuardRunnerOptions,
3
7
  RunReadinessGateInput,
@@ -1,6 +1,9 @@
1
1
  import { createLogger, type Service, ServiceRegistryError } from "../../browser";
2
2
  import { claimServiceRegistrySlot, type ServiceRegistrySession } from "../../service/registry-lifecycle";
3
3
  import type { LoggerWithScope } from "../../shared/log";
4
+ import { LOG_SPOOL_SERVICE_ID_ENV } from "../../shared/log/spool/config";
5
+ import { ensureLogSpoolFromEnv } from "../../shared/log/spool/enable";
6
+ import { logSpoolEnabledFromEnv } from "../../shared/log/upload/env";
4
7
  import type { ManagedChildProcesses } from "../process/managed-child-processes";
5
8
 
6
9
  export interface ServiceHostClosable {
@@ -10,6 +13,8 @@ export interface ServiceHostClosable {
10
13
  export interface ServiceHostContext {
11
14
  service: Service;
12
15
  session: ServiceRegistrySession;
16
+ /** Registry instance id — same as `service.id`; children inherit via spawn env injection. */
17
+ serviceId: string;
13
18
  }
14
19
 
15
20
  export interface ServiceHostOptions {
@@ -23,9 +28,11 @@ export interface ServiceHostOptions {
23
28
  prepare?: () => Promise<void>;
24
29
  createInstance: () => Promise<Service | { service: Service; baseUrl?: string }>;
25
30
  onRegistryClaimed?: (ctx: ServiceHostContext) => Promise<void>;
26
- startSupervisors?: () => void | Promise<void>;
31
+ startSupervisors?: (ctx: ServiceHostContext) => void | Promise<void>;
27
32
  waitUntilReady?: () => Promise<void>;
28
33
  startServer?: () => Promise<ServiceHostClosable>;
34
+ /** When true (default), enable file log spool for main after registry claim. */
35
+ enableLogSpoolAfterClaim?: boolean;
29
36
  /** Stop child processes and other local resources (not registry release). */
30
37
  onShutdown?: (signal: string) => Promise<void>;
31
38
  }
@@ -121,12 +128,24 @@ export function createServiceHost(options: ServiceHostOptions): ServiceHost {
121
128
  throw error;
122
129
  }
123
130
 
131
+ const hostCtx: ServiceHostContext = { service: session.service, session, serviceId: session.service.id };
132
+
124
133
  if (options.onRegistryClaimed != null) {
125
- await options.onRegistryClaimed({ service: session.service, session });
134
+ await options.onRegistryClaimed(hostCtx);
135
+ }
136
+
137
+ const enableSpool = options.enableLogSpoolAfterClaim ?? true;
138
+ if (enableSpool && logSpoolEnabledFromEnv()) {
139
+ process.env[LOG_SPOOL_SERVICE_ID_ENV] = session.service.id;
140
+ await ensureLogSpoolFromEnv({
141
+ serviceId: session.service.id,
142
+ serviceValue: options.serviceValue,
143
+ processRole: "main",
144
+ });
126
145
  }
127
146
 
128
147
  if (options.startSupervisors != null) {
129
- await options.startSupervisors();
148
+ await options.startSupervisors(hostCtx);
130
149
  }
131
150
 
132
151
  if (options.waitUntilReady != null) {
package/src/node.ts CHANGED
@@ -122,9 +122,11 @@ export type {
122
122
  } from "./node/service-host";
123
123
  export {
124
124
  applyRegistrySlotGuardStep,
125
+ COLLECT_LOG_RUNNER_KEY,
125
126
  createServiceHost,
126
127
  getWorkerSpawnCooldownLastAt,
127
128
  markWorkerSpawned,
129
+ registerCollectLogRunner,
128
130
  registerServiceGuardRunner,
129
131
  runReadinessGate,
130
132
  runServiceGuardTick,
@@ -133,27 +135,32 @@ export {
133
135
  ServiceGuardNode,
134
136
  } from "./node/service-host";
135
137
  export { RepoManager } from "./repo/repo-manager";
138
+ export { runCollectLogTick } from "./shared/log/spool/collector";
139
+ export { LOG_SPOOL_SERVICE_ID_ENV } from "./shared/log/spool/config";
140
+ export type { LogSpoolCoordinator, LogSpoolCoordinatorOptions } from "./shared/log/spool/coordinator";
141
+ export { createLogSpoolCoordinator } from "./shared/log/spool/coordinator";
136
142
  export {
137
- disableLogPersist,
138
- enableLogPersist,
139
- ensureLogPersistFromEnv,
140
- getLogPersistStats,
141
- logPersistEnabledFromEnv,
142
- resolveLogPersistRegistryPath,
143
- snapshotLogPersistReady,
144
- validateLogPersistPreloadEnv,
145
- waitForLogPersistReady,
146
- } from "./shared/log/enable-log-persist";
143
+ buildLogSpoolSpawnEnv,
144
+ ensureLogSpoolFromEnv,
145
+ getLogSpoolStats,
146
+ logSpoolEnabledFromEnv,
147
+ shutdownLogSpoolFromEnv,
148
+ validateLogSpoolPreloadEnv,
149
+ } from "./shared/log/spool/enable";
147
150
  export type {
148
- EnableLogPersistOptions,
149
- EnsureLogPersistFromEnvOptions,
150
- LogPersistLane,
151
- LogPersistReadySnapshot,
152
- LogPersistStats,
153
- WaitForLogPersistReadyOptions,
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";
151
+ EnableLogSpoolOptions,
152
+ LogSpoolCoreProcessRole,
153
+ LogSpoolProcessRole,
154
+ LogSpoolWriterStats,
155
+ } from "./shared/log/spool/interface";
156
+ export { resolveLogSpoolRoot } from "./shared/log/spool/paths";
157
+ export {
158
+ enableLogSpoolFromEnvInChild,
159
+ getMainLogSpoolWriterStats,
160
+ isLogSpoolEnabled,
161
+ shutdownLogSpool,
162
+ } from "./shared/log/spool/service-lifecycle";
163
+ export type { LogBatchMeta, LogPersistLane } from "./shared/log/upload/interface";
157
164
  export type {
158
165
  ConfigSchema,
159
166
  LoadCachedJsConfigOptions,
@@ -35,6 +35,8 @@ export type {
35
35
  PatchServiceRuntimeInput,
36
36
  RegisterServiceInput,
37
37
  ReleasedRegistrySlot,
38
+ ReleaseSystemRegistrySlotsByServiceIdInput,
39
+ ReleaseSystemRegistrySlotsByServiceIdOutcome,
38
40
  ReleaseSystemRegistrySlotsInput,
39
41
  ReleaseSystemRegistrySlotsOutcome,
40
42
  TargetSystemRegistrySlotView,
@@ -51,6 +53,7 @@ export {
51
53
  registerService,
52
54
  registerServiceAtStartup,
53
55
  releaseSystemRegistrySlots,
56
+ releaseSystemRegistrySlotsByServiceId,
54
57
  resolveActiveRegistryServiceId,
55
58
  ServiceRegistryError,
56
59
  unregisterService,
@@ -58,6 +58,13 @@ export interface ReleaseSystemRegistrySlotsInput {
58
58
  maxAttempts?: number;
59
59
  }
60
60
 
61
+ export interface ReleaseSystemRegistrySlotsByServiceIdInput {
62
+ /** Runtime Service row ids bound to ACTIVE slots (one slot per id). */
63
+ serviceIds: string[];
64
+ traceId?: string;
65
+ maxAttempts?: number;
66
+ }
67
+
61
68
  export interface ReleasedRegistrySlot {
62
69
  serviceValue: string;
63
70
  serviceId: string;
@@ -71,6 +78,13 @@ export interface ReleaseSystemRegistrySlotsOutcome {
71
78
  unchangedServiceValues: string[];
72
79
  }
73
80
 
81
+ export interface ReleaseSystemRegistrySlotsByServiceIdOutcome {
82
+ config: Config;
83
+ released: ReleasedRegistrySlot[];
84
+ /** Requested `serviceIds` with no ACTIVE slot released (unknown id, already EMPTY, or never bound). */
85
+ unchangedServiceIds: string[];
86
+ }
87
+
74
88
  export interface AppendSystemRegistrySlotsInput {
75
89
  /** Logical service keys to declare with one new EMPTY slot each when missing. */
76
90
  serviceValues: string[];
@@ -365,6 +379,34 @@ function releaseActiveSlotsForServiceValues(
365
379
  return { nextSlots, released };
366
380
  }
367
381
 
382
+ function releaseActiveSlotsForServiceIds(
383
+ slots: ServiceSlot[],
384
+ serviceIdSet: ReadonlySet<string>,
385
+ ): { nextSlots: ServiceSlot[]; released: ReleasedRegistrySlot[] } {
386
+ const nextSlots = [...slots];
387
+ const released: ReleasedRegistrySlot[] = [];
388
+
389
+ for (let slotIndex = 0; slotIndex < nextSlots.length; slotIndex += 1) {
390
+ const slot = nextSlots[slotIndex];
391
+ if (slot.serviceId == null || !serviceIdSet.has(slot.serviceId) || slot.status !== ServiceSlotStatus.ACTIVE) {
392
+ continue;
393
+ }
394
+
395
+ released.push({
396
+ serviceValue: slot.serviceValue,
397
+ serviceId: slot.serviceId,
398
+ slotIndex,
399
+ });
400
+ nextSlots[slotIndex] = {
401
+ ...slot,
402
+ serviceId: null,
403
+ status: ServiceSlotStatus.EMPTY,
404
+ };
405
+ }
406
+
407
+ return { nextSlots, released };
408
+ }
409
+
368
410
  /**
369
411
  * Force-release ACTIVE registry slots for the given logical service keys (`ACTIVE → EMPTY`).
370
412
  * Ops/dev recovery when a process crashed without {@link unregisterService}.
@@ -475,6 +517,106 @@ export async function releaseSystemRegistrySlots(
475
517
  );
476
518
  }
477
519
 
520
+ /**
521
+ * Force-release ACTIVE registry slots for the given runtime Service row ids (`ACTIVE → EMPTY`).
522
+ * Targets one slot per `serviceId` — use when multiple slots share the same `serviceValue`.
523
+ * Ops/dev recovery when a process crashed without {@link unregisterService}.
524
+ * Does not delete Service rows or mutate `details.runtime`.
525
+ */
526
+ export async function releaseSystemRegistrySlotsByServiceId(
527
+ input: ReleaseSystemRegistrySlotsByServiceIdInput,
528
+ ): Promise<ReleaseSystemRegistrySlotsByServiceIdOutcome> {
529
+ const serviceIds = [...new Set(input.serviceIds.map((value) => value.trim()).filter((value) => value !== ""))];
530
+ if (serviceIds.length === 0) {
531
+ throw new Error("[releaseSystemRegistrySlotsByServiceId] serviceIds must not be empty");
532
+ }
533
+
534
+ const serviceIdSet = new Set(serviceIds);
535
+ const maxAttempts = input.maxAttempts ?? DEFAULT_REGISTER_RETRY_ATTEMPTS;
536
+ const logger = createLogger({
537
+ module: "releaseSystemRegistrySlotsByServiceId",
538
+ traceId: input.traceId,
539
+ labels: { serviceIds: serviceIds.join(",") },
540
+ });
541
+
542
+ logger.info("开始按 serviceId 强制释放 registry 槽位", {
543
+ topic: LOG_TOPIC_REGISTRY,
544
+ data: { serviceIds },
545
+ });
546
+
547
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
548
+ try {
549
+ const config = await loadSystemRegistryConfig();
550
+ const revision = parseRegistryRevision(config.details.meta);
551
+ const slots = parseServiceSlots(config);
552
+
553
+ const { nextSlots, released } = releaseActiveSlotsForServiceIds(slots, serviceIdSet);
554
+ const releasedIdSet = new Set(released.map((entry) => entry.serviceId));
555
+ const unchangedServiceIds = serviceIds.filter((serviceId) => !releasedIdSet.has(serviceId));
556
+
557
+ if (released.length === 0) {
558
+ logger.info("无 ACTIVE 槽位需要释放", {
559
+ topic: LOG_TOPIC_REGISTRY,
560
+ data: { serviceIds, attempt },
561
+ });
562
+ return { config, released, unchangedServiceIds: serviceIds };
563
+ }
564
+
565
+ await persistSlotClaim({
566
+ configId: config.id,
567
+ revision,
568
+ slots: nextSlots,
569
+ });
570
+
571
+ const updated = await loadSystemRegistryConfig();
572
+ logger.info("槽位强制释放成功", {
573
+ topic: LOG_TOPIC_REGISTRY,
574
+ data: {
575
+ released,
576
+ unchangedServiceIds,
577
+ attempt,
578
+ revision: revision + 1,
579
+ },
580
+ });
581
+
582
+ return {
583
+ config: updated,
584
+ released,
585
+ unchangedServiceIds,
586
+ };
587
+ } catch (error) {
588
+ if (error instanceof ServiceRegistryError) {
589
+ logger.error("槽位强制释放被拒绝", {
590
+ topic: LOG_TOPIC_REGISTRY,
591
+ data: { serviceIds, code: error.code, message: error.message },
592
+ });
593
+ throw error;
594
+ }
595
+
596
+ if (isOptimisticLockError(error) && attempt < maxAttempts) {
597
+ logger.warn("registry 乐观锁冲突,重试", {
598
+ topic: LOG_TOPIC_REGISTRY,
599
+ data: { serviceIds, attempt, maxAttempts },
600
+ });
601
+ await sleep(50 * attempt);
602
+ continue;
603
+ }
604
+
605
+ const message = error instanceof Error ? error.message : String(error);
606
+ logger.error("槽位强制释放失败", {
607
+ topic: LOG_TOPIC_REGISTRY,
608
+ data: { serviceIds, attempt, message },
609
+ });
610
+ throw new ServiceRegistryError(message, "REGISTRY_UPDATE_FAILED");
611
+ }
612
+ }
613
+
614
+ throw new ServiceRegistryError(
615
+ "[releaseSystemRegistrySlotsByServiceId] Optimistic lock retries exhausted",
616
+ "REGISTRY_UPDATE_FAILED",
617
+ );
618
+ }
619
+
478
620
  /**
479
621
  * Append EMPTY {@link ServiceSlot} rows for logical service keys not yet declared.
480
622
  * Idempotent — skips keys that already appear in `details.objects`.