mikser-io-sdk-api 3.3.0 → 3.5.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/README.md +3 -3
- package/index.d.ts +19 -16
- package/index.js +1 -1
- package/package.json +1 -1
- package/src/asset.js +39 -51
- package/src/entities.js +7 -7
- package/src/href.js +40 -3
package/README.md
CHANGED
|
@@ -305,9 +305,9 @@ const { items } = await docs.list({
|
|
|
305
305
|
|
|
306
306
|
| Cap | Default | Configured at | What triggers it |
|
|
307
307
|
|---|---|---|---|
|
|
308
|
-
| `maxDepth` | 5 | `
|
|
309
|
-
| `maxPaths` | 20 | `
|
|
310
|
-
| `maxResolved` | 100 | `
|
|
308
|
+
| `maxDepth` | 5 | `catalog.expand.maxDepth` | One path is longer than this (`a.b.c.d.e.f` at default) |
|
|
309
|
+
| `maxPaths` | 20 | `catalog.expand.maxPaths` | The `expand` array has more entries than this |
|
|
310
|
+
| `maxResolved` | 100 | `catalog.expand.maxResolved` | Total entity lookups for the request (across all paths) exceeded |
|
|
311
311
|
|
|
312
312
|
```js
|
|
313
313
|
try {
|
package/index.d.ts
CHANGED
|
@@ -302,31 +302,34 @@ export function createHrefIndex(
|
|
|
302
302
|
|
|
303
303
|
export interface AssetRecord {
|
|
304
304
|
url: string
|
|
305
|
-
|
|
306
|
-
height?: number
|
|
307
|
-
srcset?: string
|
|
308
|
-
alt?: string
|
|
305
|
+
/** Raw entity meta block — opaque (mime, dimensions, duration, …). */
|
|
309
306
|
meta?: Record<string, unknown>
|
|
310
307
|
}
|
|
311
308
|
|
|
312
|
-
export interface ImageProps {
|
|
313
|
-
src: string
|
|
314
|
-
width?: number
|
|
315
|
-
height?: number
|
|
316
|
-
srcset?: string
|
|
317
|
-
alt?: string
|
|
318
|
-
}
|
|
319
|
-
|
|
320
309
|
export interface AssetIndex {
|
|
321
310
|
asset(ref: string): AssetRecord | null
|
|
322
|
-
image(ref: string): ImageProps | null
|
|
323
311
|
map: Record<string, AssetRecord>
|
|
324
312
|
}
|
|
325
313
|
|
|
314
|
+
export interface AssetUrlOptions {
|
|
315
|
+
/** Origin of the mikser server; omit for a root-relative URL. */
|
|
316
|
+
baseUrl?: string
|
|
317
|
+
/** Preset output format — replaces the source extension (.mp4 → .jpg). */
|
|
318
|
+
ext?: string
|
|
319
|
+
}
|
|
320
|
+
|
|
326
321
|
/**
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
*
|
|
322
|
+
* URL of a transcoded derivative, by the assets() plugin convention:
|
|
323
|
+
* `<baseUrl>/assets/<preset>/<source>`. Format-neutral (video, image,
|
|
324
|
+
* pdf, audio, …) — mikser's assets() is a preset transcoder, not an
|
|
325
|
+
* image pipeline.
|
|
326
|
+
*/
|
|
327
|
+
export function assetUrl(source: string, preset: string, options?: AssetUrlOptions): string
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Build a format-neutral lookup (id → { url, meta }) from a snapshot of
|
|
331
|
+
* managed asset entities. Pure data transformation — wrap in a
|
|
332
|
+
* framework-specific reactive shell to drive `useAsset` composables.
|
|
330
333
|
*/
|
|
331
334
|
export function createAssetIndex(
|
|
332
335
|
assets: Array<{ id: string; meta?: Record<string, unknown> }>,
|
package/index.js
CHANGED
|
@@ -65,4 +65,4 @@ export function createClient({
|
|
|
65
65
|
export { MikserError }
|
|
66
66
|
export { generateMikserRoutes } from './src/routes.js'
|
|
67
67
|
export { createHrefIndex } from './src/href.js'
|
|
68
|
-
export { createAssetIndex }
|
|
68
|
+
export { createAssetIndex, assetUrl } from './src/asset.js'
|
package/package.json
CHANGED
package/src/asset.js
CHANGED
|
@@ -1,65 +1,53 @@
|
|
|
1
|
-
// Asset metadata
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
|
|
1
|
+
// Asset URLs + metadata — format-neutral. mikser's assets() plugin is a
|
|
2
|
+
// preset transcoder (video, image, pdf, audio, …), not an image pipeline,
|
|
3
|
+
// so neither is this: it models a (source, preset) → derivative-URL
|
|
4
|
+
// convention plus an opaque metadata lookup. Image-specific concerns
|
|
5
|
+
// (srcset, dimensions, <img> props) are a consumer concern — build them
|
|
6
|
+
// on top of `meta` where you actually know an asset is an image.
|
|
7
|
+
import { joinUrl } from './url.js'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
* @returns {{
|
|
12
|
-
* asset: (ref: string) => AssetRecord|null,
|
|
13
|
-
* image: (ref: string) => ImageProps|null,
|
|
14
|
-
* map: Record<string, AssetRecord>,
|
|
15
|
-
* }}
|
|
10
|
+
* URL of a transcoded derivative, by the assets() plugin convention:
|
|
16
11
|
*
|
|
17
|
-
*
|
|
18
|
-
* @property {string} url
|
|
19
|
-
* @property {number|undefined} width
|
|
20
|
-
* @property {number|undefined} height
|
|
21
|
-
* @property {string|undefined} srcset
|
|
22
|
-
* @property {string|undefined} alt
|
|
23
|
-
* @property {object|undefined} meta The raw meta block, for downstream use.
|
|
12
|
+
* <baseUrl>/assets/<preset>/<source>
|
|
24
13
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* @
|
|
14
|
+
* `source` is the source ref, e.g. `/media/bg/clip.mp4`. `ext`, when
|
|
15
|
+
* given, is the preset's output format and REPLACES the source extension
|
|
16
|
+
* (a poster preset turns .mp4 → .jpg); omit it to keep the source ext.
|
|
17
|
+
* `baseUrl` is optional — omit for a same-origin, root-relative URL.
|
|
18
|
+
*
|
|
19
|
+
* @param {string} source
|
|
20
|
+
* @param {string} preset
|
|
21
|
+
* @param {{ baseUrl?: string, ext?: string }} [options]
|
|
22
|
+
* @returns {string}
|
|
23
|
+
*/
|
|
24
|
+
export function assetUrl(source, preset, { baseUrl = '', ext } = {}) {
|
|
25
|
+
if (!source || !preset) return ''
|
|
26
|
+
const file = ext ? source.replace(/\.[^./]+$/, `.${ext}`) : source
|
|
27
|
+
const path = `/assets/${preset}/${file.replace(/^\/+/, '')}`
|
|
28
|
+
return baseUrl ? joinUrl(baseUrl, path) : path
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Format-neutral lookup for managed asset entities that carry their own
|
|
33
|
+
* URL/metadata. `asset(ref)` → `{ url, meta }` | null, keyed by entity
|
|
34
|
+
* `id`. `meta` is the entity's raw meta block, opaque — mime, dimensions,
|
|
35
|
+
* duration, whatever the preset emitted. No image semantics: a consumer
|
|
36
|
+
* that knows an asset is an image reads `meta.width`/`meta.srcset` itself.
|
|
37
|
+
*
|
|
38
|
+
* @param {Array<{id: string, meta?: object}>} assets
|
|
39
|
+
* @returns {{ asset: (ref: string) => ({url: string, meta?: object}|null), map: Record<string, {url: string, meta?: object}> }}
|
|
31
40
|
*/
|
|
32
41
|
export function createAssetIndex(assets) {
|
|
33
42
|
const map = {}
|
|
34
43
|
if (Array.isArray(assets)) {
|
|
35
44
|
for (const a of assets) {
|
|
36
45
|
if (!a?.id) continue
|
|
37
|
-
map[a.id] = {
|
|
38
|
-
url: a.meta?.destination ?? a.meta?.url ?? a.id,
|
|
39
|
-
width: a.meta?.width,
|
|
40
|
-
height: a.meta?.height,
|
|
41
|
-
srcset: a.meta?.srcset,
|
|
42
|
-
alt: a.meta?.alt,
|
|
43
|
-
meta: a.meta,
|
|
44
|
-
}
|
|
46
|
+
map[a.id] = { url: a.meta?.destination ?? a.meta?.url ?? a.id, meta: a.meta }
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
return {
|
|
50
|
+
asset: (ref) => map[ref] ?? null,
|
|
51
|
+
map,
|
|
50
52
|
}
|
|
51
|
-
|
|
52
|
-
function image(ref) {
|
|
53
|
-
const a = map[ref]
|
|
54
|
-
if (!a) return null
|
|
55
|
-
return {
|
|
56
|
-
src: a.url,
|
|
57
|
-
width: a.width,
|
|
58
|
-
height: a.height,
|
|
59
|
-
srcset: a.srcset,
|
|
60
|
-
alt: a.alt,
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return { asset, image, map }
|
|
65
53
|
}
|
package/src/entities.js
CHANGED
|
@@ -51,7 +51,7 @@ const GET_MAX_URL = 1800
|
|
|
51
51
|
// console). Server-side has a matching warning that fires for all
|
|
52
52
|
// clients regardless of SDK use.
|
|
53
53
|
const WIDE_RESPONSE_ITEMS = 50
|
|
54
|
-
const
|
|
54
|
+
const warnedShapes = new Set()
|
|
55
55
|
|
|
56
56
|
function isProductionEnv() {
|
|
57
57
|
try {
|
|
@@ -74,8 +74,8 @@ function maybeWarnWide({ endpoint, query, envelopeOrItems, quiet }) {
|
|
|
74
74
|
const hasFields = Array.isArray(query?.fields) && query.fields.length > 0
|
|
75
75
|
if (hasFields) return
|
|
76
76
|
const shape = `${endpoint}|${JSON.stringify(query?.filter ?? null)}|${JSON.stringify(query?.sort ?? null)}`
|
|
77
|
-
if (
|
|
78
|
-
|
|
77
|
+
if (warnedShapes.has(shape)) return
|
|
78
|
+
warnedShapes.add(shape)
|
|
79
79
|
let sizeNote = ''
|
|
80
80
|
try {
|
|
81
81
|
const bytes = JSON.stringify(items).length
|
|
@@ -100,7 +100,7 @@ function maybeWarnWide({ endpoint, query, envelopeOrItems, quiet }) {
|
|
|
100
100
|
// calls without noticing the snapshot is no longer involved. Deduped
|
|
101
101
|
// per (endpoint, kind, what-was-set) so a page with 3 filtered calls
|
|
102
102
|
// produces 3 warnings, not 30.
|
|
103
|
-
const
|
|
103
|
+
const bypassedShapes = new Set()
|
|
104
104
|
function maybeWarnSnapshotBypass({ endpoint, kind, filter, sort, skip, quiet }) {
|
|
105
105
|
if (quiet || isProductionEnv() || isQuiet()) return
|
|
106
106
|
const reasons = []
|
|
@@ -110,8 +110,8 @@ function maybeWarnSnapshotBypass({ endpoint, kind, filter, sort, skip, quiet })
|
|
|
110
110
|
if (reasons.length === 0) return
|
|
111
111
|
const reasonLabel = reasons.join('+')
|
|
112
112
|
const shape = `${endpoint}|${kind}|${reasonLabel}`
|
|
113
|
-
if (
|
|
114
|
-
|
|
113
|
+
if (bypassedShapes.has(shape)) return
|
|
114
|
+
bypassedShapes.add(shape)
|
|
115
115
|
const fallback = kind === 'live' ? 'live list()' : 'paginated fetch'
|
|
116
116
|
console.warn(
|
|
117
117
|
`[mikser-sdk] data.catalog is set on "${endpoint}" but this ${kind}() call uses ${reasonLabel} — snapshot bypassed, falling back to ${fallback}.\n` +
|
|
@@ -776,7 +776,7 @@ export function createEntitiesClient({ baseUrl, basePath, fetch: doFetch, header
|
|
|
776
776
|
return api
|
|
777
777
|
}
|
|
778
778
|
|
|
779
|
-
return { list, listAll, urlFor, cacheKeyFor, pages, paginator, watch, live, update, delete: remove, render }
|
|
779
|
+
return { list, listAll, urlFor, cacheKeyFor, pages, paginator, watch, live, update, delete: remove, render, baseUrl }
|
|
780
780
|
}
|
|
781
781
|
}
|
|
782
782
|
|
package/src/href.js
CHANGED
|
@@ -22,20 +22,31 @@
|
|
|
22
22
|
* @returns {{
|
|
23
23
|
* href: (ref: string, lang?: string) => string,
|
|
24
24
|
* refFor: (url: string|null) => string|null,
|
|
25
|
+
* docFor: (ref: string, lang?: string) => object|null,
|
|
26
|
+
* metaFor: (ref: string, lang?: string) => object|null,
|
|
25
27
|
* alternates: (opts: { route: string|null, languages?: string[] }) => { current: {lang, url, ref}|null, alternates: Array<{lang, url}> },
|
|
26
28
|
* map: Record<string, Record<string, string>>,
|
|
27
29
|
* }}
|
|
28
30
|
*/
|
|
29
31
|
export function createHrefIndex(documents, { defaultLang = 'default' } = {}) {
|
|
30
32
|
const map = {}
|
|
33
|
+
// ref → lang → document. The index already iterates every document
|
|
34
|
+
// with its full meta to build `map`; keeping the document here too
|
|
35
|
+
// turns the href index into a content index — `metaFor('/menu')`
|
|
36
|
+
// reads a known document by its logical reference, the companion to
|
|
37
|
+
// `href('/menu')` resolving the URL. Costs one extra object slot per
|
|
38
|
+
// document; the data was already in hand.
|
|
39
|
+
const docs = {}
|
|
31
40
|
if (Array.isArray(documents)) {
|
|
32
41
|
for (const document of documents) {
|
|
33
42
|
const ref = document?.meta?.href
|
|
34
43
|
if (!ref) continue
|
|
35
44
|
const lang = document.meta?.lang ?? defaultLang
|
|
36
45
|
const url = document.meta?.route ?? document.meta?.destination ?? ref
|
|
37
|
-
if (!map[ref])
|
|
38
|
-
|
|
46
|
+
if (!map[ref]) map[ref] = {}
|
|
47
|
+
if (!docs[ref]) docs[ref] = {}
|
|
48
|
+
map[ref][lang] = url
|
|
49
|
+
docs[ref][lang] = document
|
|
39
50
|
}
|
|
40
51
|
}
|
|
41
52
|
|
|
@@ -56,6 +67,32 @@ export function createHrefIndex(documents, { defaultLang = 'default' } = {}) {
|
|
|
56
67
|
?? ref
|
|
57
68
|
}
|
|
58
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Resolve a logical reference to its document — the content
|
|
72
|
+
* companion to href(). Same lang-fallback chain (requested lang →
|
|
73
|
+
* 'default' → any available). Returns null when the ref isn't in
|
|
74
|
+
* the index (a missing document can't be faked the way a missing
|
|
75
|
+
* URL falls back to the ref string).
|
|
76
|
+
*/
|
|
77
|
+
function docFor(ref, lang) {
|
|
78
|
+
const target = lang ?? defaultLang
|
|
79
|
+
const entry = docs[ref]
|
|
80
|
+
if (!entry) return null
|
|
81
|
+
return entry[target]
|
|
82
|
+
?? entry['default']
|
|
83
|
+
?? Object.values(entry)[0]
|
|
84
|
+
?? null
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The meta of the document a logical reference resolves to — the
|
|
89
|
+
* 90% case (read fields off known content by its ref). Shorthand
|
|
90
|
+
* for `docFor(ref, lang)?.meta`.
|
|
91
|
+
*/
|
|
92
|
+
function metaFor(ref, lang) {
|
|
93
|
+
return docFor(ref, lang)?.meta ?? null
|
|
94
|
+
}
|
|
95
|
+
|
|
59
96
|
/**
|
|
60
97
|
* Reverse lookup — given a deployed URL, return the logical
|
|
61
98
|
* reference it belongs to (or null if it's not in the index).
|
|
@@ -106,5 +143,5 @@ export function createHrefIndex(documents, { defaultLang = 'default' } = {}) {
|
|
|
106
143
|
return { current, alternates: list }
|
|
107
144
|
}
|
|
108
145
|
|
|
109
|
-
return { href, refFor, alternates, map }
|
|
146
|
+
return { href, refFor, docFor, metaFor, alternates, map }
|
|
110
147
|
}
|