target-supabase-sdk 0.2.4 → 0.2.5

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 (31) hide show
  1. package/dist/browser.d.ts +2 -2
  2. package/dist/browser.d.ts.map +1 -1
  3. package/dist/browser.js +1 -1
  4. package/dist/chunks/{enable-log-persist-B8rg_wXG.js → enable-log-persist-BL2FaGQp.js} +6 -3
  5. package/dist/chunks/enable-log-persist-BL2FaGQp.js.map +1 -0
  6. package/dist/chunks/{word.interface-B_fbVFOW.js → word.interface-Mw7bTSqs.js} +115 -2
  7. package/dist/chunks/word.interface-Mw7bTSqs.js.map +1 -0
  8. package/dist/node/fs/json-state-store.d.ts.map +1 -1
  9. package/dist/node/fs/runtime-state-path.d.ts +17 -0
  10. package/dist/node/fs/runtime-state-path.d.ts.map +1 -0
  11. package/dist/node/fs/sharded-json-state-store.d.ts +19 -0
  12. package/dist/node/fs/sharded-json-state-store.d.ts.map +1 -0
  13. package/dist/node/runtime-state/create-service-runtime-state-store.d.ts +6 -2
  14. package/dist/node/runtime-state/create-service-runtime-state-store.d.ts.map +1 -1
  15. package/dist/node.js +164 -21
  16. package/dist/node.js.map +1 -1
  17. package/dist/preload.js +1 -1
  18. package/dist/service/index.d.ts +2 -2
  19. package/dist/service/index.d.ts.map +1 -1
  20. package/dist/service/registry.service.d.ts +23 -0
  21. package/dist/service/registry.service.d.ts.map +1 -1
  22. package/package.json +1 -1
  23. package/src/browser.ts +4 -0
  24. package/src/node/fs/json-state-store.ts +5 -2
  25. package/src/node/fs/runtime-state-path.ts +35 -0
  26. package/src/node/fs/sharded-json-state-store.ts +157 -0
  27. package/src/node/runtime-state/create-service-runtime-state-store.ts +17 -17
  28. package/src/service/index.ts +4 -0
  29. package/src/service/registry.service.ts +162 -0
  30. package/dist/chunks/enable-log-persist-B8rg_wXG.js.map +0 -1
  31. package/dist/chunks/word.interface-B_fbVFOW.js.map +0 -1
package/dist/preload.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { resolve } from 'node:path';
2
- import { r as resolveProjectRootByPackageName, p as pinEnvProfileFromArgv, l as loadEnvFiles, v as validateLogPersistPreloadEnv, a as logPersistEnabledFromEnv } from './chunks/enable-log-persist-B8rg_wXG.js';
2
+ import { r as resolveProjectRootByPackageName, p as pinEnvProfileFromArgv, l as loadEnvFiles, v as validateLogPersistPreloadEnv, a as logPersistEnabledFromEnv } from './chunks/enable-log-persist-BL2FaGQp.js';
3
3
  import 'node:fs';
4
4
  import 'node:url';
5
5
  import 'node:fs/promises';
@@ -7,8 +7,8 @@ export type { GetConfigPayload, PostSystemRegistryConfigPayload, ResetSystemRegi
7
7
  export { buildEmptyServiceSlots, buildSystemRegistryConfigDetails, DEFAULT_SYSTEM_REGISTRY_SEED_SLOTS, getConfig, getConfigSchema, postSystemRegistryConfig, postSystemRegistryConfigSchema, resetSystemRegistryConfig, resetSystemRegistryConfigSchema, systemRegistrySeedSlotSchema, } from "./config.api";
8
8
  export type { Config, ConfigDetails } from "./config.interface";
9
9
  export { CategoryConfig, TARGET_SYSTEM_REGISTRY_KEY } from "./config.interface";
10
- export type { PatchServiceRuntimeInput, RegisterServiceInput, TargetSystemRegistrySlotView, TargetSystemRegistryView, } from "./registry.service";
11
- export { assertRegistrySlotAvailable, assertRegistrySlotOwner, getTargetSystemRegistry, parseServiceSlot, parseServiceSlots, patchServiceRuntime, registerService, registerServiceAtStartup, resolveActiveRegistryServiceId, ServiceRegistryError, unregisterService, unregisterServiceAtShutdown, } from "./registry.service";
10
+ export type { PatchServiceRuntimeInput, RegisterServiceInput, ReleasedRegistrySlot, ReleaseSystemRegistrySlotsInput, ReleaseSystemRegistrySlotsOutcome, TargetSystemRegistrySlotView, TargetSystemRegistryView, } from "./registry.service";
11
+ export { assertRegistrySlotAvailable, assertRegistrySlotOwner, getTargetSystemRegistry, parseServiceSlot, parseServiceSlots, patchServiceRuntime, registerService, registerServiceAtStartup, releaseSystemRegistrySlots, resolveActiveRegistryServiceId, ServiceRegistryError, unregisterService, unregisterServiceAtShutdown, } from "./registry.service";
12
12
  export type { ClaimRegistrySlotInput, RegistrySlotGuardResult, RegistrySlotRuntimeState, ServiceRegistrySession, } from "./registry-lifecycle";
13
13
  export { claimServiceRegistrySlot, createClaimedRegistrySlotRuntimeState, EMPTY_REGISTRY_SLOT_RUNTIME_STATE, registrySlotRuntimePatchFromGuardResult, runRegistrySlotGuardCheck, } from "./registry-lifecycle";
14
14
  export type { GetApiPayload, GetServicePayload, PostApiPayload, PostServicePayload } from "./service.api";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EACR,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,gBAAgB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,YAAY,EACR,gBAAgB,EAChB,+BAA+B,EAC/B,gCAAgC,EAChC,sBAAsB,GACzB,MAAM,cAAc,CAAC;AACtB,OAAO,EACH,sBAAsB,EACtB,gCAAgC,EAChC,kCAAkC,EAClC,SAAS,EACT,eAAe,EACf,wBAAwB,EACxB,8BAA8B,EAC9B,yBAAyB,EACzB,+BAA+B,EAC/B,4BAA4B,GAC/B,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAChF,YAAY,EACR,wBAAwB,EACxB,oBAAoB,EACpB,4BAA4B,EAC5B,wBAAwB,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACH,2BAA2B,EAC3B,uBAAuB,EACvB,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,wBAAwB,EACxB,8BAA8B,EAC9B,oBAAoB,EACpB,iBAAiB,EACjB,2BAA2B,GAC9B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACR,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACH,wBAAwB,EACxB,qCAAqC,EACrC,iCAAiC,EACjC,uCAAuC,EACvC,yBAAyB,GAC5B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC1G,OAAO,EACH,gBAAgB,EAChB,qBAAqB,EACrB,MAAM,EACN,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,OAAO,EACP,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,EACpB,sBAAsB,EACtB,yBAAyB,EACzB,oBAAoB,GACvB,MAAM,eAAe,CAAC;AACvB,YAAY,EACR,GAAG,EACH,UAAU,EACV,OAAO,EACP,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,WAAW,GACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACjG,YAAY,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EACH,4BAA4B,EAC5B,uBAAuB,EACvB,mBAAmB,GACtB,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EACR,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,gBAAgB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,YAAY,EACR,gBAAgB,EAChB,+BAA+B,EAC/B,gCAAgC,EAChC,sBAAsB,GACzB,MAAM,cAAc,CAAC;AACtB,OAAO,EACH,sBAAsB,EACtB,gCAAgC,EAChC,kCAAkC,EAClC,SAAS,EACT,eAAe,EACf,wBAAwB,EACxB,8BAA8B,EAC9B,yBAAyB,EACzB,+BAA+B,EAC/B,4BAA4B,GAC/B,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAChF,YAAY,EACR,wBAAwB,EACxB,oBAAoB,EACpB,oBAAoB,EACpB,+BAA+B,EAC/B,iCAAiC,EACjC,4BAA4B,EAC5B,wBAAwB,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACH,2BAA2B,EAC3B,uBAAuB,EACvB,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,wBAAwB,EACxB,0BAA0B,EAC1B,8BAA8B,EAC9B,oBAAoB,EACpB,iBAAiB,EACjB,2BAA2B,GAC9B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACR,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACH,wBAAwB,EACxB,qCAAqC,EACrC,iCAAiC,EACjC,uCAAuC,EACvC,yBAAyB,GAC5B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC1G,OAAO,EACH,gBAAgB,EAChB,qBAAqB,EACrB,MAAM,EACN,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,OAAO,EACP,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,EACpB,sBAAsB,EACtB,yBAAyB,EACzB,oBAAoB,GACvB,MAAM,eAAe,CAAC;AACvB,YAAY,EACR,GAAG,EACH,UAAU,EACV,OAAO,EACP,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,WAAW,GACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACjG,YAAY,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EACH,4BAA4B,EAC5B,uBAAuB,EACvB,mBAAmB,GACtB,MAAM,qBAAqB,CAAC"}
@@ -27,6 +27,23 @@ export interface RegisterServiceInput {
27
27
  traceId?: string;
28
28
  maxAttempts?: number;
29
29
  }
30
+ export interface ReleaseSystemRegistrySlotsInput {
31
+ /** Logical service keys whose ACTIVE slots should be forced to EMPTY (e.g. `watch-service`). */
32
+ serviceValues: string[];
33
+ traceId?: string;
34
+ maxAttempts?: number;
35
+ }
36
+ export interface ReleasedRegistrySlot {
37
+ serviceValue: string;
38
+ serviceId: string;
39
+ slotIndex: number;
40
+ }
41
+ export interface ReleaseSystemRegistrySlotsOutcome {
42
+ config: Config;
43
+ released: ReleasedRegistrySlot[];
44
+ /** Requested `serviceValues` with no ACTIVE slot released (already EMPTY or never bound). */
45
+ unchangedServiceValues: string[];
46
+ }
30
47
  export declare class ServiceRegistryError extends Error {
31
48
  readonly code: "REGISTRY_CONFIG_NOT_FOUND" | "SERVICE_NOT_DECLARED" | "SERVICE_SLOTS_FULL" | "REGISTRY_SLOT_LOST" | "REGISTRY_UPDATE_FAILED";
32
49
  constructor(message: string, code: "REGISTRY_CONFIG_NOT_FOUND" | "SERVICE_NOT_DECLARED" | "SERVICE_SLOTS_FULL" | "REGISTRY_SLOT_LOST" | "REGISTRY_UPDATE_FAILED");
@@ -53,6 +70,12 @@ export declare function assertRegistrySlotOwner(input: {
53
70
  serviceValue: string;
54
71
  serviceId: string;
55
72
  }): Promise<void>;
73
+ /**
74
+ * Force-release ACTIVE registry slots for the given logical service keys (`ACTIVE → EMPTY`).
75
+ * Ops/dev recovery when a process crashed without {@link unregisterService}.
76
+ * Does not delete Service rows or mutate `details.runtime`.
77
+ */
78
+ export declare function releaseSystemRegistrySlots(input: ReleaseSystemRegistrySlotsInput): Promise<ReleaseSystemRegistrySlotsOutcome>;
56
79
  /**
57
80
  * Claim one EMPTY slot for a running Service instance (`EMPTY → ACTIVE` only).
58
81
  *
@@ -1 +1 @@
1
- {"version":3,"file":"registry.service.d.ts","sourceRoot":"","sources":["../../src/service/registry.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAGnD,OAAO,EAAE,KAAK,MAAM,EAAkD,MAAM,oBAAoB,CAAC;AAEjG,OAAO,EACH,KAAK,OAAO,EAGZ,KAAK,WAAW,EAEnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAUhE,MAAM,WAAW,4BAA4B;IACzC,IAAI,EAAE,WAAW,CAAC;IAClB,mEAAmE;IACnE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,4BAA4B,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,oBAAoB;IACjC,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,oBAAqB,SAAQ,KAAK;IAGvC,QAAQ,CAAC,IAAI,EACP,2BAA2B,GAC3B,sBAAsB,GACtB,oBAAoB,GACpB,oBAAoB,GACpB,wBAAwB;gBAN9B,OAAO,EAAE,MAAM,EACN,IAAI,EACP,2BAA2B,GAC3B,sBAAsB,GACtB,oBAAoB,GACpB,oBAAoB,GACpB,wBAAwB;CAKrC;AAcD,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CA2BnE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,EAAE,CAS/D;AAqCD;;;GAGG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAejF;AA2BD;;;GAGG;AACH,wBAAsB,2BAA2B,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBrF;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB/G;AA+CD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqFhF;AAED,yEAAyE;AACzE,wBAAsB,8BAA8B,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQjG;AAUD,MAAM,WAAW,wBAAwB;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,iFAAiF;AACjF,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBxF;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEzF;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6ElF;AAED;;GAEG;AACH,wBAAsB,2BAA2B,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB5F"}
1
+ {"version":3,"file":"registry.service.d.ts","sourceRoot":"","sources":["../../src/service/registry.service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "target-supabase-sdk",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "Supabase client initializer and data access APIs",
5
5
  "license": "MIT",
6
6
  "author": "KyLoc20",
package/src/browser.ts CHANGED
@@ -118,6 +118,9 @@ export type {
118
118
  RegisterServiceInput,
119
119
  RegistrySlotGuardResult,
120
120
  RegistrySlotRuntimeState,
121
+ ReleasedRegistrySlot,
122
+ ReleaseSystemRegistrySlotsInput,
123
+ ReleaseSystemRegistrySlotsOutcome,
121
124
  ResetSystemRegistryConfigPayload,
122
125
  Service,
123
126
  ServiceBootstrapResult,
@@ -166,6 +169,7 @@ export {
166
169
  registerService,
167
170
  registerServiceAtStartup,
168
171
  registrySlotRuntimePatchFromGuardResult,
172
+ releaseSystemRegistrySlots,
169
173
  resetSystemRegistryConfig,
170
174
  resetSystemRegistryConfigSchema,
171
175
  resolveActiveRegistryServiceId,
@@ -76,8 +76,11 @@ export function createJsonFileStateStore<T extends object, NK extends keyof T =
76
76
  const raw = await readFile(filePath, "utf8");
77
77
  const parsed = JSON.parse(raw) as Partial<T>;
78
78
  return mergeWithNested(defaultState, parsed, {}, nestedKeys);
79
- } catch {
80
- return { ...defaultState };
79
+ } catch (error) {
80
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") {
81
+ return mergeWithNested(defaultState, {}, {}, nestedKeys);
82
+ }
83
+ throw error;
81
84
  }
82
85
  },
83
86
 
@@ -0,0 +1,35 @@
1
+ import { dirname, join } from "node:path";
2
+
3
+ const RUNTIME_STATE_SHARD_DIR = "runtime-state";
4
+
5
+ export interface ResolvedRuntimeStatePaths {
6
+ /** Directory holding one JSON file per top-level slice. */
7
+ stateDir: string;
8
+ /** Legacy monolithic `state.json` — migrated on read/reset when present. */
9
+ legacyFilePath: string | null;
10
+ }
11
+
12
+ /**
13
+ * Resolve sharded runtime state layout from {@link CreateServiceRuntimeStateStoreOptions.filePath}.
14
+ *
15
+ * | `filePath` | Shard dir | Legacy |
16
+ * |-------------------------|-----------------------------------|---------------|
17
+ * | `.../state.json` | `.../runtime-state/` | `state.json` |
18
+ * | `.../runtime-state/` | same directory | none |
19
+ */
20
+ export function resolveRuntimeStatePaths(filePath: string): ResolvedRuntimeStatePaths {
21
+ if (filePath.endsWith(".json")) {
22
+ return {
23
+ stateDir: join(dirname(filePath), RUNTIME_STATE_SHARD_DIR),
24
+ legacyFilePath: filePath,
25
+ };
26
+ }
27
+ return {
28
+ stateDir: filePath,
29
+ legacyFilePath: null,
30
+ };
31
+ }
32
+
33
+ export function runtimeStateShardPath(stateDir: string, sliceKey: string): string {
34
+ return join(stateDir, `${sliceKey}.json`);
35
+ }
@@ -0,0 +1,157 @@
1
+ import { mkdir, readFile, stat, unlink } from "node:fs/promises";
2
+ import { createJsonFileStateStore, type JsonStatePatch } from "./json-state-store";
3
+ import { resolveRuntimeStatePaths, runtimeStateShardPath } from "./runtime-state-path";
4
+
5
+ export interface CreateShardedJsonFileStateStoreOptions<T extends object, NK extends keyof T> {
6
+ /** Monolithic legacy path or shard directory root (see {@link resolveRuntimeStatePaths}). */
7
+ filePath: string;
8
+ defaultState: T;
9
+ /** Top-level keys persisted as separate shard files. */
10
+ nestedKeys: NK[];
11
+ updatedAtKey?: keyof T;
12
+ }
13
+
14
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
15
+ return value != null && typeof value === "object" && !Array.isArray(value);
16
+ }
17
+
18
+ function mergeSlice<T extends object>(defaults: T, key: keyof T, patchValue: unknown): T[keyof T] {
19
+ const base = defaults[key];
20
+ if (isPlainObject(base) && isPlainObject(patchValue)) {
21
+ return { ...base, ...patchValue } as T[keyof T];
22
+ }
23
+ return patchValue as T[keyof T];
24
+ }
25
+
26
+ /**
27
+ * JSON runtime state with **one file per top-level slice** (log-persist registry pattern).
28
+ * Eliminates cross-slice lost updates when guard/scheduler/worker write concurrently.
29
+ */
30
+ export function createShardedJsonFileStateStore<T extends object, NK extends keyof T>(
31
+ options: CreateShardedJsonFileStateStoreOptions<T, NK>,
32
+ ): {
33
+ read(): Promise<T>;
34
+ write(patch: JsonStatePatch<T, NK>): Promise<T>;
35
+ reset(): Promise<T>;
36
+ } {
37
+ const { defaultState, nestedKeys, updatedAtKey } = options;
38
+ const { stateDir, legacyFilePath } = resolveRuntimeStatePaths(options.filePath);
39
+
40
+ type ShardStore = ReturnType<typeof createJsonFileStateStore<object>>;
41
+ const shardStores = new Map<string, ShardStore>();
42
+
43
+ function shardStore(sliceKey: NK): ShardStore {
44
+ const key = String(sliceKey);
45
+ let store = shardStores.get(key);
46
+ if (store == null) {
47
+ store = createJsonFileStateStore({
48
+ filePath: runtimeStateShardPath(stateDir, key),
49
+ defaultState: defaultState[sliceKey] as object,
50
+ });
51
+ shardStores.set(key, store);
52
+ }
53
+ return store;
54
+ }
55
+
56
+ async function readUpdatedAtFromShardMtimes(): Promise<string> {
57
+ let maxMtimeMs = 0;
58
+ for (const sliceKey of nestedKeys) {
59
+ try {
60
+ const shardStat = await stat(runtimeStateShardPath(stateDir, String(sliceKey)));
61
+ maxMtimeMs = Math.max(maxMtimeMs, shardStat.mtimeMs);
62
+ } catch (error) {
63
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
64
+ throw error;
65
+ }
66
+ }
67
+ }
68
+ if (maxMtimeMs <= 0) {
69
+ return defaultState[updatedAtKey as keyof T] as string;
70
+ }
71
+ return new Date(maxMtimeMs).toISOString();
72
+ }
73
+
74
+ async function migrateLegacyMonolithicIfPresent(): Promise<void> {
75
+ if (legacyFilePath == null) {
76
+ return;
77
+ }
78
+
79
+ let raw: string;
80
+ try {
81
+ raw = await readFile(legacyFilePath, "utf8");
82
+ } catch (error) {
83
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") {
84
+ return;
85
+ }
86
+ throw error;
87
+ }
88
+
89
+ let parsed: Partial<T>;
90
+ try {
91
+ parsed = JSON.parse(raw) as Partial<T>;
92
+ } catch {
93
+ await unlink(legacyFilePath).catch(() => undefined);
94
+ return;
95
+ }
96
+
97
+ await mkdir(stateDir, { recursive: true });
98
+ for (const sliceKey of nestedKeys) {
99
+ const slice = parsed[sliceKey];
100
+ if (slice != null) {
101
+ await shardStore(sliceKey).write(slice as object);
102
+ }
103
+ }
104
+
105
+ await unlink(legacyFilePath).catch(() => undefined);
106
+ }
107
+
108
+ return {
109
+ async read(): Promise<T> {
110
+ await mkdir(stateDir, { recursive: true });
111
+ await migrateLegacyMonolithicIfPresent();
112
+
113
+ const merged = { ...defaultState } as T;
114
+ for (const sliceKey of nestedKeys) {
115
+ merged[sliceKey] = (await shardStore(sliceKey).read()) as T[NK];
116
+ }
117
+ if (updatedAtKey != null) {
118
+ merged[updatedAtKey] = (await readUpdatedAtFromShardMtimes()) as T[keyof T];
119
+ }
120
+ return merged;
121
+ },
122
+
123
+ async write(patch: JsonStatePatch<T, NK>): Promise<T> {
124
+ await mkdir(stateDir, { recursive: true });
125
+ await migrateLegacyMonolithicIfPresent();
126
+
127
+ for (const sliceKey of nestedKeys) {
128
+ const patchSlice = patch[sliceKey];
129
+ if (patchSlice == null) {
130
+ continue;
131
+ }
132
+ const current = await shardStore(sliceKey).read();
133
+ const nextSlice = mergeSlice(defaultState, sliceKey, {
134
+ ...(current as object),
135
+ ...(patchSlice as object),
136
+ });
137
+ await shardStore(sliceKey).write(nextSlice as object);
138
+ }
139
+
140
+ return this.read();
141
+ },
142
+
143
+ async reset(): Promise<T> {
144
+ await mkdir(stateDir, { recursive: true });
145
+
146
+ for (const sliceKey of nestedKeys) {
147
+ await shardStore(sliceKey).reset();
148
+ }
149
+
150
+ if (legacyFilePath != null) {
151
+ await unlink(legacyFilePath).catch(() => undefined);
152
+ }
153
+
154
+ return this.read();
155
+ },
156
+ };
157
+ }
@@ -1,5 +1,6 @@
1
1
  import { EMPTY_REGISTRY_SLOT_RUNTIME_STATE } from "../../service/registry-lifecycle";
2
- import { createJsonFileStateStore, type JsonFileStateStore, type JsonStatePatch } from "../fs/json-state-store";
2
+ import type { JsonStatePatch } from "../fs/json-state-store";
3
+ import { createShardedJsonFileStateStore } from "../fs/sharded-json-state-store";
3
4
  import type {
4
5
  DefaultExtraRuntimeSlices,
5
6
  GuardRuntimeSlice,
@@ -16,6 +17,10 @@ const EPOCH_ISO = new Date(0).toISOString();
16
17
  export interface CreateServiceRuntimeStateStoreOptions<
17
18
  TExtraSlices extends Record<string, object> = DefaultExtraRuntimeSlices,
18
19
  > {
20
+ /**
21
+ * Monolithic legacy path (`…/state.json`) or shard directory (`…/runtime-state/`).
22
+ * Legacy files migrate automatically to `dirname/state.json → runtime-state/*.json`.
23
+ */
19
24
  filePath: string;
20
25
  /** Default values for service-specific top-level nested slices. */
21
26
  extraDefaults?: TExtraSlices;
@@ -78,7 +83,7 @@ function createDefaultServiceRuntimeState<TExtraSlices extends Record<string, ob
78
83
  };
79
84
  }
80
85
 
81
- /** JSON file-backed service runtime state (L3 blueprint) with typed core slices and extensions. */
86
+ /** Sharded JSON runtime state (L3 blueprint) — one file per slice under `runtime-state/`. */
82
87
  export function createServiceRuntimeStateStore<TExtraSlices extends Record<string, object> = DefaultExtraRuntimeSlices>(
83
88
  options: CreateServiceRuntimeStateStoreOptions<TExtraSlices>,
84
89
  ): ServiceRuntimeStateStore<TExtraSlices> {
@@ -95,24 +100,19 @@ export function createServiceRuntimeStateStore<TExtraSlices extends Record<strin
95
100
  ...(Object.keys(options.extraDefaults ?? {}) as (keyof TExtraSlices & string)[]),
96
101
  ] as NK[];
97
102
 
98
- let store: JsonFileStateStore<State, NK> | undefined;
99
-
100
- function instance(): JsonFileStateStore<State, NK> {
101
- store ??= createJsonFileStateStore<State, NK>({
102
- filePath: options.filePath,
103
- defaultState,
104
- nestedKeys,
105
- updatedAtKey: "updatedAt",
106
- });
107
- return store;
108
- }
103
+ const store = createShardedJsonFileStateStore<State, NK>({
104
+ filePath: options.filePath,
105
+ defaultState,
106
+ nestedKeys,
107
+ updatedAtKey: "updatedAt",
108
+ });
109
109
 
110
110
  return {
111
- readRuntimeState: () => instance().read(),
112
- writeRuntimeState: (patch) => instance().write(patch),
113
- resetRuntimeStateForStartup: () => instance().reset(),
111
+ readRuntimeState: () => store.read(),
112
+ writeRuntimeState: (patch) => store.write(patch),
113
+ resetRuntimeStateForStartup: () => store.reset(),
114
114
  finishRunnerTick: async ({ nowMs, lastFired, postedCount, extra }) => {
115
- await instance().write({
115
+ await store.write({
116
116
  scheduler: {
117
117
  lastTickAt: new Date(nowMs).toISOString(),
118
118
  lastFired,
@@ -32,6 +32,9 @@ export { CategoryConfig, TARGET_SYSTEM_REGISTRY_KEY } from "./config.interface";
32
32
  export type {
33
33
  PatchServiceRuntimeInput,
34
34
  RegisterServiceInput,
35
+ ReleasedRegistrySlot,
36
+ ReleaseSystemRegistrySlotsInput,
37
+ ReleaseSystemRegistrySlotsOutcome,
35
38
  TargetSystemRegistrySlotView,
36
39
  TargetSystemRegistryView,
37
40
  } from "./registry.service";
@@ -44,6 +47,7 @@ export {
44
47
  patchServiceRuntime,
45
48
  registerService,
46
49
  registerServiceAtStartup,
50
+ releaseSystemRegistrySlots,
47
51
  resolveActiveRegistryServiceId,
48
52
  ServiceRegistryError,
49
53
  unregisterService,
@@ -51,6 +51,26 @@ export interface RegisterServiceInput {
51
51
  maxAttempts?: number;
52
52
  }
53
53
 
54
+ export interface ReleaseSystemRegistrySlotsInput {
55
+ /** Logical service keys whose ACTIVE slots should be forced to EMPTY (e.g. `watch-service`). */
56
+ serviceValues: string[];
57
+ traceId?: string;
58
+ maxAttempts?: number;
59
+ }
60
+
61
+ export interface ReleasedRegistrySlot {
62
+ serviceValue: string;
63
+ serviceId: string;
64
+ slotIndex: number;
65
+ }
66
+
67
+ export interface ReleaseSystemRegistrySlotsOutcome {
68
+ config: Config;
69
+ released: ReleasedRegistrySlot[];
70
+ /** Requested `serviceValues` with no ACTIVE slot released (already EMPTY or never bound). */
71
+ unchangedServiceValues: string[];
72
+ }
73
+
54
74
  export class ServiceRegistryError extends Error {
55
75
  constructor(
56
76
  message: string,
@@ -298,6 +318,148 @@ function releaseOwnedSlot(slots: ServiceSlot[], serviceId: string): ServiceSlot[
298
318
  return next;
299
319
  }
300
320
 
321
+ function releaseActiveSlotsForServiceValues(
322
+ slots: ServiceSlot[],
323
+ serviceValueSet: ReadonlySet<string>,
324
+ ): { nextSlots: ServiceSlot[]; released: ReleasedRegistrySlot[] } {
325
+ const nextSlots = [...slots];
326
+ const released: ReleasedRegistrySlot[] = [];
327
+
328
+ for (let slotIndex = 0; slotIndex < nextSlots.length; slotIndex += 1) {
329
+ const slot = nextSlots[slotIndex];
330
+ if (
331
+ !serviceValueSet.has(slot.serviceValue) ||
332
+ slot.status !== ServiceSlotStatus.ACTIVE ||
333
+ slot.serviceId == null
334
+ ) {
335
+ continue;
336
+ }
337
+
338
+ released.push({
339
+ serviceValue: slot.serviceValue,
340
+ serviceId: slot.serviceId,
341
+ slotIndex,
342
+ });
343
+ nextSlots[slotIndex] = {
344
+ ...slot,
345
+ serviceId: null,
346
+ status: ServiceSlotStatus.EMPTY,
347
+ };
348
+ }
349
+
350
+ return { nextSlots, released };
351
+ }
352
+
353
+ /**
354
+ * Force-release ACTIVE registry slots for the given logical service keys (`ACTIVE → EMPTY`).
355
+ * Ops/dev recovery when a process crashed without {@link unregisterService}.
356
+ * Does not delete Service rows or mutate `details.runtime`.
357
+ */
358
+ export async function releaseSystemRegistrySlots(
359
+ input: ReleaseSystemRegistrySlotsInput,
360
+ ): Promise<ReleaseSystemRegistrySlotsOutcome> {
361
+ const serviceValues = [
362
+ ...new Set(input.serviceValues.map((value) => value.trim()).filter((value) => value !== "")),
363
+ ];
364
+ if (serviceValues.length === 0) {
365
+ throw new Error("[releaseSystemRegistrySlots] serviceValues must not be empty");
366
+ }
367
+
368
+ const serviceValueSet = new Set(serviceValues);
369
+ const maxAttempts = input.maxAttempts ?? DEFAULT_REGISTER_RETRY_ATTEMPTS;
370
+ const logger = createLogger({
371
+ module: "releaseSystemRegistrySlots",
372
+ traceId: input.traceId,
373
+ labels: { serviceValues: serviceValues.join(",") },
374
+ });
375
+
376
+ logger.info("开始强制释放 registry 槽位", {
377
+ topic: LOG_TOPIC_REGISTRY,
378
+ data: { serviceValues },
379
+ });
380
+
381
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
382
+ try {
383
+ const config = await loadSystemRegistryConfig();
384
+ const revision = parseRegistryRevision(config.details.meta);
385
+ const slots = parseServiceSlots(config);
386
+
387
+ for (const serviceValue of serviceValues) {
388
+ if (!isServiceValueDeclared(slots, serviceValue)) {
389
+ throw new ServiceRegistryError(
390
+ `Service ${serviceValue} is not declared in system registry config`,
391
+ "SERVICE_NOT_DECLARED",
392
+ );
393
+ }
394
+ }
395
+
396
+ const { nextSlots, released } = releaseActiveSlotsForServiceValues(slots, serviceValueSet);
397
+ const releasedValueSet = new Set(released.map((entry) => entry.serviceValue));
398
+ const unchangedServiceValues = serviceValues.filter((serviceValue) => !releasedValueSet.has(serviceValue));
399
+
400
+ if (released.length === 0) {
401
+ logger.info("无 ACTIVE 槽位需要释放", {
402
+ topic: LOG_TOPIC_REGISTRY,
403
+ data: { serviceValues, attempt },
404
+ });
405
+ return { config, released, unchangedServiceValues: serviceValues };
406
+ }
407
+
408
+ await persistSlotClaim({
409
+ configId: config.id,
410
+ revision,
411
+ slots: nextSlots,
412
+ });
413
+
414
+ const updated = await loadSystemRegistryConfig();
415
+ logger.info("槽位强制释放成功", {
416
+ topic: LOG_TOPIC_REGISTRY,
417
+ data: {
418
+ released,
419
+ unchangedServiceValues,
420
+ attempt,
421
+ revision: revision + 1,
422
+ },
423
+ });
424
+
425
+ return {
426
+ config: updated,
427
+ released,
428
+ unchangedServiceValues,
429
+ };
430
+ } catch (error) {
431
+ if (error instanceof ServiceRegistryError) {
432
+ logger.error("槽位强制释放被拒绝", {
433
+ topic: LOG_TOPIC_REGISTRY,
434
+ data: { serviceValues, code: error.code, message: error.message },
435
+ });
436
+ throw error;
437
+ }
438
+
439
+ if (isOptimisticLockError(error) && attempt < maxAttempts) {
440
+ logger.warn("registry 乐观锁冲突,重试", {
441
+ topic: LOG_TOPIC_REGISTRY,
442
+ data: { serviceValues, attempt, maxAttempts },
443
+ });
444
+ await sleep(50 * attempt);
445
+ continue;
446
+ }
447
+
448
+ const message = error instanceof Error ? error.message : String(error);
449
+ logger.error("槽位强制释放失败", {
450
+ topic: LOG_TOPIC_REGISTRY,
451
+ data: { serviceValues, attempt, message },
452
+ });
453
+ throw new ServiceRegistryError(message, "REGISTRY_UPDATE_FAILED");
454
+ }
455
+ }
456
+
457
+ throw new ServiceRegistryError(
458
+ "[releaseSystemRegistrySlots] Optimistic lock retries exhausted",
459
+ "REGISTRY_UPDATE_FAILED",
460
+ );
461
+ }
462
+
301
463
  /**
302
464
  * Claim one EMPTY slot for a running Service instance (`EMPTY → ACTIVE` only).
303
465
  *