@uniweb/core 0.17.0 → 0.18.0
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 +2 -1
- package/src/datastore.js +11 -2
- package/src/entity-store.js +9 -2
- package/src/fetch-config.js +28 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Core classes for the Uniweb platform - Uniweb, Website, Page, Block",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"./collection-address": "./src/query-address.js",
|
|
10
10
|
"./query-address": "./src/query-address.js",
|
|
11
11
|
"./data-paths": "./src/data-paths.js",
|
|
12
|
+
"./datastore": "./src/datastore.js",
|
|
12
13
|
"./detail-url": "./src/detail-url.js",
|
|
13
14
|
"./fetch-config": "./src/fetch-config.js",
|
|
14
15
|
"./icon-corpus": "./src/icon-corpus.js",
|
package/src/datastore.js
CHANGED
|
@@ -35,12 +35,21 @@
|
|
|
35
35
|
* @returns {string} A stable JSON string usable as a cache-Map key
|
|
36
36
|
*/
|
|
37
37
|
export function deriveCacheKey(request) {
|
|
38
|
-
|
|
38
|
+
// ⭐ `as` is the binding key; `schema` is the name it had until 2026-09-02 and
|
|
39
|
+
// still arrives on every payload published before then. Normalised HERE so one
|
|
40
|
+
// logical request hashes to one key whichever spelling reached us — a consumer
|
|
41
|
+
// deriving a key must not get two entries for the same fetch.
|
|
42
|
+
const { path, url, endpoint, transform } = request || {}
|
|
43
|
+
const as = request?.as ?? request?.schema
|
|
39
44
|
const method = request?.method && request.method.toUpperCase() !== 'GET'
|
|
40
45
|
? request.method.toUpperCase()
|
|
41
46
|
: undefined
|
|
42
47
|
const body = method === 'POST' ? request?.body : undefined
|
|
43
|
-
|
|
48
|
+
// ⚠️ The field NAME is part of the hash, so renaming it moves every key ONCE.
|
|
49
|
+
// In-memory stores repopulate; a consumer with a persistent cache takes one
|
|
50
|
+
// cold pass. Chosen over hashing under the old name, which would have hidden
|
|
51
|
+
// the rename inside the one function whose job is to be canonical.
|
|
52
|
+
return JSON.stringify({ path, url, endpoint, as, transform, method, body })
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
export default class DataStore {
|
package/src/entity-store.js
CHANGED
|
@@ -15,6 +15,13 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { isFetchRefinement, resolveFetchConfigs } from './fetch-config.js'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A fetch config's binding key — the `content.data.<key>` a component reads.
|
|
21
|
+
* `as` is the name; `schema` is what it was called until 2026-09-02 and still
|
|
22
|
+
* arrives on any payload published before then. See `fetch-config.js`.
|
|
23
|
+
*/
|
|
24
|
+
const bindingKeyOf = (cfg) => cfg?.as ?? cfg?.schema
|
|
18
25
|
import { buildDetailConfig } from './detail-url.js'
|
|
19
26
|
|
|
20
27
|
/**
|
|
@@ -201,7 +208,7 @@ export default class EntityStore {
|
|
|
201
208
|
// collecting all cascade matches.
|
|
202
209
|
if (requested === null && block.fetch) {
|
|
203
210
|
const blockFetchList = Array.isArray(block.fetch) ? block.fetch : [block.fetch]
|
|
204
|
-
const schemas = blockFetchList.filter(
|
|
211
|
+
const schemas = blockFetchList.filter(bindingKeyOf).map(bindingKeyOf)
|
|
205
212
|
if (schemas.length > 0) requested = schemas
|
|
206
213
|
}
|
|
207
214
|
|
|
@@ -299,7 +306,7 @@ export default class EntityStore {
|
|
|
299
306
|
let requested = this._getRequestedSchemas(meta)
|
|
300
307
|
if (requested === null && block.fetch) {
|
|
301
308
|
const blockFetchList = Array.isArray(block.fetch) ? block.fetch : [block.fetch]
|
|
302
|
-
const schemas = blockFetchList.filter(
|
|
309
|
+
const schemas = blockFetchList.filter(bindingKeyOf).map(bindingKeyOf)
|
|
303
310
|
if (schemas.length > 0) requested = schemas
|
|
304
311
|
}
|
|
305
312
|
if (requested === null) return { data: null }
|
package/src/fetch-config.js
CHANGED
|
@@ -131,7 +131,7 @@ function applyDeferredDetail(cfg, queries, records) {
|
|
|
131
131
|
// (`{ path: … }`) has no query at all, and its schema — inferred from the path —
|
|
132
132
|
// is the only key there is. Two shapes, two answers; the deleted one had one
|
|
133
133
|
// shape and pretended otherwise.
|
|
134
|
-
const queryName = cfg.query || cfg
|
|
134
|
+
const queryName = cfg.query || bindingKey(cfg)
|
|
135
135
|
if (!queryName || !queries) return cfg
|
|
136
136
|
const collConfig = queries[queryName]
|
|
137
137
|
if (!collConfig || typeof collConfig !== 'object') return cfg
|
|
@@ -182,6 +182,28 @@ function resolveQuerySource(cfg, records) {
|
|
|
182
182
|
return { ...cfg, path: queryDataUrl(cfg.query) }
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
/**
|
|
186
|
+
* The binding key of a fetch config — the `content.data.<key>` a component reads.
|
|
187
|
+
*
|
|
188
|
+
* ⭐ **`as` is the name; `schema` is what it was called until 2026-09-02.** The old
|
|
189
|
+
* spelling still arrives on every payload published before then and on any seed
|
|
190
|
+
* built against an older release, so this is not a deprecation window — it is a
|
|
191
|
+
* permanent reader of stored data. *(Renaming it was not cosmetic: `schema`
|
|
192
|
+
* already means the MODEL REF one record over, on a `queries` declaration, and
|
|
193
|
+
* one word for two things is what let a binding-key override silently break
|
|
194
|
+
* detail resolution.)*
|
|
195
|
+
*
|
|
196
|
+
* ⛔ Do not "simplify" this to `cfg.as`. The `??` here is earned — it spans
|
|
197
|
+
* stored payloads we cannot rewrite — unlike the one deleted from
|
|
198
|
+
* `applyDeferredDetail`, which spanned two producers we control.
|
|
199
|
+
*
|
|
200
|
+
* @param {Object} cfg
|
|
201
|
+
* @returns {string|undefined}
|
|
202
|
+
*/
|
|
203
|
+
function bindingKey(cfg) {
|
|
204
|
+
return cfg?.as ?? cfg?.schema
|
|
205
|
+
}
|
|
206
|
+
|
|
185
207
|
/**
|
|
186
208
|
* Resolve the applicable fetch configs from an ordered list of sources.
|
|
187
209
|
*
|
|
@@ -224,14 +246,15 @@ export function resolveFetchConfigs(sources, options = {}) {
|
|
|
224
246
|
if (!source) continue
|
|
225
247
|
const configList = Array.isArray(source) ? source : [source]
|
|
226
248
|
for (const cfg of configList) {
|
|
227
|
-
|
|
228
|
-
if (
|
|
229
|
-
if (
|
|
249
|
+
const key = bindingKey(cfg)
|
|
250
|
+
if (!key) continue
|
|
251
|
+
if (configs.has(key)) continue
|
|
252
|
+
if (!collectAll && !schemas.includes(key)) continue
|
|
230
253
|
// Address first: localization and deferred-detail both key on `path`,
|
|
231
254
|
// which a query ref does not have until this runs.
|
|
232
255
|
const sourced = resolveQuerySource(cfg, records)
|
|
233
256
|
const localized = localizeConfig(sourced, locale, defaultLocale)
|
|
234
|
-
configs.set(
|
|
257
|
+
configs.set(key, applyDeferredDetail(localized, queries, records))
|
|
235
258
|
}
|
|
236
259
|
}
|
|
237
260
|
|