nuxt-content-assets 0.7.0 → 0.9.0-alpha

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/dist/module.mjs CHANGED
@@ -1,33 +1,45 @@
1
1
  import * as Fs from 'fs';
2
2
  import * as Path from 'path';
3
3
  import Path__default from 'path';
4
- import { createResolver, defineNuxtModule, addTemplate } from '@nuxt/kit';
4
+ import { createResolver, defineNuxtModule, addPlugin } from '@nuxt/kit';
5
+ import debounce from 'debounce';
5
6
  import getImageSize from 'image-size';
6
- import { hash } from 'ohash';
7
- import glob from 'glob';
8
7
  import { createStorage } from 'unstorage';
9
8
  import githubDriver from 'unstorage/drivers/github';
9
+ import fsDriver from 'unstorage/drivers/fs';
10
+ import { hash } from 'ohash';
11
+ import { WebSocketServer } from 'ws';
12
+ import { listen } from 'listhen';
10
13
 
11
14
  function matchWords(value) {
12
15
  return typeof value === "string" ? value.match(/\w+/g) || [] : [];
13
16
  }
17
+ function toPath(key) {
18
+ return key.replaceAll(":", "/");
19
+ }
20
+ function deKey(path) {
21
+ return path.replace(/^[^:]+:/, "");
22
+ }
14
23
 
15
- const defaults = {
24
+ const defaults$1 = {
16
25
  assetsDir: "/assets/",
17
26
  assetsPattern: "[path]/[file]"
18
27
  };
19
- const imageExtensions = matchWords("png jpg jpeg gif svg webp ico");
20
- const mediaExtensions = matchWords("mp3 m4a wav mp4 mov webm ogg avi flv avchd");
21
- const fileExtensions = matchWords("pdf doc docx xls xlsx ppt pptx odp key");
22
- const extensions = [
23
- ...imageExtensions,
24
- ...mediaExtensions,
25
- ...fileExtensions
26
- ];
28
+ const extensions = {
29
+ image: matchWords("png jpg jpeg gif svg webp ico"),
30
+ media: matchWords("mp3 m4a wav mp4 mov webm ogg avi flv avchd")
31
+ };
27
32
 
28
33
  function isImage(path) {
29
34
  const ext = Path__default.extname(path).substring(1);
30
- return imageExtensions.includes(ext);
35
+ return extensions.image.includes(ext);
36
+ }
37
+ function isArticle(path) {
38
+ return /\.mdx?$/.test(path);
39
+ }
40
+ function isAsset(path) {
41
+ const ext = Path__default.extname(path);
42
+ return !!ext && ext !== ".DS_Store" && !isArticle(path);
31
43
  }
32
44
 
33
45
  const moduleName = "nuxt-content-assets";
@@ -51,10 +63,18 @@ function writeFile(path, data) {
51
63
  createFolder(Path.dirname(path));
52
64
  Fs.writeFileSync(path, text, { encoding: "utf8" });
53
65
  }
66
+ async function writeBlob(path, data) {
67
+ const buffer = Buffer.from(await data.arrayBuffer());
68
+ createFolder(Path.dirname(path));
69
+ Fs.writeFileSync(path, buffer);
70
+ }
54
71
  function copyFile(src, trg) {
55
72
  createFolder(Path.dirname(trg));
56
73
  Fs.copyFileSync(src, trg);
57
74
  }
75
+ function removeFile(src) {
76
+ Fs.rmSync(src);
77
+ }
58
78
  function createFolder(path) {
59
79
  Fs.mkdirSync(path, { recursive: true });
60
80
  }
@@ -65,30 +85,6 @@ function removeFolder(path) {
65
85
  }
66
86
  }
67
87
 
68
- const replacers = {
69
- key: (src) => Path__default.dirname(src).split("/").filter((e) => e).shift() || "",
70
- path: (src) => Path__default.dirname(src),
71
- folder: (src) => Path__default.dirname(src).replace(/[^/]+\//, ""),
72
- file: (src) => Path__default.basename(src),
73
- name: (src) => Path__default.basename(src, Path__default.extname(src)),
74
- extname: (src) => Path__default.extname(src),
75
- ext: (src) => Path__default.extname(src).substring(1),
76
- hash: (src) => hash({ src })
77
- };
78
- function interpolatePattern(pattern, src, warn = false) {
79
- return Path__default.join(pattern.replace(/\[\w+]/g, (match) => {
80
- const name = match.substring(1, match.length - 1);
81
- const fn = replacers[name];
82
- if (fn) {
83
- return fn(src);
84
- }
85
- if (warn) {
86
- log(`Unknown output token ${match}`, true);
87
- }
88
- return match;
89
- }));
90
- }
91
-
92
88
  function getAssetConfig(srcDir, srcAbs, pattern, hints) {
93
89
  let width = void 0;
94
90
  let height = void 0;
@@ -111,45 +107,199 @@ function getAssetConfig(srcDir, srcAbs, pattern, hints) {
111
107
  warn(`could not read image "${srcAbs}`);
112
108
  }
113
109
  }
114
- const srcRel = Path.basename(srcDir) + srcAbs.substring(srcDir.length);
115
- const srcAttr = interpolatePattern(pattern, srcRel);
110
+ const srcRel = Path.relative(srcDir, srcAbs);
111
+ const srcAttr = "/" + srcRel;
116
112
  const id = srcRel.replaceAll("/", ":");
117
113
  return { id, srcRel, srcAttr, width, height, ratio, query };
118
114
  }
119
115
 
120
- async function getGithubAssets(key, source, tempPath, extensions) {
116
+ function makeStorage(source, key = "") {
121
117
  const storage = createStorage();
122
- storage.mount(key, githubDriver({
123
- repo: source.repo,
124
- branch: source.branch || "main",
125
- dir: source.dir || "/",
126
- ttl: source.ttl || 600
127
- }));
128
- const rx = new RegExp(`.${extensions.join("|")}$`);
129
- const keys = await storage.getKeys();
130
- const assetKeys = keys.filter((key2) => rx.test(key2));
131
- const assetItems = await Promise.all(assetKeys.map(async (id) => {
132
- const data = await storage.getItem(id);
133
- return { id, data };
134
- }));
135
- const prefix = source.prefix || "";
136
- const paths = [];
137
- for (const { id, data } of assetItems) {
138
- if (data) {
139
- const path = id.replaceAll(":", "/");
140
- const absPath = Path.join(tempPath, path.replace(key, `${key}/${prefix}`));
141
- const absFolder = Path.dirname(absPath);
142
- const buffer = data.constructor.name === "Blob" ? Buffer.from(await data.arrayBuffer()) : typeof data === "object" ? JSON.stringify(data, null, " ") : String(data);
143
- Fs.mkdirSync(absFolder, { recursive: true });
144
- Fs.writeFileSync(absPath, buffer);
145
- paths.push(absPath);
118
+ const options = typeof source === "string" ? { driver: "fs", base: source } : source;
119
+ switch (options.driver) {
120
+ case "fs":
121
+ storage.mount(key, fsDriver({
122
+ ...options,
123
+ ignore: ["[^:]+?\\.md"]
124
+ }));
125
+ break;
126
+ case "github":
127
+ storage.mount(key, githubDriver({
128
+ branch: "main",
129
+ dir: "/",
130
+ ...options
131
+ }));
132
+ break;
133
+ }
134
+ return storage;
135
+ }
136
+ function makeSourceManager(key, source, publicPath, callback) {
137
+ async function onWatch(event, key2) {
138
+ if (isAsset(key2)) {
139
+ const path = event === "update" ? await copyItem(key2) : removeItem(key2);
140
+ if (callback) {
141
+ callback(event, path);
142
+ }
143
+ }
144
+ }
145
+ function getRelSrc(key2) {
146
+ return toPath(key2).replace(/\w+/, "").replace(source.prefix || "", "");
147
+ }
148
+ function getAbsSrc(key2) {
149
+ return Path.join(source.base, getRelSrc(key2));
150
+ }
151
+ function getRelTrg(key2) {
152
+ return Path.join(source.prefix || "", toPath(deKey(key2)));
153
+ }
154
+ function getAbsTrg(key2) {
155
+ return Path.join(publicPath, getRelTrg(key2));
156
+ }
157
+ function removeItem(key2) {
158
+ const absTrg = getAbsTrg(key2);
159
+ removeFile(absTrg);
160
+ return absTrg;
161
+ }
162
+ async function copyItem(key2) {
163
+ const absTrg = getAbsTrg(key2);
164
+ const driver = source.driver;
165
+ if (driver === "fs") {
166
+ const absSrc = getAbsSrc(key2);
167
+ copyFile(absSrc, absTrg);
168
+ } else if (driver === "github") {
169
+ try {
170
+ const data = await storage.getItem(key2);
171
+ if (data) {
172
+ data?.constructor.name === "Blob" ? await writeBlob(absTrg, data) : writeFile(absTrg, data);
173
+ } else {
174
+ warn(`No data for key "${key2}"`);
175
+ }
176
+ } catch (err) {
177
+ warn(err.message);
178
+ }
146
179
  }
180
+ return absTrg;
147
181
  }
148
- return paths;
182
+ async function getKeys() {
183
+ const keys = await storage.getKeys();
184
+ return keys.filter(isAsset);
185
+ }
186
+ async function init() {
187
+ const keys = await getKeys();
188
+ const paths = [];
189
+ for (const key2 of keys) {
190
+ const path = await copyItem(key2);
191
+ paths.push(path);
192
+ }
193
+ return paths;
194
+ }
195
+ const storage = makeStorage(source, key);
196
+ storage.watch(onWatch);
197
+ return {
198
+ storage,
199
+ init,
200
+ keys: getKeys
201
+ };
149
202
  }
150
- function getFsAssets(path, extensions) {
151
- const pattern = `${path}/**/*.{${extensions.join(",")}}`;
152
- return glob.globSync(pattern) || [];
203
+
204
+ const replacers = {
205
+ key: (src) => Path__default.dirname(src).split("/").filter((e) => e).shift() || "",
206
+ path: (src) => Path__default.dirname(src),
207
+ folder: (src) => Path__default.dirname(src).replace(/[^/]+\//, ""),
208
+ file: (src) => Path__default.basename(src),
209
+ name: (src) => Path__default.basename(src, Path__default.extname(src)),
210
+ extname: (src) => Path__default.extname(src),
211
+ ext: (src) => Path__default.extname(src).substring(1),
212
+ hash: (src) => hash({ src })
213
+ };
214
+ function interpolatePattern(pattern, src, warn = false) {
215
+ return Path__default.join(pattern.replace(/\[\w+]/g, (match) => {
216
+ const name = match.substring(1, match.length - 1);
217
+ const fn = replacers[name];
218
+ if (fn) {
219
+ return fn(src);
220
+ }
221
+ if (warn) {
222
+ log(`Unknown output token ${match}`, true);
223
+ }
224
+ return match;
225
+ }));
226
+ }
227
+
228
+ function createWebSocket() {
229
+ const wss = new WebSocketServer({ noServer: true });
230
+ const serve = (req, socket = req.socket, head = "") => wss.handleUpgrade(req, socket, head, (client) => wss.emit("connection", client, req));
231
+ const broadcast = (data, channel = "*") => {
232
+ data = JSON.stringify({ channel, data });
233
+ for (const client of wss.clients) {
234
+ try {
235
+ client.send(data);
236
+ } catch (err) {
237
+ }
238
+ }
239
+ };
240
+ const handlers = [];
241
+ const onMessage = (channel, callback) => {
242
+ handlers.push({ channel, callback });
243
+ };
244
+ wss.on("connection", (client) => {
245
+ client.addEventListener("message", (event) => {
246
+ try {
247
+ const { channel, data } = JSON.parse(event.data || "{}");
248
+ handlers.filter((handler) => handler.channel === channel || handler.channel === "*").forEach((handler) => handler.callback(data));
249
+ } catch (err) {
250
+ }
251
+ });
252
+ });
253
+ return {
254
+ wss,
255
+ serve,
256
+ broadcast,
257
+ onMessage,
258
+ close: () => {
259
+ wss.clients.forEach((client) => client.close());
260
+ return new Promise((resolve) => wss.close(resolve));
261
+ }
262
+ };
263
+ }
264
+ const ws = createWebSocket();
265
+ let initialized = false;
266
+ const defaults = {
267
+ port: {
268
+ port: 4001,
269
+ portRange: [4001, 4040]
270
+ },
271
+ hostname: "localhost",
272
+ showURL: false
273
+ };
274
+ function useSocketServer(nuxt, channel, onMessage) {
275
+ nuxt.hook("nitro:init", async (nitro) => {
276
+ if (!initialized) {
277
+ initialized = true;
278
+ const { server, url } = await listen(() => "Nuxt Sockets", defaults);
279
+ server.on("upgrade", ws.serve);
280
+ nitro.options.runtimeConfig.public.sockets = {
281
+ wsUrl: url.replace("http", "ws")
282
+ };
283
+ nitro.hooks.hook("close", async () => {
284
+ await ws.close();
285
+ await server.close();
286
+ });
287
+ }
288
+ });
289
+ const instance = {
290
+ send(data) {
291
+ ws.broadcast(data, channel);
292
+ return this;
293
+ },
294
+ onMessage(callback) {
295
+ ws.onMessage(channel, callback);
296
+ return this;
297
+ }
298
+ };
299
+ if (onMessage) {
300
+ instance.onMessage(onMessage);
301
+ }
302
+ return instance;
153
303
  }
154
304
 
155
305
  const resolve = createResolver(import.meta.url).resolve;
@@ -162,9 +312,7 @@ const module = defineNuxtModule({
162
312
  }
163
313
  },
164
314
  defaults: {
165
- output: `${defaults.assetsDir}/${defaults.assetsPattern}`,
166
- extensions: "",
167
- additionalExtensions: "",
315
+ output: `${defaults$1.assetsDir}/${defaults$1.assetsPattern}`,
168
316
  imageSize: "",
169
317
  debug: false
170
318
  },
@@ -174,37 +322,22 @@ const module = defineNuxtModule({
174
322
  const buildPath = nuxt.options.buildDir;
175
323
  const cachePath = Path.join(buildPath, "content-assets");
176
324
  const publicPath = Path.join(cachePath, "public");
177
- const tempPath = Path.resolve("node_modules/.nuxt-content-assets");
178
- const dump = (name, data) => {
179
- const path = `${cachePath}/debug/${name}.json`;
180
- log(`Dumping "${Path.relative("", path)}"`);
181
- writeFile(path, data);
182
- };
325
+ const indexPath = Path.join(cachePath, "assets.json");
183
326
  if (options.debug) {
184
327
  log("Removing cache folders...");
185
328
  }
186
329
  removeFolder(Path.join(buildPath, "content-cache"));
187
330
  removeFolder(cachePath);
188
- removeFolder(tempPath);
189
331
  (_a = nuxt.options).content || (_a.content = {});
190
332
  if (nuxt.options.content) {
191
333
  (_b = nuxt.options.content).ignores || (_b.ignores = []);
192
334
  }
193
- const output = options.output || defaults.assetsDir;
335
+ nuxt.options.content?.ignores.push("^((?!(md|json|yaml|csv)).)*$");
336
+ const output = options.output || defaults$1.assetsDir;
194
337
  const matches = output.match(/([^[]+)(.*)?/);
195
- const assetsDir = matches ? matches[1].replace(/^\/*/, "/").replace(/\/*$/, "") : defaults.assetsDir;
196
- const assetsPattern = (matches ? matches[2] : "") || defaults.assetsPattern;
338
+ const assetsPattern = (matches ? matches[2] : "") || defaults$1.assetsPattern;
197
339
  interpolatePattern(assetsPattern, "", true);
198
340
  const imageFlags = matchWords(options.imageSize);
199
- if (options.extensions?.trim()) {
200
- extensions.splice(0, extensions.length, ...matchWords(options.extensions));
201
- } else if (options.additionalExtensions) {
202
- extensions.push(...matchWords(options.additionalExtensions));
203
- }
204
- if (options.debug) {
205
- log("Preparing sources...");
206
- }
207
- const assets = {};
208
341
  const sources = nuxt.options._layers.map((layer) => layer.config?.content?.sources).reduce((output2, sources2) => {
209
342
  if (sources2) {
210
343
  Object.assign(output2, sources2);
@@ -220,92 +353,71 @@ const module = defineNuxtModule({
220
353
  };
221
354
  }
222
355
  }
223
- for (const [key, source] of Object.entries(sources)) {
224
- const { driver } = source;
225
- let srcDir = "";
226
- let paths = [];
227
- switch (driver) {
228
- case "fs":
229
- paths = getFsAssets(source.base, extensions);
230
- srcDir = source.base;
231
- break;
232
- case "github":
233
- paths = await getGithubAssets(key, source, tempPath, extensions);
234
- srcDir = Path.join(tempPath, key);
235
- break;
236
- }
237
- if (options.debug) {
238
- log(`Prepared ${paths.length} paths for source "${key}"`);
239
- }
240
- if (paths.length) {
241
- paths.forEach((src) => {
242
- const {
243
- id,
244
- srcRel,
245
- srcAttr,
246
- width,
247
- height,
248
- ratio,
249
- query
250
- } = getAssetConfig(srcDir, src, assetsPattern, imageFlags);
251
- nuxt.options.content.ignores.push(id);
252
- const trg = Path.join(publicPath, assetsDir, srcAttr);
253
- assets[srcRel] = {
254
- src,
255
- trg,
256
- config: {
257
- srcAttr: Path.join(assetsDir, srcAttr),
258
- width,
259
- height,
260
- ratio,
261
- query
262
- }
263
- };
264
- });
265
- }
356
+ addPlugin(resolve("./runtime/watcher"));
357
+ const socket = nuxt.options.dev ? useSocketServer(nuxt, "content-assets") : null;
358
+ function removeAsset(src) {
359
+ const srcRel = Path.relative(publicPath, src);
360
+ delete assets[srcRel];
361
+ saveAssets();
362
+ return "/" + srcRel;
266
363
  }
267
- nuxt.hook("build:before", function() {
268
- if (options.debug) {
269
- dump("assets", assets);
364
+ function updateAsset(src) {
365
+ const {
366
+ srcRel,
367
+ srcAttr,
368
+ width,
369
+ height,
370
+ ratio,
371
+ query
372
+ } = getAssetConfig(publicPath, src, assetsPattern, imageFlags);
373
+ assets[srcRel] = {
374
+ srcRel,
375
+ srcAttr,
376
+ width,
377
+ height,
378
+ ratio,
379
+ query
380
+ };
381
+ saveAssets();
382
+ return srcAttr;
383
+ }
384
+ function watchAsset(event, absTrg) {
385
+ const srcAttr = event === "update" ? updateAsset(absTrg) : removeAsset(absTrg);
386
+ if (socket) {
387
+ socket.send({ event: "update", src: srcAttr });
270
388
  }
389
+ }
390
+ const saveAssets = debounce(() => {
391
+ writeFile(indexPath, assets);
392
+ }, 50);
393
+ const assets = {};
394
+ const managers = {};
395
+ for (const [key, source] of Object.entries(sources)) {
271
396
  if (options.debug) {
272
- log(`Copying ${Object.keys(assets).length} assets...`);
273
- }
274
- const copied = [];
275
- const failed = [];
276
- for (const [key, { src, trg }] of Object.entries(assets)) {
277
- if (Fs.existsSync(src)) {
278
- copyFile(src, trg);
279
- copied.push(key);
280
- } else {
281
- failed.push(key);
282
- }
397
+ log(`Creating source "${key}"`);
283
398
  }
284
- if (options.debug) {
285
- if (copied.length) {
286
- list("Copied", copied);
287
- }
288
- if (failed.length) {
289
- list("Failed to copy", failed);
399
+ managers[key] = makeSourceManager(key, source, publicPath, watchAsset);
400
+ }
401
+ nuxt.hook("build:before", async function() {
402
+ for (const [key, manager] of Object.entries(managers)) {
403
+ const paths = await manager.init();
404
+ paths.forEach((path) => updateAsset(path));
405
+ if (options.debug) {
406
+ list(`Copied "${key}" assets`, paths.map((path) => Path.relative(publicPath, path)));
290
407
  }
291
408
  }
292
409
  });
293
- const nitroAssets = Object.entries(assets).reduce((output2, [key, value]) => {
294
- output2[key] = value.config;
295
- return output2;
296
- }, {});
297
410
  const virtualConfig = [
298
- `export const assets = ${JSON.stringify(nitroAssets, null, " ")}`
411
+ // `export const assets = ${JSON.stringify(assets, null, ' ')}`,
412
+ `export const cachePath = '${cachePath}'`
299
413
  ].join("\n");
300
- nuxt.options.alias[`#${moduleName}`] = addTemplate({
301
- filename: `${moduleName}.mjs`,
302
- getContents: () => virtualConfig
303
- }).dst;
304
414
  nuxt.hook("nitro:config", async (config) => {
305
415
  config.plugins || (config.plugins = []);
306
416
  config.plugins.push(pluginPath);
307
417
  config.virtual || (config.virtual = {});
308
- config.virtual[`#${moduleName}`] = virtualConfig;
418
+ config.virtual[`#${moduleName}`] = () => {
419
+ return virtualConfig;
420
+ };
309
421
  config.publicAssets || (config.publicAssets = []);
310
422
  config.publicAssets.push({
311
423
  dir: publicPath
@@ -2,8 +2,8 @@ export declare const defaults: {
2
2
  assetsDir: string;
3
3
  assetsPattern: string;
4
4
  };
5
- export declare const imageExtensions: string[];
6
- export declare const mediaExtensions: string[];
7
- export declare const fileExtensions: string[];
8
- export declare const extensions: string[];
9
5
  export declare const tags: string[];
6
+ export declare const extensions: {
7
+ image: string[];
8
+ media: string[];
9
+ };
@@ -3,12 +3,8 @@ export const defaults = {
3
3
  assetsDir: "/assets/",
4
4
  assetsPattern: "[path]/[file]"
5
5
  };
6
- export const imageExtensions = matchWords("png jpg jpeg gif svg webp ico");
7
- export const mediaExtensions = matchWords("mp3 m4a wav mp4 mov webm ogg avi flv avchd");
8
- export const fileExtensions = matchWords("pdf doc docx xls xlsx ppt pptx odp key");
9
- export const extensions = [
10
- ...imageExtensions,
11
- ...mediaExtensions,
12
- ...fileExtensions
13
- ];
14
6
  export const tags = ["img", "video", "audio", "source", "embed", "iframe", "a"];
7
+ export const extensions = {
8
+ image: matchWords("png jpg jpeg gif svg webp ico"),
9
+ media: matchWords("mp3 m4a wav mp4 mov webm ogg avi flv avchd")
10
+ };
@@ -1,8 +1,20 @@
1
1
  import Path from "path";
2
2
  import { visit } from "unist-util-visit";
3
- import { isValidAsset, walk } from "./utils/index.mjs";
3
+ import { deKey, isValidAsset, toPath, walk } from "./utils/index.mjs";
4
4
  import { tags } from "./options.mjs";
5
- import { assets } from "#nuxt-content-assets";
5
+ import { cachePath } from "#nuxt-content-assets";
6
+ import { makeStorage } from "./services/index.mjs";
7
+ async function updateAssets() {
8
+ assets = await storage.getItem("assets.json");
9
+ }
10
+ const storage = makeStorage(cachePath);
11
+ storage.watch(async (event, key) => {
12
+ if (event === "update" && key === "assets.json") {
13
+ await updateAssets();
14
+ }
15
+ });
16
+ let assets = {};
17
+ void updateAssets();
6
18
  function getAsset(srcDoc, relAsset) {
7
19
  const srcAsset = Path.join(Path.dirname(srcDoc), relAsset);
8
20
  return assets[srcAsset] || {};
@@ -10,7 +22,7 @@ function getAsset(srcDoc, relAsset) {
10
22
  const plugin = async (nitro) => {
11
23
  nitro.hooks.hook("content:file:afterParse", async (file) => {
12
24
  if (file._id.endsWith(".md")) {
13
- const srcDoc = file._id.split(":").join("/");
25
+ const srcDoc = toPath(deKey(file._id));
14
26
  const filter = (value, key) => !(String(key).startsWith("_") || key === "body");
15
27
  walk(file, (value, parent, key) => {
16
28
  if (isValidAsset(value)) {
@@ -1,5 +1,5 @@
1
1
  export type AssetConfig = {
2
- id: string;
2
+ id?: string;
3
3
  srcRel: string;
4
4
  srcAttr: string;
5
5
  width?: number;
@@ -1,7 +1,6 @@
1
1
  import * as Path from "path";
2
2
  import getImageSize from "image-size";
3
3
  import { isImage, warn } from "../utils/index.mjs";
4
- import { interpolatePattern } from "./paths.mjs";
5
4
  export function getAssetConfig(srcDir, srcAbs, pattern, hints) {
6
5
  let width = void 0;
7
6
  let height = void 0;
@@ -24,8 +23,8 @@ export function getAssetConfig(srcDir, srcAbs, pattern, hints) {
24
23
  warn(`could not read image "${srcAbs}`);
25
24
  }
26
25
  }
27
- const srcRel = Path.basename(srcDir) + srcAbs.substring(srcDir.length);
28
- const srcAttr = interpolatePattern(pattern, srcRel);
26
+ const srcRel = Path.relative(srcDir, srcAbs);
27
+ const srcAttr = "/" + srcRel;
29
28
  const id = srcRel.replaceAll("/", ":");
30
29
  return { id, srcRel, srcAttr, width, height, ratio, query };
31
30
  }
@@ -0,0 +1,2 @@
1
+ import { Callback } from '../../utils';
2
+ export declare function useSocketClient(channel: string, onMessage: Callback): void;
@@ -0,0 +1,9 @@
1
+ import { useRuntimeConfig } from "#imports";
2
+ export function useSocketClient(channel, onMessage) {
3
+ const url = useRuntimeConfig().public.sockets?.wsUrl;
4
+ if (process.client && url) {
5
+ import("./composable").then(({ useSocket }) => {
6
+ useSocket(channel, onMessage);
7
+ });
8
+ }
9
+ }
@@ -0,0 +1,4 @@
1
+ export declare function useSocket(channel: string, callback: (data: any) => void): {
2
+ connect: (retry?: boolean) => void;
3
+ send: (data: any) => void;
4
+ } | undefined;