@kosdev-code/kos-asset-manager 0.0.1-next.29 → 0.0.1-next.30
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 +65 -0
- package/bin/kos-assets.mjs +144 -8
- package/bin/lib/declare-assets.mjs +147 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -119,6 +119,71 @@ keys when the declaration is generated:
|
|
|
119
119
|
|
|
120
120
|
A pattern that matches nothing is reported during the build.
|
|
121
121
|
|
|
122
|
+
## Media somewhere else
|
|
123
|
+
|
|
124
|
+
`src/assets/media` is the ui default. A content project — a brandset, a
|
|
125
|
+
descriptor pack — usually keeps its media elsewhere and ships it at a
|
|
126
|
+
different path inside the kab, so both are settable:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"kondra": {
|
|
131
|
+
"ui": {
|
|
132
|
+
"assets": {
|
|
133
|
+
"mediaSrc": "assets/logos",
|
|
134
|
+
"mediaRoot": "/logos",
|
|
135
|
+
"groups": { "boot": ["coke/**"] }
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`mediaSrc` is where the files are **on disk**, relative to the project root.
|
|
143
|
+
`mediaRoot` is where they land **inside the kab**, which is what urls are
|
|
144
|
+
built from. They are two different things — a project using vite's
|
|
145
|
+
`publicDir` drops the directory name on the way out, so `assets/logos` on
|
|
146
|
+
disk is `/logos` in the kab — and neither can be derived from the other.
|
|
147
|
+
Leave both out and you get `src/assets/media` and `/assets/media`.
|
|
148
|
+
|
|
149
|
+
Keys are still relative to `mediaSrc`, so `assets/logos/coke/pour.svg` is the
|
|
150
|
+
key `coke/pour`, and bindings, groups and tags work exactly as they do
|
|
151
|
+
anywhere else.
|
|
152
|
+
|
|
153
|
+
The build checks its work: every declared file has to be in the build output
|
|
154
|
+
under `mediaRoot`, and if none of them are the build fails naming the setting
|
|
155
|
+
rather than leaving a kab whose every image 404s on the device.
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
kos-assets: 214 declared assets are not in the build output under
|
|
159
|
+
/assets/media — check mediaRoot in .kos.json, and that the build copies
|
|
160
|
+
the media into dist/content/ui-brandset/assets/media
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
You don't have to work either of them out by hand. `kos-assets init` looks
|
|
164
|
+
for the media on disk, and reads where the build puts it out of the build
|
|
165
|
+
output — exact, where guessing from the source path would be wrong for any
|
|
166
|
+
project that rewrites paths on the way out:
|
|
167
|
+
|
|
168
|
+
```sh
|
|
169
|
+
npx nx run ui-brandset:build # so there is an output to read
|
|
170
|
+
npx kos-assets init content/ui-brandset
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
kos-assets: found media in assets/logos
|
|
175
|
+
kos-assets: it is served from /logos in the kab
|
|
176
|
+
kos-assets: recorded the media location in content/ui-brandset/.kos.json
|
|
177
|
+
kos-assets: added the assets target to content/ui-brandset/project.json
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
It writes only what it can establish and never touches a value already
|
|
181
|
+
there, so a project it gets wrong is corrected by setting it and running
|
|
182
|
+
again. Without a build output it records `mediaSrc` and says it could not
|
|
183
|
+
tell what the root is, rather than guessing one. The target it writes then
|
|
184
|
+
scans the right folder and follows the project's own `descriptor` target
|
|
185
|
+
wherever that writes.
|
|
186
|
+
|
|
122
187
|
## Installing
|
|
123
188
|
|
|
124
189
|
```sh
|
package/bin/kos-assets.mjs
CHANGED
|
@@ -10,11 +10,13 @@
|
|
|
10
10
|
* adds the target that runs it to the project.
|
|
11
11
|
*/
|
|
12
12
|
import { existsSync } from 'node:fs';
|
|
13
|
-
import { join, resolve } from 'node:path';
|
|
13
|
+
import { dirname, join, resolve } from 'node:path';
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
|
-
SOURCE_DIR,
|
|
17
16
|
buildAssets,
|
|
17
|
+
detectMediaRoot,
|
|
18
|
+
detectMediaSrc,
|
|
19
|
+
mediaSource,
|
|
18
20
|
readJson,
|
|
19
21
|
writeJson,
|
|
20
22
|
} from './lib/declare-assets.mjs';
|
|
@@ -24,10 +26,129 @@ const fail = (message) => {
|
|
|
24
26
|
process.exit(1);
|
|
25
27
|
};
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
/**
|
|
30
|
+
* The declared paths are only useful if the files are actually in the kab at
|
|
31
|
+
* the root the declaration names. The build output is what gets zipped, so
|
|
32
|
+
* it can be checked here -- which turns a wrong `mediaRoot` into a build
|
|
33
|
+
* error rather than an image that 404s on the device.
|
|
34
|
+
*/
|
|
35
|
+
const verifyContents = (assets, outputDir) => {
|
|
36
|
+
const missing = Object.values(assets.entries).filter(
|
|
37
|
+
(entry) => !existsSync(join(outputDir, assets.root, entry.path))
|
|
30
38
|
);
|
|
39
|
+
if (missing.length === 0) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const total = Object.keys(assets.entries).length;
|
|
44
|
+
const root = assets.root || '/';
|
|
45
|
+
if (missing.length === total) {
|
|
46
|
+
fail(
|
|
47
|
+
`${total} declared assets are not in the build output under ${root} — ` +
|
|
48
|
+
`check mediaRoot in .kos.json, and that the build copies the media ` +
|
|
49
|
+
`into ${join(outputDir, assets.root)}`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
console.warn(
|
|
53
|
+
`kos-assets: ${missing.length} of ${total} declared assets are not in ` +
|
|
54
|
+
`the build output: ${missing
|
|
55
|
+
.slice(0, 5)
|
|
56
|
+
.map((entry) => entry.path)
|
|
57
|
+
.join(', ')}${missing.length > 5 ? ', …' : ''}`
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/** Where the descriptor lands unless the project says otherwise. */
|
|
62
|
+
const defaultDescriptor = (projectRoot) =>
|
|
63
|
+
join('dist', projectRoot, 'descriptor.json');
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The media directory the project declares, for the target's inputs. A
|
|
67
|
+
* project that keeps its media somewhere else still has to invalidate the
|
|
68
|
+
* cache when it changes.
|
|
69
|
+
*/
|
|
70
|
+
const readDeclared = (projectRoot) => {
|
|
71
|
+
const dotKos = resolve(projectRoot, '.kos.json');
|
|
72
|
+
return existsSync(dotKos)
|
|
73
|
+
? readJson(dotKos)?.kondra?.ui?.assets ?? {}
|
|
74
|
+
: {};
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const mediaGlob = (declared) => mediaSource(declared).join('/');
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Write a detected media location into the project's .kos.json, so a project
|
|
81
|
+
* that keeps its media somewhere other than the ui default is wired up
|
|
82
|
+
* without having to be told where it is.
|
|
83
|
+
*
|
|
84
|
+
* Only what can be established is written: `mediaSrc` comes off the disk,
|
|
85
|
+
* and `mediaRoot` off a build output, which is exact where guessing from the
|
|
86
|
+
* source path would be wrong for any project that rewrites paths on the way
|
|
87
|
+
* out. Nothing already declared is touched.
|
|
88
|
+
*/
|
|
89
|
+
const detectLayout = (projectRoot, declared, outputDir) => {
|
|
90
|
+
const dotKos = resolve(projectRoot, '.kos.json');
|
|
91
|
+
if (!existsSync(dotKos)) {
|
|
92
|
+
return declared;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const found = { ...declared };
|
|
96
|
+
if (!found.mediaSrc) {
|
|
97
|
+
const detected = detectMediaSrc(projectRoot);
|
|
98
|
+
if (detected) {
|
|
99
|
+
found.mediaSrc = detected;
|
|
100
|
+
console.log(`kos-assets: found media in ${detected}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (found.mediaSrc && found.mediaRoot === undefined) {
|
|
104
|
+
const root = detectMediaRoot(
|
|
105
|
+
projectRoot,
|
|
106
|
+
mediaSource(found),
|
|
107
|
+
resolve(outputDir)
|
|
108
|
+
);
|
|
109
|
+
if (root === undefined) {
|
|
110
|
+
console.warn(
|
|
111
|
+
`kos-assets: could not tell where ${found.mediaSrc} ends up inside ` +
|
|
112
|
+
`the kab — build the project and run init again, or set ` +
|
|
113
|
+
`kondra.ui.assets.mediaRoot in .kos.json`
|
|
114
|
+
);
|
|
115
|
+
} else {
|
|
116
|
+
found.mediaRoot = root;
|
|
117
|
+
console.log(`kos-assets: it is served from ${root || '/'} in the kab`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (found.mediaSrc === declared.mediaSrc &&
|
|
122
|
+
found.mediaRoot === declared.mediaRoot) {
|
|
123
|
+
return declared;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const kos = readJson(dotKos);
|
|
127
|
+
kos.kondra = {
|
|
128
|
+
...kos.kondra,
|
|
129
|
+
ui: { ...kos.kondra?.ui, assets: { ...kos.kondra?.ui?.assets, ...found } },
|
|
130
|
+
};
|
|
131
|
+
writeJson(dotKos, kos);
|
|
132
|
+
console.log(`kos-assets: recorded the media location in ${dotKos}`);
|
|
133
|
+
return found;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Where the project's descriptor target writes, which is not always
|
|
138
|
+
* `dist/<projectRoot>` -- content projects in particular often point
|
|
139
|
+
* somewhere else, and the assets target has to follow it.
|
|
140
|
+
*/
|
|
141
|
+
const descriptorTarget = (project, projectRoot) => {
|
|
142
|
+
const options = project.targets?.descriptor?.options;
|
|
143
|
+
if (!options?.outputPath) {
|
|
144
|
+
return defaultDescriptor(projectRoot);
|
|
145
|
+
}
|
|
146
|
+
const dir = options.outputPath.replace('{projectRoot}', projectRoot);
|
|
147
|
+
return join(dir, options.fileName ?? 'descriptor.json');
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const build = (projectRoot, out) => {
|
|
151
|
+
const descriptorPath = resolve(out ?? defaultDescriptor(projectRoot));
|
|
31
152
|
if (!existsSync(descriptorPath)) {
|
|
32
153
|
fail(
|
|
33
154
|
`no descriptor at ${descriptorPath} — run the descriptor target first, or pass --out`
|
|
@@ -40,6 +161,8 @@ const build = (projectRoot, out) => {
|
|
|
40
161
|
return;
|
|
41
162
|
}
|
|
42
163
|
|
|
164
|
+
verifyContents(assets, dirname(descriptorPath));
|
|
165
|
+
|
|
43
166
|
const descriptor = readJson(descriptorPath);
|
|
44
167
|
descriptor.kondra = {
|
|
45
168
|
...descriptor.kondra,
|
|
@@ -81,17 +204,30 @@ const init = (projectRoot) => {
|
|
|
81
204
|
|
|
82
205
|
const project = readJson(path);
|
|
83
206
|
project.targets = project.targets ?? {};
|
|
207
|
+
|
|
208
|
+
// follow the project's own descriptor target rather than assuming where it
|
|
209
|
+
// writes, so a content project is wired correctly without a manual --out
|
|
210
|
+
const descriptor = descriptorTarget(project, projectRoot);
|
|
211
|
+
const out =
|
|
212
|
+
descriptor === defaultDescriptor(projectRoot) ? '' : ` --out ${descriptor}`;
|
|
213
|
+
|
|
214
|
+
const declared = detectLayout(
|
|
215
|
+
projectRoot,
|
|
216
|
+
readDeclared(projectRoot),
|
|
217
|
+
dirname(descriptor)
|
|
218
|
+
);
|
|
219
|
+
|
|
84
220
|
// the declaration is written into a build output, so nx needs to know what
|
|
85
221
|
// it reads and what it produces — otherwise a restored build can be paired
|
|
86
222
|
// with a freshly scanned declaration and the kab ships a mismatch
|
|
87
223
|
project.targets.assets = {
|
|
88
|
-
command: `${invocation()} build ${projectRoot}`,
|
|
224
|
+
command: `${invocation()} build ${projectRoot}${out}`,
|
|
89
225
|
dependsOn: ['descriptor'],
|
|
90
226
|
inputs: [
|
|
91
|
-
`{projectRoot}/${
|
|
227
|
+
`{projectRoot}/${mediaGlob(declared)}/**/*`,
|
|
92
228
|
'{projectRoot}/.kos.json',
|
|
93
229
|
],
|
|
94
|
-
outputs: [
|
|
230
|
+
outputs: [`{workspaceRoot}/${descriptor}`],
|
|
95
231
|
};
|
|
96
232
|
|
|
97
233
|
const zip = project.targets.zip;
|
|
@@ -12,6 +12,26 @@ import { join, resolve } from 'node:path';
|
|
|
12
12
|
|
|
13
13
|
const SOURCE_DIR = ['src', 'assets', 'media'];
|
|
14
14
|
const ASSETS_ROOT = '/assets/media';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Where a project keeps its media, and where that media ends up inside the
|
|
18
|
+
* kab. They are two different things -- the project's build step decides the
|
|
19
|
+
* mapping between them, and a content project using vite's `publicDir` drops
|
|
20
|
+
* the directory name on the way out -- so neither can be derived from the
|
|
21
|
+
* other. A project that doesn't say gets the ui defaults.
|
|
22
|
+
*
|
|
23
|
+
* "assets": { "mediaSrc": "assets/logos", "mediaRoot": "/logos" }
|
|
24
|
+
*/
|
|
25
|
+
const mediaSource = (declared) =>
|
|
26
|
+
declared.mediaSrc ? declared.mediaSrc.split('/').filter(Boolean) : SOURCE_DIR;
|
|
27
|
+
|
|
28
|
+
const mediaRoot = (declared) => {
|
|
29
|
+
if (!declared.mediaRoot) {
|
|
30
|
+
return declared.mediaSrc ? '' : ASSETS_ROOT;
|
|
31
|
+
}
|
|
32
|
+
const trimmed = declared.mediaRoot.replace(/\/+$/, '');
|
|
33
|
+
return trimmed === '/' || trimmed === '' ? '' : `/${trimmed.replace(/^\/+/, '')}`;
|
|
34
|
+
};
|
|
15
35
|
const TYPES = {
|
|
16
36
|
'.avif': 'image/avif',
|
|
17
37
|
'.gif': 'image/gif',
|
|
@@ -243,6 +263,114 @@ const boundKey = (rel, bindings) => {
|
|
|
243
263
|
return undefined;
|
|
244
264
|
};
|
|
245
265
|
|
|
266
|
+
/** Never a project's own media, and expensive to walk. */
|
|
267
|
+
const SKIP_DIRS = new Set([
|
|
268
|
+
'node_modules',
|
|
269
|
+
'dist',
|
|
270
|
+
'tmp',
|
|
271
|
+
'coverage',
|
|
272
|
+
'.git',
|
|
273
|
+
'.nx',
|
|
274
|
+
'.kos',
|
|
275
|
+
]);
|
|
276
|
+
|
|
277
|
+
/** Every media file below a directory, by extension, with its path. */
|
|
278
|
+
const scanMedia = (dir, prefix = '') =>
|
|
279
|
+
readdirSync(dir, { withFileTypes: true }).flatMap((item) => {
|
|
280
|
+
if (item.name.startsWith('.') || SKIP_DIRS.has(item.name)) return [];
|
|
281
|
+
const rel = prefix ? `${prefix}/${item.name}` : item.name;
|
|
282
|
+
if (item.isDirectory()) return scanMedia(join(dir, item.name), rel);
|
|
283
|
+
const ext = item.name.slice(item.name.lastIndexOf('.')).toLowerCase();
|
|
284
|
+
return TYPES[ext] ? [rel] : [];
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
/** The deepest directory every one of these paths sits under. */
|
|
288
|
+
const commonDir = (paths) => {
|
|
289
|
+
const segments = paths.map((path) => path.split('/').slice(0, -1));
|
|
290
|
+
const [first = [], ...rest] = segments;
|
|
291
|
+
let shared = first;
|
|
292
|
+
for (const other of rest) {
|
|
293
|
+
let i = 0;
|
|
294
|
+
while (i < shared.length && shared[i] === other[i]) i += 1;
|
|
295
|
+
shared = shared.slice(0, i);
|
|
296
|
+
}
|
|
297
|
+
return shared.join('/');
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
/** True when this directory holds media, or leads to some. */
|
|
301
|
+
const holdsMedia = (dir) => scanMedia(dir).length > 0;
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* The common ancestor of a project's media is too deep when the media
|
|
305
|
+
* happens to sit in one subfolder -- a brandset with a single brand would be
|
|
306
|
+
* read as that brand. So climb back up while the parent holds nothing but
|
|
307
|
+
* media, which stops at the directory the project actually treats as its
|
|
308
|
+
* media root: the one with something else beside it.
|
|
309
|
+
*/
|
|
310
|
+
const climbToMedia = (projectRoot, dir) => {
|
|
311
|
+
const segments = dir.split('/').filter(Boolean);
|
|
312
|
+
while (segments.length > 1) {
|
|
313
|
+
const parent = segments.slice(0, -1);
|
|
314
|
+
const entries = readdirSync(resolve(projectRoot, ...parent), {
|
|
315
|
+
withFileTypes: true,
|
|
316
|
+
}).filter(
|
|
317
|
+
(item) => !item.name.startsWith('.') && !SKIP_DIRS.has(item.name)
|
|
318
|
+
);
|
|
319
|
+
const onlyMedia = entries.every((item) =>
|
|
320
|
+
item.isDirectory()
|
|
321
|
+
? holdsMedia(resolve(projectRoot, ...parent, item.name))
|
|
322
|
+
: TYPES[item.name.slice(item.name.lastIndexOf('.')).toLowerCase()]
|
|
323
|
+
);
|
|
324
|
+
if (!onlyMedia) {
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
segments.pop();
|
|
328
|
+
}
|
|
329
|
+
return segments.join('/');
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Where a project already keeps its media, for a project that hasn't said.
|
|
334
|
+
* Returns undefined when it is already in the ui default place, or when
|
|
335
|
+
* there is no media to find.
|
|
336
|
+
*/
|
|
337
|
+
const detectMediaSrc = (projectRoot) => {
|
|
338
|
+
if (existsSync(resolve(projectRoot, ...SOURCE_DIR))) {
|
|
339
|
+
return undefined;
|
|
340
|
+
}
|
|
341
|
+
const found = scanMedia(resolve(projectRoot));
|
|
342
|
+
if (found.length === 0) {
|
|
343
|
+
return undefined;
|
|
344
|
+
}
|
|
345
|
+
const dir = commonDir(found);
|
|
346
|
+
return dir === '' ? undefined : climbToMedia(projectRoot, dir);
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Where a media directory ends up inside the kab, read off a build output
|
|
351
|
+
* rather than guessed: find a file the build already copied and take the
|
|
352
|
+
* path it was copied to. Undefined when the project hasn't been built, or
|
|
353
|
+
* when the build doesn't carry the media at all.
|
|
354
|
+
*/
|
|
355
|
+
const detectMediaRoot = (projectRoot, source, outputDir) => {
|
|
356
|
+
const mediaDir = resolve(projectRoot, ...source);
|
|
357
|
+
if (!existsSync(mediaDir) || !existsSync(outputDir)) {
|
|
358
|
+
return undefined;
|
|
359
|
+
}
|
|
360
|
+
const [sample] = scanMedia(mediaDir);
|
|
361
|
+
if (!sample) {
|
|
362
|
+
return undefined;
|
|
363
|
+
}
|
|
364
|
+
const built = scanMedia(resolve(outputDir)).filter(
|
|
365
|
+
(path) => path === sample || path.endsWith(`/${sample}`)
|
|
366
|
+
);
|
|
367
|
+
if (built.length !== 1) {
|
|
368
|
+
return undefined;
|
|
369
|
+
}
|
|
370
|
+
const root = built[0].slice(0, built[0].length - sample.length);
|
|
371
|
+
return root === '' ? '' : `/${root.replace(/\/+$/, '')}`;
|
|
372
|
+
};
|
|
373
|
+
|
|
246
374
|
const fail = (message) => {
|
|
247
375
|
console.error(`kos-assets: ${message}`);
|
|
248
376
|
process.exit(1);
|
|
@@ -269,16 +397,22 @@ const walk = (dir, prefix = '') =>
|
|
|
269
397
|
* groups and preload flags are authored in .kos.json and carried through.
|
|
270
398
|
*/
|
|
271
399
|
const buildAssets = (projectRoot) => {
|
|
272
|
-
const mediaDir = resolve(projectRoot, ...SOURCE_DIR);
|
|
273
|
-
if (!existsSync(mediaDir)) {
|
|
274
|
-
return undefined;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
400
|
const dotKos = resolve(projectRoot, '.kos.json');
|
|
278
401
|
const declared = existsSync(dotKos)
|
|
279
402
|
? readJson(dotKos)?.kondra?.ui?.assets ?? {}
|
|
280
403
|
: {};
|
|
281
404
|
|
|
405
|
+
const source = mediaSource(declared);
|
|
406
|
+
const mediaDir = resolve(projectRoot, ...source);
|
|
407
|
+
if (!existsSync(mediaDir)) {
|
|
408
|
+
// a project that named its media directory meant it, so a typo there is
|
|
409
|
+
// a build error rather than a project that quietly declares nothing
|
|
410
|
+
if (declared.mediaSrc) {
|
|
411
|
+
fail(`no media directory at ${join(projectRoot, ...source)} (mediaSrc)`);
|
|
412
|
+
}
|
|
413
|
+
return undefined;
|
|
414
|
+
}
|
|
415
|
+
|
|
282
416
|
const bindings = declared.keys ?? {};
|
|
283
417
|
const markers = readMarkers(mediaDir);
|
|
284
418
|
const claimed = new Set();
|
|
@@ -379,7 +513,7 @@ const buildAssets = (projectRoot) => {
|
|
|
379
513
|
}
|
|
380
514
|
|
|
381
515
|
return {
|
|
382
|
-
root:
|
|
516
|
+
root: mediaRoot(declared),
|
|
383
517
|
entries,
|
|
384
518
|
...(Object.keys(groups).length > 0 ? { groups } : {}),
|
|
385
519
|
};
|
|
@@ -390,6 +524,13 @@ export {
|
|
|
390
524
|
SOURCE_DIR,
|
|
391
525
|
ASSETS_ROOT,
|
|
392
526
|
TYPES,
|
|
527
|
+
mediaSource,
|
|
528
|
+
mediaRoot,
|
|
529
|
+
scanMedia,
|
|
530
|
+
commonDir,
|
|
531
|
+
climbToMedia,
|
|
532
|
+
detectMediaSrc,
|
|
533
|
+
detectMediaRoot,
|
|
393
534
|
parseMarker,
|
|
394
535
|
readMarkers,
|
|
395
536
|
bindingMatcher,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kosdev-code/kos-asset-manager",
|
|
3
|
-
"version": "0.0.1-next.
|
|
3
|
+
"version": "0.0.1-next.30",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"types": "./index.d.ts",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"kos": {
|
|
27
27
|
"build": {
|
|
28
|
-
"gitHash": "
|
|
28
|
+
"gitHash": "630400cd67fd24b5cd069b7661dae83277c18934"
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"publishConfig": {
|