Repository navigation
Conversation
…-boot resolution The .js-suffixed import at combo.ts:90 stopped resolving to localDb.ts under Turbopack's dev-instrumentation path after the dependency bump in diegosouzapw#10647, crashing npm run dev on a fresh npm ci with: Cannot find module '../../src/lib/localDb.js' Every sibling static import in this same file already uses the .ts extension (see line 89); this one was the only .js-suffixed exception. Matching that style resolves cleanly under both webpack and Turbopack. Verified live: fresh npm ci + npm run dev booted and served GET /api/health/ping -> 200 on the current release/v3.8.50 tip (df90591), where it previously failed instrumentation before serving anything. Closes diegosouzapw#10674
|
Heads-up: this fixes the dev-boot error but the production build ( I tested this change against a pristine
The remaining 28 errors — one root causeAll 28 are the same client-bundle contamination, introduced by the static import in #10542 (
The complete fix (2 files, behavior-preserving)Red = removed (before), green = added (after). Line anchors below refer to the current File 1:
|
| Line (current tree) | Change |
|---|---|
| L9 | Remove the static import of aihordeImageCatalog.ts (the trigger) |
| L9–10 | Add AiHordeRegistryModelEntry + aiHordeCatalogEntries snapshot + setAiHordeImageCatalogEntries() |
| L18–23 | get models() reads the snapshot instead of the service |
diff --git a/open-sse/config/providers/registry/aihorde/imageModels.ts b/open-sse/config/providers/registry/aihorde/imageModels.ts
index be04ce18a..5aee065cf 100644
--- a/open-sse/config/providers/registry/aihorde/imageModels.ts
+++ b/open-sse/config/providers/registry/aihorde/imageModels.ts
@@ -5,8 +5,34 @@
* async API (`/v2/generate/async`). `models` is a live getter so
* imageRegistry stays under the file-size cap and zero-worker names are
* never advertised.
+ *
+ * NOTE: this module must NOT statically import the live catalog service
+ * (open-sse/services/aihordeImageCatalog.ts). That service pulls in the
+ * network/DB stack (safeOutboundFetch → featureFlags → db/core →
+ * better-sqlite3), which would drag server-only code into the client bundle
+ * and fail the production build. Instead, the server-side Horde poller pushes
+ * refreshed snapshots in through `setAiHordeImageCatalogEntries()`.
*/
-import { getCachedAiHordeImageCatalogEntries } from "../../../../services/aihordeImageCatalog.ts";
+
+export interface AiHordeRegistryModelEntry {
+ id: string;
+ name: string;
+ provider: string;
+ supportedSizes: string[];
+ inputModalities: string[];
+ description?: string;
+}
+
+// Snapshot of the live AI Horde catalog. Empty until the server-side poller
+// pushes a refresh. (The client bundle never populates it — same as before,
+// when the client always read an empty in-memory cache.)
+let aiHordeCatalogEntries: AiHordeRegistryModelEntry[] = [];
+
+export function setAiHordeImageCatalogEntries(
+ entries: AiHordeRegistryModelEntry[]
+): void {
+ aiHordeCatalogEntries = entries;
+}
export const AI_HORDE_IMAGE_PROVIDER = {
id: "aihorde",
@@ -16,7 +42,7 @@ export const AI_HORDE_IMAGE_PROVIDER = {
authHeader: "apikey",
format: "aihorde",
get models() {
- return getCachedAiHordeImageCatalogEntries().map((entry) => ({
+ return aiHordeCatalogEntries.map((entry) => ({
id: entry.id.startsWith("aihorde/") ? entry.id.slice("aihorde/".length) : entry.id,
name: entry.name,
inputModalities: entry.inputModalities,File 2: open-sse/services/aihordeImageCatalog.ts
| Line (current tree) | Change |
|---|---|
| L10 | Add the setter import (after safeOutboundFetch) |
| L138–147 | replace(...) → syncRegistrySnapshot(this) |
| L149–153 | clear() → syncRegistrySnapshot(this) |
| L198 | Add registryEntriesFrom() + syncRegistrySnapshot() helpers |
| L204–215 | getCachedAiHordeImageCatalogEntries() refactored onto the shared helper |
diff --git a/open-sse/services/aihordeImageCatalog.ts b/open-sse/services/aihordeImageCatalog.ts
index a0cffa02a..e544aca88 100644
--- a/open-sse/services/aihordeImageCatalog.ts
+++ b/open-sse/services/aihordeImageCatalog.ts
@@ -8,6 +8,10 @@
*/
import { safeOutboundFetch } from "@/shared/network/safeOutboundFetch";
+import {
+ setAiHordeImageCatalogEntries,
+ type AiHordeRegistryModelEntry,
+} from "../config/providers/registry/aihorde/imageModels.ts";
export const AI_HORDE_API_BASE = "https://aihorde.net/api";
export const AI_HORDE_ANONYMOUS_KEY = "0000000000";
@@ -143,6 +147,7 @@ export class HordeImageCatalog {
} else {
this.lastError = error;
}
+ syncRegistrySnapshot(this);
}
/** Drop the snapshot so the next `ensureFresh` must hit Horde. */
@@ -150,6 +155,7 @@ export class HordeImageCatalog {
this.models = new Map();
this.updatedAt = null;
this.lastError = null;
+ syncRegistrySnapshot(this);
}
setFetch(fetchImpl: HordeFetch): void {
@@ -197,19 +203,13 @@ export class HordeImageCatalog {
export const aiHordeImageCatalog = new HordeImageCatalog();
-export function resetAiHordeImageCatalog(): void {
- aiHordeImageCatalog.clear();
-}
-
-export function getCachedAiHordeImageCatalogEntries(): Array<{
- id: string;
- name: string;
- provider: string;
- supportedSizes: string[];
- inputModalities: string[];
- description?: string;
-}> {
- return aiHordeImageCatalog.listModels().map((model) => ({
+/**
+ * Map a catalog snapshot to the registry entry shape and push it into
+ * `AI_HORDE_IMAGE_PROVIDER` (see imageModels.ts). Only the module-level
+ * singleton drives the registry — injected test instances are ignored.
+ */
+function registryEntriesFrom(models: HordeImageCatalogModel[]): AiHordeRegistryModelEntry[] {
+ return models.map((model) => ({
id: `aihorde/${model.name}`,
name: `${model.name} (AI Horde)`,
provider: "aihorde",
@@ -218,3 +218,16 @@ export function getCachedAiHordeImageCatalogEntries(): Array<{
description: `${model.count} worker${model.count === 1 ? "" : "s"} online`,
}));
}
+
+function syncRegistrySnapshot(from: HordeImageCatalog): void {
+ if (from !== aiHordeImageCatalog) return;
+ setAiHordeImageCatalogEntries(registryEntriesFrom(from.listModels()));
+}
+
+export function resetAiHordeImageCatalog(): void {
+ aiHordeImageCatalog.clear();
+}
+
+export function getCachedAiHordeImageCatalogEntries(): AiHordeRegistryModelEntry[] {
+ return registryEntriesFrom(aiHordeImageCatalog.listModels());
+}Verification (pristine base + this PR's fix + the above 2 files)
npm run build:✓ Compiled successfully— 0 errors (was 29)tests/unit/aihorde-image-catalog.test.ts+aihorde-image-generation.test.ts: 12/12 passnpm run typecheck:core: clean- No runtime behavior change: server-side the registry still gets live catalog data (the poller pushes on
replace()/clear()); client-side the model list was always empty (browser can't poll Horde or hit the DB), so nothing regresses there.
Happy to open this as a follow-up PR (or fold it in here) — the release branch currently can't build without both changes.
…Models.ts imageModels.ts statically imported aihordeImageCatalog.ts, which pulls in safeOutboundFetch -> featureFlags -> db/core -> better-sqlite3 and friends. imageRegistry.ts (which imports imageModels.ts) is reachable from the "use client" ProviderDetailPageClient.tsx dashboard page via mediaServiceKinds.ts -> serviceKindIndex.ts, so the whole server DB/ network stack was getting dragged into the browser bundle. Turbopack reported this as 28 Module-not-found errors (fs/net/tls/...) across the reachable server graph, failing npm run build outright. imageModels.ts no longer imports the catalog service. It holds a module-level snapshot (empty until refreshed) and exposes setAiHordeImageCatalogEntries() for the server-side poller to push into. aihordeImageCatalog.ts's replace()/clear() now call that setter after every snapshot change, and getCachedAiHordeImageCatalogEntries() is refactored onto the same registryEntriesFrom() mapping helper so the two entry points can't drift. No behavior change: server-side the registry still reflects the live catalog (pushed on every replace()/clear()); client-side the model list was always empty before this fix too, since the browser can neither poll Horde nor reach the DB. Verified: npm run build goes from 28 errors to 0 (Compiled successfully). tests/unit/aihorde-*.test.ts: 29/29 pass. Reported and diagnosed with a full repro + verified diff by @jonlwheat2-gif on PR diegosouzapw#10688; this commit re-verifies the diagnosis against the current tree and applies it.
|
Thanks for the careful diagnosis and live verification — this is exactly the right fix, but it has already been merged into release/v3.8.50, so this PR is fully subsumed and I'm closing it. Both changes you made here are already on the base tip:
Since the base tip already contains every line this PR intends (combo.ts:90 is |
Summary
open-sse/services/combo.ts:90importedlocalDbwith an explicit.jsextension, unlike every sibling static import in the same file (.tsor no extension). That.jssuffix stopped resolving under Turbopack's dev-instrumentation path after the dependency bump in feat(compression): adota omniglyph 1.4.0, perfis semânticos e contabilidade com evidência #10647, sonpm ci && npm run devon the current tip dies during boot before serving anything:One-line fix: use
.ts, matching the sibling import one line above it.Update (second commit): fixes the dev-boot bug above but doesn't fix
npm run build, which was still red for a separate reason — thanks @jonlwheat2-gif for the full diagnosis and verified fix in the review comments.open-sse/config/providers/registry/aihorde/imageModels.tsstatically importsopen-sse/services/aihordeImageCatalog.ts, which pulls insafeOutboundFetch -> featureFlags -> db/core -> better-sqlite3.imageRegistry.ts(which importsimageModels.ts) is reachable from the"use client"ProviderDetailPageClient.tsxdashboard page viamediaServiceKinds.ts -> serviceKindIndex.ts, so the whole server DB/network stack was getting dragged into the browser bundle — Turbopack reported 28Module not founderrors (fs/net/tls/...) across the reachable server graph.imageModels.tsno longer imports the catalog service directly; it holds a module-level snapshot that the server-side Horde poller pushes into via a newsetAiHordeImageCatalogEntries()setter, called fromreplace()/clear()after every snapshot change. No behavior change — server-side the registry still reflects the live catalog, client-side the model list was always empty before this too (the browser can neither poll Horde nor reach the DB).Related Issues
Validation
npx eslinton all touched files: cleanrelease/v3.8.50tip (df9059141)npm run build: before the second commit,Turbopack build failed with 28 errors(reproduced against a pristine checkout + freshnpm ci, matching @jonlwheat2-gif's report exactly). After:✓ Compiled successfully, 0 errors.tests/unit/aihorde-*.test.ts(5 files, the full AI Horde suite): 29/29 pass vianode --test.Tests Added Or Updated
imageModels.ts/aihordeImageCatalog.tsrefactor is a wiring change (push instead of pull) with identical runtime behavior on both ends; the existingtests/unit/aihorde-image-catalog.test.tsandtests/unit/aihorde-image-generation.test.tsalready covergetCachedAiHordeImageCatalogEntries()and the registry entry shape, and both pass unmodified against the refactor.Coverage Notes
Reviewer Notes
npm ci+npm run devonrelease/v3.8.50tip (df9059141): before this change, boot failed with theCannot find moduleerror above; after, the dev server listens andGET /api/health/pingreturns200 {"status":"ok",...}.