@goodandready/dsh-model-sync 0.5.3 → 0.5.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.
package/lib/http.js CHANGED
@@ -240,6 +240,12 @@ export function normalizeSelectionRequest(body) {
240
240
  }
241
241
 
242
242
  export function registerHttpApi(ctx, synchronizer, { getSchedulerStatus = () => null } = {}) {
243
+ if (typeof ctx?.webServer?.register !== 'function') {
244
+ if (typeof ctx?.logger?.warn === 'function') {
245
+ ctx.logger.warn('[dsh-model-sync] webServer service unavailable, HTTP API skipped')
246
+ }
247
+ return []
248
+ }
243
249
  const makeHandler = (route) => async (req, res) => {
244
250
  if (!trusted(req, { requireLoopback: req.method === 'POST' })) return json(res, 403, { error: { code: 'forbidden', message: 'dsh-model-sync: cross-origin or non-loopback request rejected' } })
245
251
  if (route === 'status') {
package/lib/index.js CHANGED
@@ -122,11 +122,34 @@ export function plainConfig(value) {
122
122
  }
123
123
 
124
124
  export function apply(ctx, config) {
125
- const baseConfig = structuredClone(config || {})
126
- const resolveConfig = (value) => Config(structuredClone(value || {}))
125
+ const baseConfig = structuredClone(plainConfig(config || {}))
126
+ const resolveConfig = (value) => plainConfig(Config(plainConfig(value) || {}))
127
127
  let liveConfig = resolveConfig(baseConfig)
128
128
  let reconfigure = () => {}
129
- let saveConfigImpl
129
+ let saveConfigImpl = async (patch) => {
130
+ const plainPatch = plainConfig(patch)
131
+ let settings
132
+ try {
133
+ settings = (typeof ctx.get === 'function' ? ctx.get('settings') : null) ?? ctx.settings
134
+ } catch (err) {
135
+ if (typeof ctx.logger?.debug === 'function') {
136
+ ctx.logger.debug('[dsh-model-sync] settings service read failed:', err)
137
+ }
138
+ }
139
+ if (settings && typeof settings.update === 'function') {
140
+ try {
141
+ await settings.update(NS, plainPatch)
142
+ } catch (err) {
143
+ if (typeof ctx.logger?.warn === 'function') {
144
+ ctx.logger.warn('[dsh-model-sync] settings.update failed:', err)
145
+ }
146
+ }
147
+ }
148
+ liveConfig = resolveConfig({ ...liveConfig, ...plainPatch })
149
+ reconfigure()
150
+ return liveConfig
151
+ }
152
+
130
153
  // ctx.inject starts a child fiber; keep a stable function reference for the
131
154
  // synchronizer while that fiber connects to the Settings service.
132
155
  const saveConfig = async (patch) => {
@@ -136,6 +159,19 @@ export function apply(ctx, config) {
136
159
  return saveConfigImpl(patch)
137
160
  }
138
161
 
162
+ const service = createProviderService(ctx)
163
+ const synchronizer = createModelSynchronizer(ctx, { getConfig: () => liveConfig, saveConfig })
164
+ const scheduler = createSyncScheduler(synchronizer, { getConfig: () => liveConfig })
165
+ reconfigure = () => scheduler.reconfigure()
166
+ scheduler.start()
167
+
168
+ if (typeof ctx.on === 'function') {
169
+ ctx.on('loader/volatile-update', () => {
170
+ liveConfig = resolveConfig(config)
171
+ reconfigure()
172
+ })
173
+ }
174
+
139
175
  // settings.register was removed before 0.1.7-rc.2. The host hands the profile entry
140
176
  // config to apply() directly, and liveConfig above is derived from it; the
141
177
  // Loader mutates the boxes in place and re-announces them with
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-model-sync",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "Automatic model catalog synchronization for API-key DeepSeek Harness providers.",
5
5
  "keywords": [
6
6
  "deepseek-harness",