nuxt-files-sdk 0.0.5 → 0.1.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.
Files changed (62) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +35 -9
  3. package/dist/config/load.js +67 -0
  4. package/dist/config/load.js.map +1 -0
  5. package/dist/config/merge.d.ts +5 -0
  6. package/dist/config/merge.js +22 -0
  7. package/dist/config/merge.js.map +1 -0
  8. package/dist/config/prune.js +55 -0
  9. package/dist/config/prune.js.map +1 -0
  10. package/dist/config.d.ts +101 -103
  11. package/dist/config.js +2 -2
  12. package/dist/config.js.map +1 -1
  13. package/dist/devtools/auth.js +49 -0
  14. package/dist/devtools/auth.js.map +1 -0
  15. package/dist/devtools/client/app.js +6 -4
  16. package/dist/devtools/client/browser-agent-rpc-BXhoSh1z-DRoP5jHQ.js +1 -0
  17. package/dist/devtools/client/index.html +4 -1
  18. package/dist/devtools/devframe.js +7 -1
  19. package/dist/devtools/devframe.js.map +1 -1
  20. package/dist/devtools/diagnostics.d.ts +1 -1
  21. package/dist/devtools/diagnostics.js +1 -1
  22. package/dist/devtools/diagnostics.js.map +1 -1
  23. package/dist/devtools/files-read.d.ts +1 -1
  24. package/dist/devtools/files-write.d.ts +1 -1
  25. package/dist/devtools/files.js +7 -4
  26. package/dist/devtools/files.js.map +1 -1
  27. package/dist/devtools/index.js +24 -6
  28. package/dist/devtools/index.js.map +1 -1
  29. package/dist/devtools/nuxt-v3-handler.js +1 -1
  30. package/dist/devtools/nuxt-v3-handler.js.map +1 -1
  31. package/dist/devtools/nuxt-v3.js +1 -1
  32. package/dist/devtools/nuxt-v3.js.map +1 -1
  33. package/dist/devtools/nuxt-v4.js.map +1 -1
  34. package/dist/devtools/snapshot.d.ts +8 -2
  35. package/dist/devtools/snapshot.js +13 -3
  36. package/dist/devtools/snapshot.js.map +1 -1
  37. package/dist/devtools/token.d.ts +14 -0
  38. package/dist/devtools/token.js +17 -0
  39. package/dist/devtools/token.js.map +1 -0
  40. package/dist/integration/nitro.d.ts +6 -0
  41. package/dist/integration/nitro.js +160 -63
  42. package/dist/integration/nitro.js.map +1 -1
  43. package/dist/module.d.ts +1 -4
  44. package/dist/module.js +31 -20
  45. package/dist/module.js.map +1 -1
  46. package/dist/nitro.d.ts +2 -4
  47. package/dist/nitro.js +2 -4
  48. package/dist/nitro.js.map +1 -1
  49. package/dist/package.js +1 -1
  50. package/dist/runtime/internal.d.ts +11 -0
  51. package/dist/runtime/internal.js +30 -0
  52. package/dist/runtime/internal.js.map +1 -0
  53. package/dist/runtime/normalize.js +29 -0
  54. package/dist/runtime/normalize.js.map +1 -0
  55. package/dist/runtime/provider-types.d.ts +53 -0
  56. package/dist/runtime/registry.d.ts +55 -8
  57. package/dist/runtime/registry.js +125 -89
  58. package/dist/runtime/registry.js.map +1 -1
  59. package/dist/runtime.d.ts +8 -9
  60. package/dist/runtime.js +8 -25
  61. package/dist/runtime.js.map +1 -1
  62. package/package.json +25 -14
@@ -1,4 +1,6 @@
1
- import { inspectFiles, useServerFiles } from "../runtime.js";
1
+ import { inspectFiles } from "../runtime/internal.js";
2
+ import { useServerFiles } from "../runtime.js";
3
+ import { authorizeFilesDevtoolsRequest } from "./auth.js";
2
4
  import { FILES_DEVTOOLS_MAX_UPLOAD_SIZE } from "./snapshot.js";
3
5
  import { createFilesRouter } from "files-sdk/api";
4
6
  import { createRouteHandler } from "files-sdk/nitro";
@@ -33,12 +35,13 @@ const createFilesDevtoolsHandler = (write) => {
33
35
  maxUploadSize: FILES_DEVTOOLS_MAX_UPLOAD_SIZE,
34
36
  secret: crypto.randomUUID()
35
37
  }));
36
- return (event) => {
38
+ return async (event, secret) => {
39
+ if (!await authorizeFilesDevtoolsRequest(event.node.req, secret)) return new Response(null, { status: 401 });
37
40
  const url = new URL(event.node.req.url ?? "/", "http://nuxt-files-sdk.local");
38
- if (event.node.req.method === "GET" && url.searchParams.get("op") === "devtools") return Promise.resolve(Response.json({
41
+ if (event.node.req.method === "GET" && url.searchParams.get("op") === "devtools") return Response.json({
39
42
  write,
40
43
  maxUploadSize: FILES_DEVTOOLS_MAX_UPLOAD_SIZE
41
- }));
44
+ });
42
45
  return handleFiles(event);
43
46
  };
44
47
  };
@@ -1 +1 @@
1
- {"version":3,"file":"files.js","names":[],"sources":["../../src/devtools/files.ts"],"sourcesContent":["import type { Files } from 'files-sdk'\nimport { createFilesRouter, type FilesOperation } from 'files-sdk/api'\nimport { createRouteHandler } from 'files-sdk/nitro'\n\nimport { inspectFiles, useServerFiles } from '../runtime'\nimport { FILES_DEVTOOLS_MAX_UPLOAD_SIZE } from './snapshot'\n\nconst readOperations = ['capabilities', 'list', 'exists', 'download'] as const satisfies readonly FilesOperation[]\nconst writeOperations = [...readOperations, 'upload', 'delete'] as const satisfies readonly FilesOperation[]\nexport const filesDevtoolsOperations = (write: boolean): readonly FilesOperation[] =>\n write ? writeOperations : readOperations\nconst getFiles: (name?: string) => Files = useServerFiles\n\nconst resolveFiles = (request: Request): Files => {\n const requested = new URL(request.url).searchParams.get('storage') ?? undefined\n const storages = inspectFiles().storages\n if (storages.length === 1 && storages[0]?.name === undefined) {\n if (requested !== undefined) throw new Error(`[nuxt-files-sdk:unknown-storage] Unknown storage \"${requested}\".`)\n return getFiles()\n }\n if (requested === undefined || !storages.some(({ name }) => name === requested)) {\n throw new Error('[nuxt-files-sdk:unknown-storage] Select a configured storage.')\n }\n return getFiles(requested)\n}\n\nexport const createFilesDevtoolsHandler = (write: boolean) => {\n const handleFiles = createRouteHandler(\n createFilesRouter({\n files: resolveFiles,\n operations: filesDevtoolsOperations(write),\n maxUploadSize: FILES_DEVTOOLS_MAX_UPLOAD_SIZE,\n secret: crypto.randomUUID(),\n }),\n )\n return (event: Parameters<typeof handleFiles>[0]): Promise<Response> => {\n const url = new URL(event.node.req.url ?? '/', 'http://nuxt-files-sdk.local')\n if (event.node.req.method === 'GET' && url.searchParams.get('op') === 'devtools') {\n return Promise.resolve(Response.json({ write, maxUploadSize: FILES_DEVTOOLS_MAX_UPLOAD_SIZE }))\n }\n return handleFiles(event)\n }\n}\n"],"mappings":";;;;;AAOA,MAAM,iBAAiB;CAAC;CAAgB;CAAQ;CAAU;AAAU;AACpE,MAAM,kBAAkB;CAAC,GAAG;CAAgB;CAAU;AAAQ;AAC9D,MAAa,2BAA2B,UACpC,QAAQ,kBAAkB;AAC9B,MAAM,WAAqC;AAE3C,MAAM,gBAAgB,YAA4B;CAC9C,MAAM,YAAY,IAAI,IAAI,QAAQ,GAAG,CAAC,CAAC,aAAa,IAAI,SAAS,KAAK,KAAA;CACtE,MAAM,WAAW,aAAa,CAAC,CAAC;CAChC,IAAI,SAAS,WAAW,KAAK,SAAS,EAAE,EAAE,SAAS,KAAA,GAAW;EAC1D,IAAI,cAAc,KAAA,GAAW,MAAM,IAAI,MAAM,qDAAqD,UAAU,GAAG;EAC/G,OAAO,SAAS;CACpB;CACA,IAAI,cAAc,KAAA,KAAa,CAAC,SAAS,MAAM,EAAE,WAAW,SAAS,SAAS,GAC1E,MAAM,IAAI,MAAM,+DAA+D;CAEnF,OAAO,SAAS,SAAS;AAC7B;AAEA,MAAa,8BAA8B,UAAmB;CAC1D,MAAM,cAAc,mBAChB,kBAAkB;EACd,OAAO;EACP,YAAY,wBAAwB,KAAK;EACzC,eAAe;EACf,QAAQ,OAAO,WAAW;CAC9B,CAAC,CACL;CACA,QAAQ,UAAgE;EACpE,MAAM,MAAM,IAAI,IAAI,MAAM,KAAK,IAAI,OAAO,KAAK,6BAA6B;EAC5E,IAAI,MAAM,KAAK,IAAI,WAAW,SAAS,IAAI,aAAa,IAAI,IAAI,MAAM,YAClE,OAAO,QAAQ,QAAQ,SAAS,KAAK;GAAE;GAAO,eAAe;EAA+B,CAAC,CAAC;EAElG,OAAO,YAAY,KAAK;CAC5B;AACJ"}
1
+ {"version":3,"file":"files.js","names":[],"sources":["../../src/devtools/files.ts"],"sourcesContent":["import type { Files } from 'files-sdk'\nimport { createFilesRouter, type FilesOperation } from 'files-sdk/api'\nimport { createRouteHandler } from 'files-sdk/nitro'\n\nimport { useServerFiles } from '../runtime'\nimport { inspectFiles } from '../runtime/internal'\nimport { authorizeFilesDevtoolsRequest } from './auth'\nimport { FILES_DEVTOOLS_MAX_UPLOAD_SIZE } from './snapshot'\n\nconst readOperations = ['capabilities', 'list', 'exists', 'download'] as const satisfies readonly FilesOperation[]\nconst writeOperations = [...readOperations, 'upload', 'delete'] as const satisfies readonly FilesOperation[]\nexport const filesDevtoolsOperations = (write: boolean): readonly FilesOperation[] =>\n write ? writeOperations : readOperations\nconst getFiles: (name?: string) => Files = useServerFiles\n\nconst resolveFiles = (request: Request): Files => {\n const requested = new URL(request.url).searchParams.get('storage') ?? undefined\n const storages = inspectFiles().storages\n if (storages.length === 1 && storages[0]?.name === undefined) {\n if (requested !== undefined) throw new Error(`[nuxt-files-sdk:unknown-storage] Unknown storage \"${requested}\".`)\n return getFiles()\n }\n if (requested === undefined || !storages.some(({ name }) => name === requested)) {\n throw new Error('[nuxt-files-sdk:unknown-storage] Select a configured storage.')\n }\n return getFiles(requested)\n}\n\nexport const createFilesDevtoolsHandler = (write: boolean) => {\n const handleFiles = createRouteHandler(\n createFilesRouter({\n files: resolveFiles,\n operations: filesDevtoolsOperations(write),\n maxUploadSize: FILES_DEVTOOLS_MAX_UPLOAD_SIZE,\n secret: crypto.randomUUID(),\n }),\n )\n return async (event: Parameters<typeof handleFiles>[0], secret: string): Promise<Response> => {\n if (!(await authorizeFilesDevtoolsRequest(event.node.req, secret))) {\n return new Response(null, { status: 401 })\n }\n const url = new URL(event.node.req.url ?? '/', 'http://nuxt-files-sdk.local')\n if (event.node.req.method === 'GET' && url.searchParams.get('op') === 'devtools') {\n return Response.json({ write, maxUploadSize: FILES_DEVTOOLS_MAX_UPLOAD_SIZE })\n }\n return handleFiles(event)\n }\n}\n"],"mappings":";;;;;;;AASA,MAAM,iBAAiB;CAAC;CAAgB;CAAQ;CAAU;AAAU;AACpE,MAAM,kBAAkB;CAAC,GAAG;CAAgB;CAAU;AAAQ;AAC9D,MAAa,2BAA2B,UACpC,QAAQ,kBAAkB;AAC9B,MAAM,WAAqC;AAE3C,MAAM,gBAAgB,YAA4B;CAC9C,MAAM,YAAY,IAAI,IAAI,QAAQ,GAAG,CAAC,CAAC,aAAa,IAAI,SAAS,KAAK,KAAA;CACtE,MAAM,WAAW,aAAa,CAAC,CAAC;CAChC,IAAI,SAAS,WAAW,KAAK,SAAS,EAAE,EAAE,SAAS,KAAA,GAAW;EAC1D,IAAI,cAAc,KAAA,GAAW,MAAM,IAAI,MAAM,qDAAqD,UAAU,GAAG;EAC/G,OAAO,SAAS;CACpB;CACA,IAAI,cAAc,KAAA,KAAa,CAAC,SAAS,MAAM,EAAE,WAAW,SAAS,SAAS,GAC1E,MAAM,IAAI,MAAM,+DAA+D;CAEnF,OAAO,SAAS,SAAS;AAC7B;AAEA,MAAa,8BAA8B,UAAmB;CAC1D,MAAM,cAAc,mBAChB,kBAAkB;EACd,OAAO;EACP,YAAY,wBAAwB,KAAK;EACzC,eAAe;EACf,QAAQ,OAAO,WAAW;CAC9B,CAAC,CACL;CACA,OAAO,OAAO,OAA0C,WAAsC;EAC1F,IAAI,CAAE,MAAM,8BAA8B,MAAM,KAAK,KAAK,MAAM,GAC5D,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;EAE7C,MAAM,MAAM,IAAI,IAAI,MAAM,KAAK,IAAI,OAAO,KAAK,6BAA6B;EAC5E,IAAI,MAAM,KAAK,IAAI,WAAW,SAAS,IAAI,aAAa,IAAI,IAAI,MAAM,YAClE,OAAO,SAAS,KAAK;GAAE;GAAO,eAAe;EAA+B,CAAC;EAEjF,OAAO,YAAY,KAAK;CAC5B;AACJ"}
@@ -1,24 +1,42 @@
1
- import { FILES_DEVTOOLS_MAX_UPLOAD_SIZE, FILES_DEVTOOLS_PATH, FILES_GATEWAY_PATH, FILES_SNAPSHOT_PATH } from "./snapshot.js";
1
+ import { FILES_DEVTOOLS_MAX_UPLOAD_SIZE, FILES_DEVTOOLS_PATH, FILES_GATEWAY_PATH, FILES_SNAPSHOT_PATH, FILES_TOKEN_PATH } from "./snapshot.js";
2
2
  import nuxt_v3_handler_default from "./nuxt-v3-handler.js";
3
+ import token_default from "./token.js";
3
4
  import { setupNuxtV3Devtools } from "./nuxt-v3.js";
4
5
  import { setupNuxtV4Devtools } from "./nuxt-v4.js";
5
- import { addDevServerHandler, addServerHandler } from "@nuxt/kit";
6
+ import { addDevServerHandler, addServerHandler, addServerTemplate } from "@nuxt/kit";
6
7
  import { fileURLToPath } from "node:url";
7
8
  //#region src/devtools/index.ts
8
- const setupFilesDevtools = (nuxt, version, write) => {
9
+ const authenticatedHandler = (name, path, arguments_) => {
10
+ const filename = `#nuxt-files-sdk/${name}`;
11
+ addServerTemplate({
12
+ filename,
13
+ getContents: () => `import handler from ${JSON.stringify(path.replaceAll("\\", "/"))}\nexport default event => handler(event, ${arguments_.map((value) => JSON.stringify(value)).join(", ")})\n`
14
+ });
15
+ return filename;
16
+ };
17
+ const setupFilesDevtools = (nuxt, version, write, secrets) => {
9
18
  addServerHandler({
10
19
  route: FILES_SNAPSHOT_PATH,
11
- handler: fileURLToPath(new URL("./snapshot.js", import.meta.url))
20
+ handler: authenticatedHandler("snapshot", fileURLToPath(new URL("./snapshot.js", import.meta.url)), [secrets.token])
12
21
  });
13
22
  addServerHandler({
14
23
  route: FILES_GATEWAY_PATH,
15
- handler: fileURLToPath(new URL(write ? "./files-write.js" : "./files-read.js", import.meta.url))
24
+ handler: authenticatedHandler("files", fileURLToPath(new URL(write ? "./files-write.js" : "./files-read.js", import.meta.url)), [secrets.token])
16
25
  });
17
26
  if (Number.parseInt(version) >= 4) setupNuxtV4Devtools(nuxt, {
18
27
  write,
19
- maxUploadSize: FILES_DEVTOOLS_MAX_UPLOAD_SIZE
28
+ maxUploadSize: FILES_DEVTOOLS_MAX_UPLOAD_SIZE,
29
+ tokenSecret: secrets.token
20
30
  });
21
31
  else {
32
+ addDevServerHandler({
33
+ route: FILES_TOKEN_PATH,
34
+ handler: (event) => token_default(event, secrets.token, async (token) => {
35
+ const host = "devtools" in nuxt ? nuxt.devtools : void 0;
36
+ if (!host || typeof host !== "object" || !("ensureDevAuthToken" in host) || typeof host.ensureDevAuthToken !== "function") throw new Error("Nuxt DevTools authentication is unavailable.");
37
+ await host.ensureDevAuthToken(token);
38
+ })
39
+ });
22
40
  addDevServerHandler({
23
41
  route: FILES_DEVTOOLS_PATH,
24
42
  handler: nuxt_v3_handler_default
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["uiHandler"],"sources":["../../src/devtools/index.ts"],"sourcesContent":["import { fileURLToPath } from 'node:url'\n\nimport { addDevServerHandler, addServerHandler } from '@nuxt/kit'\nimport type { Nuxt } from '@nuxt/schema'\n\nimport { setupNuxtV3Devtools } from './nuxt-v3'\nimport uiHandler from './nuxt-v3-handler'\nimport { setupNuxtV4Devtools } from './nuxt-v4'\nimport {\n FILES_DEVTOOLS_MAX_UPLOAD_SIZE,\n FILES_DEVTOOLS_PATH,\n FILES_GATEWAY_PATH,\n FILES_SNAPSHOT_PATH,\n} from './snapshot'\n\nexport const setupFilesDevtools = (nuxt: Nuxt, version: string, write: boolean): void => {\n // Snapshot must run inside Nitro's worker, where the runtime registry lives.\n addServerHandler({\n route: FILES_SNAPSHOT_PATH,\n handler: fileURLToPath(new URL('./snapshot.js', import.meta.url)),\n })\n addServerHandler({\n route: FILES_GATEWAY_PATH,\n handler: fileURLToPath(new URL(write ? './files-write.js' : './files-read.js', import.meta.url)),\n })\n if (Number.parseInt(version) >= 4) {\n setupNuxtV4Devtools(nuxt, { write, maxUploadSize: FILES_DEVTOOLS_MAX_UPLOAD_SIZE })\n } else {\n addDevServerHandler({\n route: FILES_DEVTOOLS_PATH,\n handler: uiHandler,\n })\n setupNuxtV3Devtools(nuxt)\n }\n}\n"],"mappings":";;;;;;;AAeA,MAAa,sBAAsB,MAAY,SAAiB,UAAyB;CAErF,iBAAiB;EACb,OAAO;EACP,SAAS,cAAc,IAAI,IAAI,iBAAiB,YAAY,GAAG,CAAC;CACpE,CAAC;CACD,iBAAiB;EACb,OAAO;EACP,SAAS,cAAc,IAAI,IAAI,QAAQ,qBAAqB,mBAAmB,YAAY,GAAG,CAAC;CACnG,CAAC;CACD,IAAI,OAAO,SAAS,OAAO,KAAK,GAC5B,oBAAoB,MAAM;EAAE;EAAO,eAAe;CAA+B,CAAC;MAC/E;EACH,oBAAoB;GAChB,OAAO;GACP,SAASA;EACb,CAAC;EACD,oBAAoB,IAAI;CAC5B;AACJ"}
1
+ {"version":3,"file":"index.js","names":["tokenHandler","uiHandler"],"sources":["../../src/devtools/index.ts"],"sourcesContent":["import { fileURLToPath } from 'node:url'\n\nimport { addDevServerHandler, addServerHandler, addServerTemplate } from '@nuxt/kit'\nimport type { Nuxt } from '@nuxt/schema'\n\nimport { setupNuxtV3Devtools } from './nuxt-v3'\nimport uiHandler from './nuxt-v3-handler'\nimport { setupNuxtV4Devtools } from './nuxt-v4'\nimport {\n FILES_DEVTOOLS_MAX_UPLOAD_SIZE,\n FILES_DEVTOOLS_PATH,\n FILES_GATEWAY_PATH,\n FILES_SNAPSHOT_PATH,\n FILES_TOKEN_PATH,\n} from './snapshot'\nimport tokenHandler from './token'\n\nconst authenticatedHandler = (name: string, path: string, arguments_: string[]): string => {\n const filename = `#nuxt-files-sdk/${name}`\n addServerTemplate({\n filename,\n getContents: () =>\n `import handler from ${JSON.stringify(path.replaceAll('\\\\', '/'))}\\nexport default event => handler(event, ${arguments_.map((value) => JSON.stringify(value)).join(', ')})\\n`,\n })\n return filename\n}\n\nexport const setupFilesDevtools = (nuxt: Nuxt, version: string, write: boolean, secrets: { token: string }): void => {\n // Snapshot must run inside Nitro's worker, where the runtime registry lives.\n addServerHandler({\n route: FILES_SNAPSHOT_PATH,\n handler: authenticatedHandler('snapshot', fileURLToPath(new URL('./snapshot.js', import.meta.url)), [\n secrets.token,\n ]),\n })\n addServerHandler({\n route: FILES_GATEWAY_PATH,\n handler: authenticatedHandler(\n 'files',\n fileURLToPath(new URL(write ? './files-write.js' : './files-read.js', import.meta.url)),\n [secrets.token],\n ),\n })\n if (Number.parseInt(version) >= 4) {\n setupNuxtV4Devtools(nuxt, {\n write,\n maxUploadSize: FILES_DEVTOOLS_MAX_UPLOAD_SIZE,\n tokenSecret: secrets.token,\n })\n } else {\n addDevServerHandler({\n route: FILES_TOKEN_PATH,\n handler: (event) =>\n tokenHandler(event, secrets.token, async (token) => {\n const host = 'devtools' in nuxt ? nuxt.devtools : undefined\n if (\n !host ||\n typeof host !== 'object' ||\n !('ensureDevAuthToken' in host) ||\n typeof host.ensureDevAuthToken !== 'function'\n ) {\n throw new Error('Nuxt DevTools authentication is unavailable.')\n }\n await host.ensureDevAuthToken(token)\n }),\n })\n addDevServerHandler({\n route: FILES_DEVTOOLS_PATH,\n handler: uiHandler,\n })\n setupNuxtV3Devtools(nuxt)\n }\n}\n"],"mappings":";;;;;;;;AAiBA,MAAM,wBAAwB,MAAc,MAAc,eAAiC;CACvF,MAAM,WAAW,mBAAmB;CACpC,kBAAkB;EACd;EACA,mBACI,uBAAuB,KAAK,UAAU,KAAK,WAAW,MAAM,GAAG,CAAC,EAAE,2CAA2C,WAAW,KAAK,UAAU,KAAK,UAAU,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE;CACjL,CAAC;CACD,OAAO;AACX;AAEA,MAAa,sBAAsB,MAAY,SAAiB,OAAgB,YAAqC;CAEjH,iBAAiB;EACb,OAAO;EACP,SAAS,qBAAqB,YAAY,cAAc,IAAI,IAAI,iBAAiB,YAAY,GAAG,CAAC,GAAG,CAChG,QAAQ,KACZ,CAAC;CACL,CAAC;CACD,iBAAiB;EACb,OAAO;EACP,SAAS,qBACL,SACA,cAAc,IAAI,IAAI,QAAQ,qBAAqB,mBAAmB,YAAY,GAAG,CAAC,GACtF,CAAC,QAAQ,KAAK,CAClB;CACJ,CAAC;CACD,IAAI,OAAO,SAAS,OAAO,KAAK,GAC5B,oBAAoB,MAAM;EACtB;EACA,eAAe;EACf,aAAa,QAAQ;CACzB,CAAC;MACE;EACH,oBAAoB;GAChB,OAAO;GACP,UAAU,UACNA,cAAa,OAAO,QAAQ,OAAO,OAAO,UAAU;IAChD,MAAM,OAAO,cAAc,OAAO,KAAK,WAAW,KAAA;IAClD,IACI,CAAC,QACD,OAAO,SAAS,YAChB,EAAE,wBAAwB,SAC1B,OAAO,KAAK,uBAAuB,YAEnC,MAAM,IAAI,MAAM,8CAA8C;IAElE,MAAM,KAAK,mBAAmB,KAAK;GACvC,CAAC;EACT,CAAC;EACD,oBAAoB;GAChB,OAAO;GACP,SAASC;EACb,CAAC;EACD,oBAAoB,IAAI;CAC5B;AACJ"}
@@ -13,7 +13,7 @@ const assets = /* @__PURE__ */ new Map([
13
13
  }]
14
14
  ]);
15
15
  var nuxt_v3_handler_default = async (event) => {
16
- const asset = assets.get(event.path);
16
+ const asset = assets.get(new URL(event.path, "http://localhost").pathname);
17
17
  if (!asset) return void 0;
18
18
  event.node.res.setHeader("content-type", asset.contentType);
19
19
  return asset.content;
@@ -1 +1 @@
1
- {"version":3,"file":"nuxt-v3-handler.js","names":[],"sources":["../../src/devtools/nuxt-v3-handler.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\n\nconst html = {\n contentType: 'text/html; charset=utf-8',\n content: readFile(new URL('./client/index.html', import.meta.url), 'utf8'),\n}\nconst assets = new Map([\n ['/', html],\n ['/index.html', html],\n [\n '/app.js',\n {\n contentType: 'text/javascript; charset=utf-8',\n content: readFile(new URL('./client/app.js', import.meta.url), 'utf8'),\n },\n ],\n])\n\nexport default async (event: { path: string; node: { res: { setHeader(name: string, value: string): void } } }) => {\n const asset = assets.get(event.path)\n if (!asset) return undefined\n event.node.res.setHeader('content-type', asset.contentType)\n return asset.content\n}\n"],"mappings":";;AAEA,MAAM,OAAO;CACT,aAAa;CACb,SAAS,SAAS,IAAI,IAAI,uBAAuB,YAAY,GAAG,GAAG,MAAM;AAC7E;AACA,MAAM,yBAAS,IAAI,IAAI;CACnB,CAAC,KAAK,IAAI;CACV,CAAC,eAAe,IAAI;CACpB,CACI,WACA;EACI,aAAa;EACb,SAAS,SAAS,IAAI,IAAI,mBAAmB,YAAY,GAAG,GAAG,MAAM;CACzE,CACJ;AACJ,CAAC;AAED,IAAA,0BAAe,OAAO,UAA6F;CAC/G,MAAM,QAAQ,OAAO,IAAI,MAAM,IAAI;CACnC,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,MAAM,KAAK,IAAI,UAAU,gBAAgB,MAAM,WAAW;CAC1D,OAAO,MAAM;AACjB"}
1
+ {"version":3,"file":"nuxt-v3-handler.js","names":[],"sources":["../../src/devtools/nuxt-v3-handler.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\n\nconst html = {\n contentType: 'text/html; charset=utf-8',\n content: readFile(new URL('./client/index.html', import.meta.url), 'utf8'),\n}\nconst assets = new Map([\n ['/', html],\n ['/index.html', html],\n [\n '/app.js',\n {\n contentType: 'text/javascript; charset=utf-8',\n content: readFile(new URL('./client/app.js', import.meta.url), 'utf8'),\n },\n ],\n])\n\nexport default async (event: { path: string; node: { res: { setHeader(name: string, value: string): void } } }) => {\n const asset = assets.get(new URL(event.path, 'http://localhost').pathname)\n if (!asset) return undefined\n event.node.res.setHeader('content-type', asset.contentType)\n return asset.content\n}\n"],"mappings":";;AAEA,MAAM,OAAO;CACT,aAAa;CACb,SAAS,SAAS,IAAI,IAAI,uBAAuB,YAAY,GAAG,GAAG,MAAM;AAC7E;AACA,MAAM,yBAAS,IAAI,IAAI;CACnB,CAAC,KAAK,IAAI;CACV,CAAC,eAAe,IAAI;CACpB,CACI,WACA;EACI,aAAa;EACb,SAAS,SAAS,IAAI,IAAI,mBAAmB,YAAY,GAAG,GAAG,MAAM;CACzE,CACJ;AACJ,CAAC;AAED,IAAA,0BAAe,OAAO,UAA6F;CAC/G,MAAM,QAAQ,OAAO,IAAI,IAAI,IAAI,MAAM,MAAM,kBAAkB,CAAC,CAAC,QAAQ;CACzE,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,MAAM,KAAK,IAAI,UAAU,gBAAgB,MAAM,WAAW;CAC1D,OAAO,MAAM;AACjB"}
@@ -8,7 +8,7 @@ const setupNuxtV3Devtools = (nuxt) => {
8
8
  icon: "ph:files-duotone",
9
9
  view: {
10
10
  type: "iframe",
11
- src: FILES_DEVTOOLS_PATH
11
+ src: `${FILES_DEVTOOLS_PATH}?host=nuxt-v3`
12
12
  }
13
13
  });
14
14
  });
@@ -1 +1 @@
1
- {"version":3,"file":"nuxt-v3.js","names":[],"sources":["../../src/devtools/nuxt-v3.ts"],"sourcesContent":["import type { Nuxt } from '@nuxt/schema'\n\nimport { FILES_DEVTOOLS_PATH } from './snapshot'\n\ninterface CustomTab {\n name: string\n title: string\n icon: string\n view: { type: 'iframe'; src: string }\n}\n\ndeclare module '@nuxt/schema' {\n interface NuxtHooks {\n 'devtools:customTabs': (tabs: CustomTab[]) => void\n }\n}\n\nexport const setupNuxtV3Devtools = (nuxt: Nuxt): void => {\n nuxt.hook('devtools:customTabs', (tabs) => {\n tabs.push({\n name: 'nuxt-files-sdk',\n title: 'Files',\n icon: 'ph:files-duotone',\n view: { type: 'iframe', src: FILES_DEVTOOLS_PATH },\n })\n })\n}\n"],"mappings":";;AAiBA,MAAa,uBAAuB,SAAqB;CACrD,KAAK,KAAK,wBAAwB,SAAS;EACvC,KAAK,KAAK;GACN,MAAM;GACN,OAAO;GACP,MAAM;GACN,MAAM;IAAE,MAAM;IAAU,KAAK;GAAoB;EACrD,CAAC;CACL,CAAC;AACL"}
1
+ {"version":3,"file":"nuxt-v3.js","names":[],"sources":["../../src/devtools/nuxt-v3.ts"],"sourcesContent":["import type { Nuxt } from '@nuxt/schema'\n\nimport { FILES_DEVTOOLS_PATH } from './snapshot'\n\ninterface CustomTab {\n name: string\n title: string\n icon: string\n view: { type: 'iframe'; src: string }\n}\n\ndeclare module '@nuxt/schema' {\n interface NuxtHooks {\n 'devtools:customTabs': (tabs: CustomTab[]) => void\n }\n}\n\nexport const setupNuxtV3Devtools = (nuxt: Nuxt): void => {\n nuxt.hook('devtools:customTabs', (tabs) => {\n tabs.push({\n name: 'nuxt-files-sdk',\n title: 'Files',\n icon: 'ph:files-duotone',\n view: { type: 'iframe', src: `${FILES_DEVTOOLS_PATH}?host=nuxt-v3` },\n })\n })\n}\n"],"mappings":";;AAiBA,MAAa,uBAAuB,SAAqB;CACrD,KAAK,KAAK,wBAAwB,SAAS;EACvC,KAAK,KAAK;GACN,MAAM;GACN,OAAO;GACP,MAAM;GACN,MAAM;IAAE,MAAM;IAAU,KAAK,GAAG,oBAAoB;GAAe;EACvE,CAAC;CACL,CAAC;AACL"}
@@ -1 +1 @@
1
- {"version":3,"file":"nuxt-v4.js","names":[],"sources":["../../src/devtools/nuxt-v4.ts"],"sourcesContent":["import { NUXT_DEVTOOLS_GROUP_ID, onDevtoolsReady } from '@nuxt/devtools-kit'\nimport type { Nuxt } from '@nuxt/schema'\nimport { createEmbedded } from 'devframe/adapters/embedded'\n\nimport { createFilesDevframe } from './devframe'\nimport { FILES_DEVTOOLS_PATH } from './snapshot'\n\nexport const setupNuxtV4Devtools = (nuxt: Nuxt, options: { write: boolean; maxUploadSize: number }): void => {\n onDevtoolsReady(async (context) => {\n await createEmbedded(\n createFilesDevframe({\n ...options,\n notifyFailure: (message) => context.messages.add(message),\n }),\n { ctx: context },\n )\n context.docks.register({\n id: 'nuxt-files-sdk',\n title: 'Files',\n icon: 'ph:files-duotone',\n type: 'iframe',\n url: FILES_DEVTOOLS_PATH,\n groupId: NUXT_DEVTOOLS_GROUP_ID,\n })\n\n const broadcast = (method: 'refresh' | 'copy-diagnostics') =>\n context.scope('nuxt-files-sdk').rpc.broadcast({ method, args: [], optional: true, event: true })\n context.commands.register({\n id: 'nuxt-files-sdk:open',\n title: 'Files: Open',\n icon: 'ph:files-duotone',\n category: 'tools',\n handler: () => context.docks.activate('nuxt-files-sdk'),\n })\n context.commands.register({\n id: 'nuxt-files-sdk:refresh',\n title: 'Files: Refresh',\n icon: 'ph:arrow-clockwise-duotone',\n category: 'tools',\n handler: () => broadcast('refresh'),\n })\n context.commands.register({\n id: 'nuxt-files-sdk:copy-diagnostics',\n title: 'Files: Copy Diagnostics',\n icon: 'ph:copy-duotone',\n category: 'tools',\n handler: () => broadcast('copy-diagnostics'),\n })\n }, nuxt)\n}\n"],"mappings":";;;;;AAOA,MAAa,uBAAuB,MAAY,YAA6D;CACzG,gBAAgB,OAAO,YAAY;EAC/B,MAAM,eACF,oBAAoB;GAChB,GAAG;GACH,gBAAgB,YAAY,QAAQ,SAAS,IAAI,OAAO;EAC5D,CAAC,GACD,EAAE,KAAK,QAAQ,CACnB;EACA,QAAQ,MAAM,SAAS;GACnB,IAAI;GACJ,OAAO;GACP,MAAM;GACN,MAAM;GACN,KAAK;GACL,SAAS;EACb,CAAC;EAED,MAAM,aAAa,WACf,QAAQ,MAAM,gBAAgB,CAAC,CAAC,IAAI,UAAU;GAAE;GAAQ,MAAM,CAAC;GAAG,UAAU;GAAM,OAAO;EAAK,CAAC;EACnG,QAAQ,SAAS,SAAS;GACtB,IAAI;GACJ,OAAO;GACP,MAAM;GACN,UAAU;GACV,eAAe,QAAQ,MAAM,SAAS,gBAAgB;EAC1D,CAAC;EACD,QAAQ,SAAS,SAAS;GACtB,IAAI;GACJ,OAAO;GACP,MAAM;GACN,UAAU;GACV,eAAe,UAAU,SAAS;EACtC,CAAC;EACD,QAAQ,SAAS,SAAS;GACtB,IAAI;GACJ,OAAO;GACP,MAAM;GACN,UAAU;GACV,eAAe,UAAU,kBAAkB;EAC/C,CAAC;CACL,GAAG,IAAI;AACX"}
1
+ {"version":3,"file":"nuxt-v4.js","names":[],"sources":["../../src/devtools/nuxt-v4.ts"],"sourcesContent":["import { NUXT_DEVTOOLS_GROUP_ID, onDevtoolsReady } from '@nuxt/devtools-kit'\nimport type { Nuxt } from '@nuxt/schema'\nimport { createEmbedded } from 'devframe/adapters/embedded'\n\nimport { createFilesDevframe } from './devframe'\nimport { FILES_DEVTOOLS_PATH } from './snapshot'\n\nexport const setupNuxtV4Devtools = (\n nuxt: Nuxt,\n options: { write: boolean; maxUploadSize: number; tokenSecret: string },\n): void => {\n onDevtoolsReady(async (context) => {\n await createEmbedded(\n createFilesDevframe({\n ...options,\n notifyFailure: (message) => context.messages.add(message),\n }),\n { ctx: context },\n )\n context.docks.register({\n id: 'nuxt-files-sdk',\n title: 'Files',\n icon: 'ph:files-duotone',\n type: 'iframe',\n url: FILES_DEVTOOLS_PATH,\n groupId: NUXT_DEVTOOLS_GROUP_ID,\n })\n\n const broadcast = (method: 'refresh' | 'copy-diagnostics') =>\n context.scope('nuxt-files-sdk').rpc.broadcast({ method, args: [], optional: true, event: true })\n context.commands.register({\n id: 'nuxt-files-sdk:open',\n title: 'Files: Open',\n icon: 'ph:files-duotone',\n category: 'tools',\n handler: () => context.docks.activate('nuxt-files-sdk'),\n })\n context.commands.register({\n id: 'nuxt-files-sdk:refresh',\n title: 'Files: Refresh',\n icon: 'ph:arrow-clockwise-duotone',\n category: 'tools',\n handler: () => broadcast('refresh'),\n })\n context.commands.register({\n id: 'nuxt-files-sdk:copy-diagnostics',\n title: 'Files: Copy Diagnostics',\n icon: 'ph:copy-duotone',\n category: 'tools',\n handler: () => broadcast('copy-diagnostics'),\n })\n }, nuxt)\n}\n"],"mappings":";;;;;AAOA,MAAa,uBACT,MACA,YACO;CACP,gBAAgB,OAAO,YAAY;EAC/B,MAAM,eACF,oBAAoB;GAChB,GAAG;GACH,gBAAgB,YAAY,QAAQ,SAAS,IAAI,OAAO;EAC5D,CAAC,GACD,EAAE,KAAK,QAAQ,CACnB;EACA,QAAQ,MAAM,SAAS;GACnB,IAAI;GACJ,OAAO;GACP,MAAM;GACN,MAAM;GACN,KAAK;GACL,SAAS;EACb,CAAC;EAED,MAAM,aAAa,WACf,QAAQ,MAAM,gBAAgB,CAAC,CAAC,IAAI,UAAU;GAAE;GAAQ,MAAM,CAAC;GAAG,UAAU;GAAM,OAAO;EAAK,CAAC;EACnG,QAAQ,SAAS,SAAS;GACtB,IAAI;GACJ,OAAO;GACP,MAAM;GACN,UAAU;GACV,eAAe,QAAQ,MAAM,SAAS,gBAAgB;EAC1D,CAAC;EACD,QAAQ,SAAS,SAAS;GACtB,IAAI;GACJ,OAAO;GACP,MAAM;GACN,UAAU;GACV,eAAe,UAAU,SAAS;EACtC,CAAC;EACD,QAAQ,SAAS,SAAS;GACtB,IAAI;GACJ,OAAO;GACP,MAAM;GACN,UAAU;GACV,eAAe,UAAU,kBAAkB;EAC/C,CAAC;CACL,GAAG,IAAI;AACX"}
@@ -5,7 +5,6 @@ export interface FilesDevtoolsSnapshot {
5
5
  name?: string;
6
6
  adapter: string;
7
7
  plugins: string[];
8
- source: 'storage' | 'devStorage';
9
8
  initialized: boolean;
10
9
  }>;
11
10
  diagnostics: FilesDevtoolsDiagnostic[];
@@ -13,8 +12,15 @@ export interface FilesDevtoolsSnapshot {
13
12
  export declare const FILES_DEVTOOLS_PATH = "/__nuxt-files-sdk/";
14
13
  export declare const FILES_SNAPSHOT_PATH = "/__nuxt-files-sdk/snapshot";
15
14
  export declare const FILES_GATEWAY_PATH = "/__nuxt-files-sdk/files";
15
+ export declare const FILES_TOKEN_PATH = "/__nuxt-files-sdk/token";
16
16
  export declare const FILES_DEVTOOLS_MAX_UPLOAD_SIZE: number;
17
- declare function _default(): FilesDevtoolsSnapshot;
17
+ declare function _default(event: {
18
+ node: {
19
+ req: {
20
+ headers: Headers;
21
+ };
22
+ };
23
+ }, secret: string): Promise<Response>;
18
24
  //#endregion
19
25
  export { _default as default };
20
26
  //# sourceMappingURL=snapshot.d.ts.map
@@ -1,11 +1,21 @@
1
- import { inspectFiles } from "../runtime.js";
1
+ import { inspectFiles } from "../runtime/internal.js";
2
+ import { authorizeFilesDevtoolsRequest } from "./auth.js";
3
+ import { createFilesDevtoolsDiagnostic } from "./diagnostics.js";
2
4
  //#region src/devtools/snapshot.ts
3
5
  const FILES_DEVTOOLS_PATH = "/__nuxt-files-sdk/";
4
6
  const FILES_SNAPSHOT_PATH = `${FILES_DEVTOOLS_PATH}snapshot`;
5
7
  const FILES_GATEWAY_PATH = `${FILES_DEVTOOLS_PATH}files`;
8
+ const FILES_TOKEN_PATH = `${FILES_DEVTOOLS_PATH}token`;
6
9
  const FILES_DEVTOOLS_MAX_UPLOAD_SIZE = 10485760;
7
- var snapshot_default = () => inspectFiles();
10
+ var snapshot_default = async (event, secret) => {
11
+ if (!await authorizeFilesDevtoolsRequest(event.node.req, secret)) return new Response(null, { status: 401 });
12
+ const snapshot = inspectFiles();
13
+ return Response.json({
14
+ ...snapshot,
15
+ diagnostics: snapshot.diagnostics.map(({ code, name, adapter }) => createFilesDevtoolsDiagnostic(code, adapter ? `${name === void 0 ? "The single storage" : `Storage "${name}"`} (${adapter}) could not be initialized.` : void 0))
16
+ });
17
+ };
8
18
  //#endregion
9
- export { FILES_DEVTOOLS_MAX_UPLOAD_SIZE, FILES_DEVTOOLS_PATH, FILES_GATEWAY_PATH, FILES_SNAPSHOT_PATH, snapshot_default as default };
19
+ export { FILES_DEVTOOLS_MAX_UPLOAD_SIZE, FILES_DEVTOOLS_PATH, FILES_GATEWAY_PATH, FILES_SNAPSHOT_PATH, FILES_TOKEN_PATH, snapshot_default as default };
10
20
 
11
21
  //# sourceMappingURL=snapshot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"snapshot.js","names":[],"sources":["../../src/devtools/snapshot.ts"],"sourcesContent":["import { inspectFiles } from '../runtime'\nimport type { FilesDevtoolsDiagnostic } from './diagnostics'\n\nexport interface FilesDevtoolsSnapshot {\n storages: Array<{\n name?: string\n adapter: string\n plugins: string[]\n source: 'storage' | 'devStorage'\n initialized: boolean\n }>\n diagnostics: FilesDevtoolsDiagnostic[]\n}\n\nexport const FILES_DEVTOOLS_PATH = '/__nuxt-files-sdk/'\nexport const FILES_SNAPSHOT_PATH = `${FILES_DEVTOOLS_PATH}snapshot`\nexport const FILES_GATEWAY_PATH = `${FILES_DEVTOOLS_PATH}files`\nexport const FILES_DEVTOOLS_MAX_UPLOAD_SIZE = 10 * 1024 * 1024\n\nexport default () => inspectFiles()\n"],"mappings":";;AAcA,MAAa,sBAAsB;AACnC,MAAa,sBAAsB,GAAG,oBAAoB;AAC1D,MAAa,qBAAqB,GAAG,oBAAoB;AACzD,MAAa,iCAAiC;AAE9C,IAAA,yBAAqB,aAAa"}
1
+ {"version":3,"file":"snapshot.js","names":[],"sources":["../../src/devtools/snapshot.ts"],"sourcesContent":["import { inspectFiles } from '../runtime/internal'\nimport { authorizeFilesDevtoolsRequest } from './auth'\nimport { createFilesDevtoolsDiagnostic, type FilesDevtoolsDiagnostic } from './diagnostics'\n\nexport interface FilesDevtoolsSnapshot {\n storages: Array<{\n name?: string\n adapter: string\n plugins: string[]\n initialized: boolean\n }>\n diagnostics: FilesDevtoolsDiagnostic[]\n}\n\nexport const FILES_DEVTOOLS_PATH = '/__nuxt-files-sdk/'\nexport const FILES_SNAPSHOT_PATH = `${FILES_DEVTOOLS_PATH}snapshot`\nexport const FILES_GATEWAY_PATH = `${FILES_DEVTOOLS_PATH}files`\nexport const FILES_TOKEN_PATH = `${FILES_DEVTOOLS_PATH}token`\nexport const FILES_DEVTOOLS_MAX_UPLOAD_SIZE = 10 * 1024 * 1024\n\nexport default async (event: { node: { req: { headers: Headers } } }, secret: string) => {\n if (!(await authorizeFilesDevtoolsRequest(event.node.req, secret))) {\n return new Response(null, { status: 401 })\n }\n const snapshot = inspectFiles()\n return Response.json({\n ...snapshot,\n diagnostics: snapshot.diagnostics.map(({ code, name, adapter }) =>\n createFilesDevtoolsDiagnostic(\n code,\n adapter\n ? `${name === undefined ? 'The single storage' : `Storage \"${name}\"`} (${adapter}) could not be initialized.`\n : undefined,\n ),\n ),\n })\n}\n"],"mappings":";;;;AAcA,MAAa,sBAAsB;AACnC,MAAa,sBAAsB,GAAG,oBAAoB;AAC1D,MAAa,qBAAqB,GAAG,oBAAoB;AACzD,MAAa,mBAAmB,GAAG,oBAAoB;AACvD,MAAa,iCAAiC;AAE9C,IAAA,mBAAe,OAAO,OAAgD,WAAmB;CACrF,IAAI,CAAE,MAAM,8BAA8B,MAAM,KAAK,KAAK,MAAM,GAC5D,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;CAE7C,MAAM,WAAW,aAAa;CAC9B,OAAO,SAAS,KAAK;EACjB,GAAG;EACH,aAAa,SAAS,YAAY,KAAK,EAAE,MAAM,MAAM,cACjD,8BACI,MACA,UACM,GAAG,SAAS,KAAA,IAAY,uBAAuB,YAAY,KAAK,GAAG,IAAI,QAAQ,+BAC/E,KAAA,CACV,CACJ;CACJ,CAAC;AACL"}
@@ -0,0 +1,14 @@
1
+ //#region src/devtools/token.d.ts
2
+ declare function _default(event: {
3
+ node: {
4
+ req: {
5
+ headers: {
6
+ get?: (name: string) => string | null | undefined;
7
+ [key: string]: unknown;
8
+ };
9
+ };
10
+ };
11
+ }, secret: string, authorize: (token: string) => Promise<void>): Promise<Response>;
12
+ //#endregion
13
+ export { _default as default };
14
+ //# sourceMappingURL=token.d.ts.map
@@ -0,0 +1,17 @@
1
+ import { createFilesDevtoolsToken } from "./auth.js";
2
+ //#region src/devtools/token.ts
3
+ var token_default = async (event, secret, authorize) => {
4
+ const headers = event.node.req.headers;
5
+ const received = headers.get?.("x-nuxt-devtools-token") ?? headers["x-nuxt-devtools-token"];
6
+ if (typeof received !== "string" || !received) return new Response(null, { status: 401 });
7
+ try {
8
+ await authorize(received);
9
+ } catch {
10
+ return new Response(null, { status: 401 });
11
+ }
12
+ return Response.json(await createFilesDevtoolsToken(secret), { headers: { "cache-control": "no-store" } });
13
+ };
14
+ //#endregion
15
+ export { token_default as default };
16
+
17
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","names":[],"sources":["../../src/devtools/token.ts"],"sourcesContent":["import { createFilesDevtoolsToken } from './auth'\n\nexport default async (\n event: {\n node: { req: { headers: { get?: (name: string) => string | null | undefined; [key: string]: unknown } } }\n },\n secret: string,\n authorize: (token: string) => Promise<void>,\n) => {\n const headers = event.node.req.headers\n const received = headers.get?.('x-nuxt-devtools-token') ?? headers['x-nuxt-devtools-token']\n if (typeof received !== 'string' || !received) return new Response(null, { status: 401 })\n try {\n await authorize(received)\n } catch {\n return new Response(null, { status: 401 })\n }\n return Response.json(await createFilesDevtoolsToken(secret), { headers: { 'cache-control': 'no-store' } })\n}\n"],"mappings":";;AAEA,IAAA,gBAAe,OACX,OAGA,QACA,cACC;CACD,MAAM,UAAU,MAAM,KAAK,IAAI;CAC/B,MAAM,WAAW,QAAQ,MAAM,uBAAuB,KAAK,QAAQ;CACnE,IAAI,OAAO,aAAa,YAAY,CAAC,UAAU,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;CACxF,IAAI;EACA,MAAM,UAAU,QAAQ;CAC5B,QAAQ;EACJ,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;CAC7C;CACA,OAAO,SAAS,KAAK,MAAM,yBAAyB,MAAM,GAAG,EAAE,SAAS,EAAE,iBAAiB,WAAW,EAAE,CAAC;AAC7G"}
@@ -8,7 +8,13 @@ export interface NitroIntegration {
8
8
  rootDir: string;
9
9
  buildDir: string;
10
10
  dev?: boolean;
11
+ static?: boolean;
12
+ preset?: string;
11
13
  plugins: string[];
14
+ handlers?: {
15
+ route: string;
16
+ handler: string;
17
+ }[];
12
18
  alias?: Record<string, string>;
13
19
  externals?: {
14
20
  inline?: unknown[];
@@ -1,40 +1,65 @@
1
+ import { normalizeFilesConfig } from "../runtime/normalize.js";
2
+ import { loadFilesConfig } from "../config/load.js";
3
+ import { pruneFilesConfigSource } from "../config/prune.js";
1
4
  import { resolve } from "node:path";
2
5
  import { mkdir, readFile, writeFile } from "node:fs/promises";
3
- import { getProvider } from "files-sdk/providers";
4
- import { createJiti } from "jiti";
6
+ import { createRequire } from "node:module";
7
+ import { fileURLToPath } from "node:url";
8
+ import { getProvider, listEnvVars } from "files-sdk/providers";
5
9
  //#region src/integration/nitro.ts
6
- const isStorageConfig = (value) => Boolean(value && typeof value === "object" && "adapter" in value && typeof value.adapter === "string");
7
- const isStorageRecord = (value) => Boolean(value && typeof value === "object" && Object.values(value).every(isStorageConfig));
8
- const selectedAdapters = (config, development) => {
9
- if (!config || typeof config !== "object") throw new Error("[nuxt-files-sdk:invalid-config] Files configuration must be an object.");
10
- const typedConfig = config;
11
- const storage = typedConfig.storage;
12
- const devStorage = typedConfig.devStorage;
13
- if (!storage && !development) return void 0;
14
- if (!storage && !devStorage) throw new Error("[nuxt-files-sdk:invalid-config] At least one storage is required.");
15
- const selected = [];
16
- const single = isStorageConfig(storage ?? devStorage);
17
- if (!storage) {
18
- if (isStorageConfig(devStorage)) selected.push(devStorage);
19
- else if (isStorageRecord(devStorage) && Object.keys(devStorage).length > 0) selected.push(...Object.values(devStorage));
20
- else throw new Error("[nuxt-files-sdk:invalid-config] At least one development storage is required.");
21
- } else if (!isStorageConfig(storage) && (!isStorageRecord(storage) || Object.keys(storage).length === 0)) throw new Error("[nuxt-files-sdk:invalid-config] At least one storage is required.");
22
- else if (isStorageConfig(storage)) {
23
- if (devStorage && !isStorageConfig(devStorage)) throw new Error("[nuxt-files-sdk:invalid-config] A single storage requires a single devStorage override.");
24
- selected.push(development && isStorageConfig(devStorage) ? devStorage : storage);
25
- } else {
26
- if (devStorage && !isStorageRecord(devStorage)) throw new Error("[nuxt-files-sdk:invalid-config] Named storage requires named devStorage overrides.");
27
- const overrides = isStorageRecord(devStorage) ? devStorage : void 0;
28
- for (const name of Object.keys(overrides ?? {})) if (!Object.hasOwn(storage, name)) throw new Error(`[nuxt-files-sdk:unknown-storage] Unknown storage "${name}".`);
29
- for (const [name, namedStorage] of Object.entries(storage)) selected.push(development ? overrides?.[name] ?? namedStorage : namedStorage);
30
- }
31
- const adapters = [...new Set(selected.map(({ adapter }) => adapter))].toSorted();
10
+ const AWS_CORE_DEPENDENCIES = [
11
+ "@aws-sdk/client-s3",
12
+ "@aws-sdk/s3-presigned-post",
13
+ "@aws-sdk/s3-request-presigner"
14
+ ];
15
+ const AWS_MULTIPART_DEPENDENCY = "@aws-sdk/lib-storage";
16
+ const FETCH_CAPABLE_S3_ADAPTERS = /* @__PURE__ */ new Set([
17
+ "minio",
18
+ "r2",
19
+ "rustfs"
20
+ ]);
21
+ const WORKERD_PRESETS = /* @__PURE__ */ new Set([
22
+ "cloudflare-module",
23
+ "cloudflare-durable",
24
+ "cloudflare-pages"
25
+ ]);
26
+ const optionalAwsSdkDependencies = (adapters, options) => {
27
+ if (options.nitroMajor >= 3 || !options.preset || !WORKERD_PRESETS.has(options.preset)) return [];
28
+ const s3Adapters = adapters.filter((adapter) => getProvider(adapter)?.peerDeps.includes("@aws-sdk/client-s3"));
29
+ if (s3Adapters.length === 0) return [];
30
+ return (s3Adapters.every((adapter) => FETCH_CAPABLE_S3_ADAPTERS.has(adapter)) ? [...AWS_CORE_DEPENDENCIES, AWS_MULTIPART_DEPENDENCY] : [AWS_MULTIPART_DEPENDENCY]).filter((dependency) => !options.resolvable(dependency));
31
+ };
32
+ const nitroMajorVersion = (nitro) => nitro.meta?.majorVersion ?? ("routing" in nitro ? 3 : 2);
33
+ const selectedAdapters = (config) => {
34
+ const entries = normalizeFilesConfig(config);
35
+ const single = entries.has(void 0);
36
+ const adapters = [...new Set([...entries.values()].map(({ storage }) => storage.adapter).filter((adapter) => typeof adapter === "string"))].toSorted();
32
37
  for (const adapter of adapters) if (!getProvider(adapter)) throw new Error(`[nuxt-files-sdk:unknown-adapter] Unknown adapter "${adapter}".`);
33
38
  return {
34
39
  adapters,
35
40
  single
36
41
  };
37
42
  };
43
+ const gatewayRoutes = (config) => {
44
+ const routes = config && typeof config === "object" && "routes" in config ? config.routes : void 0;
45
+ if (routes === void 0) return [];
46
+ if (!Array.isArray(routes)) throw new Error("[nuxt-files-sdk:invalid-route] routes must be an array.");
47
+ const storages = normalizeFilesConfig(config);
48
+ const paths = /* @__PURE__ */ new Set();
49
+ const selected = [];
50
+ for (const route of routes) {
51
+ if (!route || typeof route !== "object" || !("path" in route) || typeof route.path !== "string" || !/^\/(?:[\w.~-]+(?:\/[\w.~-]+)*)?$/u.test(route.path)) throw new Error("[nuxt-files-sdk:invalid-route] Each route needs a static absolute path.");
52
+ if (paths.has(route.path)) throw new Error(`[nuxt-files-sdk:duplicate-route] Duplicate route "${route.path}".`);
53
+ paths.add(route.path);
54
+ const name = "storage" in route ? route.storage : void 0;
55
+ if (storages.has(void 0) ? name !== void 0 : typeof name !== "string" || !storages.has(name)) throw new Error(`[nuxt-files-sdk:unknown-storage] Invalid storage for route "${route.path}".`);
56
+ selected.push(typeof name === "string" ? {
57
+ path: route.path,
58
+ storage: name
59
+ } : { path: route.path });
60
+ }
61
+ return selected;
62
+ };
38
63
  const factoryName = (adapter) => adapter === "cloudinary" ? "cloudinaryAdapter" : adapter.replaceAll(/-([a-z0-9])/gu, (_, character) => character.toUpperCase());
39
64
  const providerCode = (adapters) => ({
40
65
  imports: adapters.map((adapter, index) => `import { ${factoryName(adapter)} as provider${index} } from ${JSON.stringify(`files-sdk/${adapter}`)}`).join("\n"),
@@ -49,71 +74,143 @@ declare module ${JSON.stringify(moduleName)} {
49
74
  }
50
75
  }
51
76
  `;
52
- const storageTypes = (configPath, nitroMajor, single) => `import type config from ${JSON.stringify(configPath)}
77
+ const storageTypes = (configPath, nitroMajor) => `import type config from ${JSON.stringify(configPath)}
53
78
  import type { SingleStorage, StorageRegistry } from 'nuxt-files-sdk/runtime'
54
79
 
55
80
  declare module 'nuxt-files-sdk/runtime' {
56
- ${single ? "interface NuxtFilesSingleStorage { value: SingleStorage<typeof config> }" : "interface NuxtFilesStorageRegistry extends StorageRegistry<typeof config> {}"}
81
+ interface NuxtFilesSingleStorage { value: SingleStorage<typeof config> }
82
+ interface NuxtFilesStorageRegistry extends StorageRegistry<typeof config> {}
57
83
  }
58
84
  ${hookTypes(nitroMajor >= 3 ? "nitro/types" : "nitropack/types")}
59
85
  export {}
60
86
  `;
61
87
  const setupNitroFilesIntegration = async (nitro, options) => {
62
88
  const configPath = options.configPath.replaceAll("\\", "/");
63
- const jiti = createJiti(import.meta.url, {
64
- ...nitro.options.alias ? { alias: nitro.options.alias } : {},
65
- interopDefault: true,
66
- moduleCache: false
89
+ const config = await loadFilesConfig({
90
+ configPath,
91
+ environments: options.environments,
92
+ alias: nitro.options.alias,
93
+ injectImports: nitro.unimport?.injectImports.bind(nitro.unimport)
67
94
  });
68
- const source = await readFile(configPath, "utf8");
69
- const code = nitro.unimport ? (await nitro.unimport.injectImports(source, configPath)).code : source;
70
- const loaded = await jiti.evalModule(code, {
71
- filename: configPath,
72
- async: true
95
+ if (!config) return false;
96
+ const selected = selectedAdapters(config);
97
+ const directory = resolve(nitro.options.rootDir, nitro.options.buildDir, "nuxt-files-sdk");
98
+ const typesPath = resolve(directory, "storage-registry.d.ts");
99
+ let writeRuntime;
100
+ const writeTypes = async () => {
101
+ await mkdir(directory, { recursive: true });
102
+ await writeFile(typesPath, storageTypes(configPath, nitroMajorVersion(nitro)));
103
+ };
104
+ await writeTypes();
105
+ nitro.hooks.hook("types:extend", async (types) => {
106
+ await writeTypes();
107
+ await writeRuntime?.();
108
+ const tsConfig = types.tsConfig ??= {};
109
+ (tsConfig.include ??= []).push(typesPath);
110
+ const paths = (tsConfig.compilerOptions ??= {}).paths ??= {};
111
+ paths["files-sdk"] ??= [resolve(nitro.options.rootDir, "node_modules/files-sdk").replaceAll("\\", "/")];
73
112
  });
74
- const config = loaded && typeof loaded === "object" && "default" in loaded ? loaded.default : loaded;
75
- const selected = selectedAdapters(config, options.development);
76
- if (!selected) return;
77
- const { adapters, single } = selected;
113
+ const routes = gatewayRoutes(config);
114
+ const { adapters } = selected;
78
115
  const providers = providerCode(adapters);
79
- const runtimeConfig = options.development ? "config" : "{ storage: config.storage }";
116
+ const internalPath = fileURLToPath(new URL("../runtime/internal.js", import.meta.url)).replaceAll("\\", "/");
117
+ const environment = Object.fromEntries(adapters.map((adapter) => [adapter, listEnvVars(adapter).filter((variable) => variable.readBy === "files-sdk").map((variable) => [variable.key, ...variable.aliases ?? []])]));
118
+ const require = createRequire(resolve(nitro.options.rootDir, "package.json"));
119
+ const aliases = nitro.options.alias ?? {};
120
+ const shimFiles = optionalAwsSdkDependencies(adapters, {
121
+ nitroMajor: nitroMajorVersion(nitro),
122
+ preset: nitro.options.preset,
123
+ resolvable: (dependency) => {
124
+ if (Object.hasOwn(aliases, dependency)) return true;
125
+ try {
126
+ require.resolve(dependency);
127
+ return true;
128
+ } catch {
129
+ return false;
130
+ }
131
+ }
132
+ }).map((dependency) => ({
133
+ dependency,
134
+ path: resolve(directory, `${dependency.replaceAll(/[^a-z0-9]+/giu, "-")}.mjs`)
135
+ }));
136
+ if (shimFiles.length > 0) {
137
+ nitro.options.alias = aliases;
138
+ for (const { dependency, path } of shimFiles) aliases[dependency] = path.replaceAll("\\", "/");
139
+ }
80
140
  nitro.unimport?.getInternalContext().addons.push({
81
141
  name: "nuxt-files-sdk-jsdoc",
82
- declaration: (declarations) => declarations.replace(/^(\s*)(const useServerFiles: typeof .*\.useServerFiles)$/mu, "$1/** Return the project's Files client, including its configured plugin extensions. */\n$1const useServerFiles: typeof import('nuxt-files-sdk/runtime').useServerFiles")
142
+ declaration: (declarations) => declarations.replace(/^([ \t]*)const (useServerFiles|syncFiles|transferFiles): typeof .*\.\2$/gmu, (_, indent, name) => `${name === "useServerFiles" ? `${indent}/** Return the project's Files client, including its configured plugin extensions. */\n` : ""}${indent}const ${name}: typeof import('nuxt-files-sdk/runtime').${name}`)
83
143
  });
84
144
  const externals = nitro.options.externals ??= {};
85
145
  (externals.inline ??= []).push("nuxt-files-sdk");
86
146
  if (!nitro.options.dev) externals.inline.push("files-sdk");
87
- const directory = resolve(nitro.options.buildDir, "nuxt-files-sdk");
88
- const pluginPath = resolve(directory, options.development ? "plugin.dev.mjs" : "plugin.mjs");
89
- const typesPath = resolve(directory, "storage-registry.d.ts");
90
- const filesSdkTypes = resolve(nitro.options.rootDir, "node_modules/files-sdk/dist").replaceAll("\\", "/");
91
- externals.inline.push(pluginPath.replaceAll("\\", "/"), configPath);
147
+ const pluginPath = resolve(directory, nitro.options.dev ? "plugin.dev.mjs" : "plugin.mjs");
148
+ const resolvedPath = resolve(directory, nitro.options.dev ? "resolved.dev.mjs" : "resolved.mjs");
149
+ const selectedPath = resolve(directory, nitro.options.dev ? "selected.dev.ts" : "selected.ts");
150
+ const routePaths = routes.map((_, index) => resolve(directory, `gateway-${index}${nitro.options.dev ? ".dev" : ""}.mjs`).replaceAll("\\", "/"));
151
+ for (const [index, route] of routes.entries()) (nitro.options.handlers ??= []).push({
152
+ route: route.path,
153
+ handler: routePaths[index]
154
+ });
155
+ externals.inline.push(pluginPath.replaceAll("\\", "/"), resolvedPath.replaceAll("\\", "/"), selectedPath.replaceAll("\\", "/"), ...routePaths);
92
156
  nitro.options.plugins.push(pluginPath.replaceAll("\\", "/"));
93
- nitro.hooks.hook("types:extend", async (types) => {
157
+ writeRuntime = async () => {
94
158
  await mkdir(directory, { recursive: true });
95
- await Promise.all([writeFile(pluginPath, `import config from ${JSON.stringify(configPath)}
159
+ await Promise.all(shimFiles.map(({ dependency, path }) => writeFile(path, `throw new Error(${JSON.stringify(`[nuxt-files-sdk:missing-optional-dependency] ${dependency} is required for this Files SDK operation. Install it or select the provider's fetch client.`)})\n`)));
160
+ const originalSource = await readFile(configPath, "utf8");
161
+ const importedSource = nitro.unimport ? (await nitro.unimport.injectImports(originalSource, configPath)).code : originalSource;
162
+ await writeFile(selectedPath, pruneFilesConfigSource(importedSource, configPath, options.environments));
163
+ const mergePath = fileURLToPath(new URL("../config/merge.js", import.meta.url)).replaceAll("\\", "/");
164
+ const selectedBranches = options.environments.flatMap((name) => [`raw[${JSON.stringify(`$${name}`)}]`, `raw.$env?.[${JSON.stringify(name)}]`]).toReversed();
165
+ await writeFile(resolvedPath, `import raw from ${JSON.stringify(selectedPath.replaceAll("\\", "/"))}\nimport { mergeFilesConfig } from ${JSON.stringify(mergePath)}\nconst resolved = mergeFilesConfig(${[...selectedBranches, "raw"].join(", ")})\nexport default { storage: resolved.storage, routes: resolved.routes }\n`);
166
+ await writeFile(pluginPath, `import config from ${JSON.stringify(resolvedPath.replaceAll("\\", "/"))}
96
167
  ${providers.imports}
97
- import { configureFiles } from 'nuxt-files-sdk/runtime'
168
+ import { configureFiles } from ${JSON.stringify(internalPath)}
98
169
 
99
- export default (nitroApp) => configureFiles(${runtimeConfig}, {
100
- development: ${JSON.stringify(options.development)},
170
+ export default (nitroApp) => configureFiles(config, {
101
171
  factories: { ${providers.factories} },
172
+ environment: ${JSON.stringify(environment)},
102
173
  hooks: {
103
174
  onAction: (event, storage) => nitroApp.hooks.callHook('files:action', { event, storage }),
104
175
  onError: (event, storage) => nitroApp.hooks.callHook('files:error', { event, storage }),
105
176
  onRetry: (event, storage) => nitroApp.hooks.callHook('files:retry', { event, storage }),
106
177
  },
107
178
  })
108
- `), writeFile(typesPath, storageTypes(configPath, nitro.meta?.majorVersion ?? ("routing" in nitro ? 3 : 2), single))]);
109
- const tsConfig = types.tsConfig ??= {};
110
- (tsConfig.include ??= []).push(typesPath);
111
- const paths = (tsConfig.compilerOptions ??= {}).paths ??= {};
112
- paths["files-sdk"] ??= [`${filesSdkTypes}/index.d.ts`];
113
- paths["files-sdk/*"] ??= [`${filesSdkTypes}/*/index.d.ts`];
114
- });
179
+ `);
180
+ await Promise.all(routePaths.map((path, index) => {
181
+ const route = routes[index];
182
+ const handler = nitroMajorVersion(nitro) >= 3 ? "router.handle(event.req)" : "createRouteHandler(router)(event)";
183
+ return writeFile(path, `import config from ${JSON.stringify(resolvedPath.replaceAll("\\", "/"))}
184
+ import { createFilesRouter } from 'files-sdk/api'
185
+ ${nitroMajorVersion(nitro) >= 3 ? "" : "import { createRouteHandler } from 'files-sdk/nitro'"}
186
+ import { getFiles } from ${JSON.stringify(internalPath)}
187
+
188
+ const route = config.routes[${index}]
189
+ const environmentSecret = typeof process === 'undefined' ? undefined : process.env?.FILES_API_SECRET
190
+ const secret = route.authorize
191
+ ? route.secret || environmentSecret || crypto.randomUUID() + crypto.randomUUID()
192
+ : route.secret
193
+ if (route.authorize && !route.secret && !environmentSecret) {
194
+ console.warn('[nuxt-files-sdk:gateway-secret] Set FILES_API_SECRET for upload tokens shared across processes.')
195
+ }
196
+ let sharedRouter
197
+ const makeRouter = (event) => createFilesRouter({
198
+ ...route,
199
+ files: () => getFiles(${route.storage === void 0 ? "" : JSON.stringify(route.storage)}),
200
+ secret,
201
+ authorize: route.authorize && ((context) => route.authorize({ ...context, event })),
202
+ })
203
+ export default (event) => {
204
+ const router = route.authorize ? makeRouter(event) : (sharedRouter ??= makeRouter(event))
205
+ return ${handler}
206
+ }
207
+ `);
208
+ }));
209
+ };
210
+ await writeRuntime();
211
+ return true;
115
212
  };
116
213
  //#endregion
117
- export { providerCode, selectedAdapters, setupNitroFilesIntegration, storageTypes };
214
+ export { gatewayRoutes, optionalAwsSdkDependencies, providerCode, selectedAdapters, setupNitroFilesIntegration, storageTypes };
118
215
 
119
216
  //# sourceMappingURL=nitro.js.map