@linxin666/dsh-usage 0.3.7 → 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Context } from '@deepseek-ai/cordis'
2
2
  import type {} from '@deepseek-ai/dsh-host-webserver'
3
- import { installSettingsSection, settingsNamespace } from '@deepseek-ai/dsh-settings'
3
+ import type { SettingsNamespace } from '@deepseek-ai/dsh-settings'
4
4
  import z from 'schemastery'
5
5
  import { mountOnce } from './mount-once.ts'
6
6
  import { UsageService, type UsageServiceOptions } from './host/usage-service.ts'
@@ -8,7 +8,7 @@ import { makeUsageOverviewRoute, makeUsageRefreshRoute } from './host/routes.ts'
8
8
 
9
9
  export const name = 'dsh-usage'
10
10
  export const inject = ['webServer']
11
- export const USAGE_SETTINGS_NAMESPACE = settingsNamespace('dsh-usage')
11
+ export const USAGE_SETTINGS_NAMESPACE = 'dsh-usage' as SettingsNamespace
12
12
 
13
13
  export interface Config {
14
14
  enabled?: boolean
@@ -44,46 +44,59 @@ export function resolveConfig(config?: Config): ResolvedConfig {
44
44
  export const apply = mountOnce('@linxin666/dsh-usage', (ctx: Context, config?: Config): void => {
45
45
  let source: () => Config = () => config ?? {}
46
46
  let service: UsageService | undefined
47
+ let pendingStop: Promise<void> | undefined
47
48
  let disposeRoutes: (() => void) | undefined
48
49
 
49
50
  const rearm = (): void => {
50
51
  const value = resolveConfig(source())
51
52
  if (!value.enabled) {
52
- service?.stop()
53
+ pendingStop = service?.stop()
53
54
  service = undefined
54
55
  disposeRoutes?.()
55
56
  disposeRoutes = undefined
56
57
  return
57
58
  }
58
59
  if (service === undefined) {
59
- service = new UsageService(ctx, value)
60
- service.start()
61
- const disposers = [makeUsageOverviewRoute(service), makeUsageRefreshRoute(service)]
62
- .map((route) => ctx.webServer.register(route))
63
- disposeRoutes = () => {
64
- for (const dispose of disposers) {
65
- try {
66
- dispose()
67
- } catch {
68
- // Route fiber already gone during shutdown.
60
+ const next = new UsageService(ctx, value)
61
+ service = next
62
+ const begin = (): void => {
63
+ // A disable may have landed while the predecessor's final flush was
64
+ // still pending; only start if this instance is still the live one.
65
+ if (service !== next) return
66
+ next.start()
67
+ const disposers = [makeUsageOverviewRoute(next), makeUsageRefreshRoute(next)]
68
+ .map((route) => ctx.webServer.register(route))
69
+ disposeRoutes = () => {
70
+ for (const dispose of disposers) {
71
+ try {
72
+ dispose()
73
+ } catch {
74
+ // Route fiber already gone during shutdown.
75
+ }
69
76
  }
70
77
  }
71
78
  }
79
+ // Serialize the start behind a just-stopped predecessor: its final
80
+ // ledger flush must land on disk before this instance loads the file.
81
+ if (pendingStop !== undefined) pendingStop.then(begin, begin)
82
+ else begin()
72
83
  } else {
73
84
  service.applyOptions(value)
74
85
  }
75
86
  }
76
87
 
77
- installSettingsSection(ctx, USAGE_SETTINGS_NAMESPACE, Config, config ?? {}, {
78
- setSource: (next) => { source = next; rearm() },
79
- onChange: rearm,
88
+ ctx.inject(['settings'], (settingsCtx) => {
89
+ settingsCtx.settings.installSection(ctx, USAGE_SETTINGS_NAMESPACE, Config, config ?? {}, {
90
+ setSource: (next) => { source = next; rearm() },
91
+ onChange: rearm,
92
+ })
80
93
  })
81
94
 
82
95
  ctx.effect(() => {
83
96
  rearm()
84
97
  return () => {
85
98
  disposeRoutes?.()
86
- service?.stop()
99
+ void service?.stop()
87
100
  service = undefined
88
101
  }
89
102
  }, 'dsh-usage: runtime')