@uniweb/kit 0.13.5 → 0.13.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/kit",
3
- "version": "0.13.5",
3
+ "version": "0.13.6",
4
4
  "description": "Standard component library for Uniweb foundations",
5
5
  "type": "module",
6
6
  "exports": {
@@ -44,8 +44,8 @@
44
44
  "shiki": "^3.0.0",
45
45
  "tailwind-merge": "^3.6.0",
46
46
  "temml": "^0.13.2",
47
- "@uniweb/core": "^0.12.0",
48
47
  "@uniweb/semantic-parser": "^1.3.1",
48
+ "@uniweb/core": "^0.12.1",
49
49
  "@uniweb/scene": "^0.1.3"
50
50
  },
51
51
  "peerDependencies": {
@@ -142,6 +142,37 @@ export function createSearchClient(website, options = {}) {
142
142
  // host serves none.
143
143
  const authoredProvider = website?.config?.search?.provider
144
144
 
145
+ // ⛔ …BUT AN AUTHORED `index` IS NOT A CHOICE, IT IS THE DEFAULT SPELLED OUT.
146
+ // `getSearchConfig()` fills `provider: 'index'` when the author said nothing,
147
+ // and `docs/authoring/search.md` shows it in its options block labelled
148
+ // "default" — so a site that copied that block to set `include:` or
149
+ // `exclude:` carries it without having decided anything.
150
+ //
151
+ // Treating it as a veto pinned exactly those sites to the local index. On a
152
+ // host-served site that index does not exist (the build stops emitting one on
153
+ // that lane), so an ENTITLED site — one whose host does offer search — drew a
154
+ // box, queried `search-index.json`, and got a 404. They had bought the
155
+ // feature and could not use it.
156
+ //
157
+ // ⇒ An authored `index` no longer outranks a host's offer. Any OTHER authored
158
+ // provider still does: `endpoint` and a foundation transport are real choices
159
+ // and the comment above still applies to them.
160
+ //
161
+ // ⚠️ This removes one thing an author could previously express — "use the
162
+ // local index even though my host offers search". On a host-served lane that
163
+ // preference resolves to a 404 either way, and on a static host `source` is
164
+ // never 'host' so this branch cannot fire and the local index is untouched.
165
+ //
166
+ // ⛔ REACHES NEW AND REBUILT FOUNDATIONS ONLY. A foundation bundles its own
167
+ // frozen copy of this file, so an already-published one keeps the old
168
+ // precedence. Unlike the host-decline check — which lives in `@uniweb/core`
169
+ // precisely so the runtime carries it to every foundation regardless of age —
170
+ // provider selection is kit's, and frozen kit reads `website.config` directly.
171
+ // There is no honest core-side fix: it would mean rewriting authored config
172
+ // to steer a consumer's branch.
173
+ const authoredVeto =
174
+ authoredProvider && authoredProvider !== 'index' ? authoredProvider : null
175
+
145
176
  // ⛔ THE HOST ANSWERED AND DECLINED. `resolveService` returns
146
177
  // `{ url: null, source: 'host' }` when a host declares the service NAME
147
178
  // while offering no address — the decline shape `@uniweb/core/services`
@@ -173,7 +204,7 @@ export function createSearchClient(website, options = {}) {
173
204
 
174
205
  const declared =
175
206
  providerOverride ||
176
- authoredProvider ||
207
+ authoredVeto ||
177
208
  (service.source === 'host' ? 'endpoint' : 'index')
178
209
 
179
210
  // One in-flight resolution shared by every caller.
@@ -168,21 +168,32 @@ export function createEndpointProvider(website, options = {}) {
168
168
  // more than "403". `isEnabled()` is what a foundation asks, and it is
169
169
  // false long before this line runs.
170
170
  //
171
- // ⚠️ Ordering, if the local-index fallback in `client.js` is ever
172
- // removed: that fallback is currently what stops this string
173
- // propagating, so removing it would surface this message where nothing
174
- // renders one today. Settle where a provider error may surface FIRST.
171
+ // ⛔ THE HOST'S SENTENCE GOES TO THE CONSOLE, NEVER INTO THE THROW.
172
+ //
173
+ // It used to become the Error's message, and `useSearch` exposes
174
+ // `error` — so a foundation rendering it would have shown a visitor a
175
+ // host-authored English sentence about someone's provisioning state.
176
+ // The only thing preventing that was `client.js`'s local-index
177
+ // fallback swallowing the throw, which is incidental: that fallback
178
+ // exists to DEGRADE, and removing it (reasonable — on a host-served
179
+ // lane there is no index to fall back to) would have surfaced the
180
+ // sentence as its first act.
181
+ //
182
+ // ⇒ Splitting the two registers removes the ordering hazard entirely
183
+ // rather than documenting it: whatever reaches `error` is now
184
+ // framework-authored and carries no host prose, so the fallback can be
185
+ // removed on its own merits whenever someone wants to.
175
186
  let declined
176
187
  try {
177
188
  declined = (await response.json())?.error
178
189
  } catch {
179
190
  /* not JSON — the status is all there is */
180
191
  }
181
- throw new Error(
182
- typeof declined === 'string' && declined.trim()
183
- ? declined.trim()
184
- : `Search endpoint returned ${response.status}`
185
- )
192
+ if (typeof declined === 'string' && declined.trim()) {
193
+ // Developer register: a console reader needs more than a number.
194
+ console.warn(`[uniweb] search endpoint declined: ${declined.trim()}`)
195
+ }
196
+ throw new Error(`Search endpoint returned ${response.status}`)
186
197
  }
187
198
 
188
199
  const payload = await response.json()