@holo-js/adapter-nuxt 0.3.27 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Holo-JS contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ e7de7522096e85f09dffe635f153a2321b5d38f460190ac2164bb8db98bd3188
package/dist/module.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import * as nuxt_schema from 'nuxt/schema';
1
+ import { NuxtModule } from 'nuxt/schema';
2
2
  import { LoadedHoloConfig, HoloConfigMap } from '@holo-js/config';
3
3
 
4
4
  type ModuleOptions = Record<string, never>;
@@ -44,7 +44,6 @@ type HoloStorageRuntimeConfig = {
44
44
  disks: Record<string, RuntimeDiskConfig>;
45
45
  };
46
46
  type StorageModule = {
47
- applyNitroStorageConfig(nitro: NuxtOptionsWithNitro, config: HoloStorageRuntimeConfig, s3Driver: string): void;
48
47
  hasPublicLocalDisk(config: HoloStorageRuntimeConfig): boolean;
49
48
  mergeModuleOptions(base: StorageModuleOptions | undefined, overrides: StorageModuleOptions | undefined): StorageModuleOptions;
50
49
  normalizeModuleOptions(options: StorageModuleOptions | undefined): HoloStorageRuntimeConfig;
@@ -65,7 +64,6 @@ type NuxtViteOptions = {
65
64
  };
66
65
  interface NuxtOptionsWithNitro {
67
66
  nitro: {
68
- storage: Record<string, unknown>;
69
67
  moduleSideEffects?: string[];
70
68
  errorHandler?: string | string[];
71
69
  externals?: {
@@ -94,7 +92,6 @@ interface NuxtOptionsWithNitro {
94
92
  };
95
93
  [key: string]: unknown;
96
94
  };
97
- holoStorage?: HoloStorageRuntimeConfig;
98
95
  [key: string]: unknown;
99
96
  };
100
97
  build: {
@@ -106,7 +103,6 @@ interface NuxtOptionsWithNitro {
106
103
  rootDir?: string;
107
104
  _holoStorageModuleOptions?: StorageModuleOptions;
108
105
  _holoStorageFinalizeRegistered?: boolean;
109
- _holoStorageRuntimeRegistered?: boolean;
110
106
  _holoBroadcastAuthRouteRegistered?: boolean;
111
107
  _holoRealtimeRouteRegistered?: boolean;
112
108
  _holoClientTransformsRegistered?: boolean;
@@ -120,10 +116,11 @@ declare function isProjectPackageLinked(rootDir: string, packageRootName: string
120
116
  declare function addNitroRuntimeTraceIncludes(opts: NuxtOptionsWithNitro, rootDir: string, pluginPackages?: readonly string[], resolvePackage?: (rootDir: string, packageName: string) => string | undefined): void;
121
117
  declare function resolveClientOptimizeDeps(rootDir: string): string[];
122
118
  declare function addViteOptimizeDeps(opts: NuxtOptionsWithNitro, deps: readonly string[]): void;
123
- declare function isRealtimeDefinitionModule(_rootDir: string, id: string): boolean;
119
+ declare function isRealtimeDefinitionModule(rootDir: string, id: string, directories?: readonly string[]): boolean;
124
120
  declare function resolveExistingRealtimeDefinitionFile(path: string): string | undefined;
125
121
  declare function existsFile(path: string): boolean;
126
122
  declare function resolveRealtimeDefinitionImport(source: string, importer: string | undefined): string | undefined;
123
+ declare function renderRealtimeDefinitionsModule(rootDir: string): string;
127
124
  declare function createRealtimeDefinitionVitePlugin(rootDir: string): unknown;
128
125
  declare function addVitePlugin(vite: NuxtViteOptions, plugin: unknown): void;
129
126
  declare function addNitroErrorHandler(opts: NuxtOptionsWithNitro, handler: string): void;
@@ -136,9 +133,8 @@ declare function resolveStorageSetup(storageModule: StorageModule | undefined, l
136
133
  };
137
134
  declare function finalizeStorageSetup(storageModule: StorageModule, opts: NuxtOptionsWithNitro, resolver: {
138
135
  resolve(path: string): string;
139
- }, s3Driver: string): void;
140
- declare function applyStorageRuntimeConfig(runtimeConfig: Record<string, unknown>, normalized: HoloStorageRuntimeConfig | undefined): void;
141
- declare const _default: nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
136
+ }): void;
137
+ declare const holoNuxtModule: NuxtModule<ModuleOptions>;
142
138
 
143
139
  declare const moduleInternals: {
144
140
  addViteOptimizeDeps: typeof addViteOptimizeDeps;
@@ -151,7 +147,6 @@ declare const moduleInternals: {
151
147
  hasModuleNotFoundCode: typeof hasModuleNotFoundCode;
152
148
  hasLoadedConfigFile: typeof hasLoadedConfigFile;
153
149
  importOptionalStorageS3Module: typeof importOptionalStorageS3Module;
154
- applyStorageRuntimeConfig: typeof applyStorageRuntimeConfig;
155
150
  finalizeStorageSetup: typeof finalizeStorageSetup;
156
151
  resolveStorageSetup: typeof resolveStorageSetup;
157
152
  isModuleResolutionFailure: typeof isModuleResolutionFailure;
@@ -160,6 +155,7 @@ declare const moduleInternals: {
160
155
  isProjectPackageLinked: typeof isProjectPackageLinked;
161
156
  isRealtimeDefinitionModule: typeof isRealtimeDefinitionModule;
162
157
  resolveClientOptimizeDeps: typeof resolveClientOptimizeDeps;
158
+ renderRealtimeDefinitionsModule: typeof renderRealtimeDefinitionsModule;
163
159
  resolveExistingRealtimeDefinitionFile: typeof resolveExistingRealtimeDefinitionFile;
164
160
  resolveRealtimeDefinitionImport: typeof resolveRealtimeDefinitionImport;
165
161
  };
@@ -167,5 +163,5 @@ declare const adapterNuxtInternals: {
167
163
  toStorageModuleOptions: typeof toStorageModuleOptions;
168
164
  };
169
165
 
170
- export { adapterNuxtInternals, _default as default, moduleInternals };
166
+ export { adapterNuxtInternals, holoNuxtModule as default, moduleInternals };
171
167
  export type { ModuleOptions };
package/dist/module.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@holo-js/adapter-nuxt",
3
3
  "configKey": "@holo-js/adapter-nuxt",
4
- "version": "0.3.27",
4
+ "version": "0.4.0",
5
5
  "builder": {
6
- "@nuxt/module-builder": "1.0.2",
6
+ "@nuxt/module-builder": "1.0.3",
7
7
  "unbuild": "unknown"
8
8
  }
9
9
  }
package/dist/module.mjs CHANGED
@@ -1,30 +1,33 @@
1
1
  import { createRealtimeClientDefinitionTransform as createRealtimeClientDefinitionTransform$1, createRealtimeClientDefinitionModule as createRealtimeClientDefinitionModule$1, compileBrowserValidation } from '@holo-js/adapter-shared/build';
2
- import { existsSync, lstatSync, readFileSync } from 'node:fs';
3
- import { writeFile, readdir, readFile, mkdir, access } from 'node:fs/promises';
2
+ import { resolveRealtimeDefinitionDirectories, isInRealtimeDefinitionDirectory, assertRealtimeDefinitionTree } from '@holo-js/adapter-shared/realtime-directories';
3
+ import { existsSync, lstatSync, readFileSync, readdirSync } from 'node:fs';
4
+ import { readdir, readFile, mkdir, access } from 'node:fs/promises';
4
5
  import { createRequire } from 'node:module';
5
6
  import { resolve, extname, relative, basename, dirname, isAbsolute } from 'node:path';
6
7
  import { defineNuxtModule, createResolver, addServerPlugin, addServerImportsDir, addServerHandler, addPlugin } from '@nuxt/kit';
7
8
  import { loadConfigDirectory } from '@holo-js/config';
8
9
  import '@holo-js/db/config';
9
10
 
10
- function createRealtimeClientDefinitionModule(source) {
11
- return createRealtimeClientDefinitionModule$1(source, "@holo-js/adapter-nuxt/realtime");
11
+ function createRealtimeClientDefinitionModule(source, filePath) {
12
+ return createRealtimeClientDefinitionModule$1({ source, importTarget: "@holo-js/adapter-nuxt/realtime", filePath });
12
13
  }
13
- function createRealtimeClientDefinitionTransform(source) {
14
- return createRealtimeClientDefinitionTransform$1(source, "@holo-js/adapter-nuxt/realtime");
14
+ function createRealtimeClientDefinitionTransform(source, filePath) {
15
+ return createRealtimeClientDefinitionTransform$1({ source, importTarget: "@holo-js/adapter-nuxt/realtime", filePath });
15
16
  }
16
17
 
17
18
  const MODEL_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"]);
18
19
  const HOLO_PACKAGE_SCOPE = "@holo-js/";
19
20
  const realtimeClientDefinitionPrefix = "\0holo-realtime-client:";
21
+ const realtimeDefinitionsModuleId = "#holo/realtime-definitions";
22
+ const VALIDATION_CLIENT_DEPENDENCIES = ["valibot", "@holo-js/kernel > file-type"];
20
23
  const CLIENT_OPTIMIZE_DEPS = [
21
24
  {
22
25
  packageName: `${HOLO_PACKAGE_SCOPE}forms`,
23
- include: `${HOLO_PACKAGE_SCOPE}forms > ${HOLO_PACKAGE_SCOPE}validation > valibot`
26
+ include: VALIDATION_CLIENT_DEPENDENCIES.map((dependency) => `${HOLO_PACKAGE_SCOPE}forms > ${HOLO_PACKAGE_SCOPE}validation > ${dependency}`)
24
27
  },
25
28
  {
26
29
  packageName: `${HOLO_PACKAGE_SCOPE}validation`,
27
- include: `${HOLO_PACKAGE_SCOPE}validation > valibot`
30
+ include: VALIDATION_CLIENT_DEPENDENCIES.map((dependency) => `${HOLO_PACKAGE_SCOPE}validation > ${dependency}`)
28
31
  }
29
32
  ];
30
33
  const NITRO_RUNTIME_TRACE_IMPORTS = [
@@ -207,7 +210,7 @@ function resolveClientOptimizeDeps(rootDir) {
207
210
  for (const { packageName, include } of CLIENT_OPTIMIZE_DEPS) {
208
211
  try {
209
212
  projectRequire.resolve(packageName);
210
- deps.push(include);
213
+ deps.push(...include);
211
214
  } catch (error) {
212
215
  if (!isModuleResolutionFailure(error)) {
213
216
  throw error;
@@ -229,10 +232,10 @@ function addViteOptimizeDeps(opts, deps) {
229
232
  ])
230
233
  ];
231
234
  }
232
- function isRealtimeDefinitionModule(_rootDir, id) {
235
+ function isRealtimeDefinitionModule(rootDir, id, directories = resolveRealtimeDefinitionDirectories(rootDir)) {
233
236
  const [sourcePath = ""] = id.split("?");
234
237
  const normalizedId = sourcePath.replaceAll("\\", "/");
235
- return normalizedId.includes("/server/realtime/") && MODEL_FILE_EXTENSIONS.has(extname(normalizedId));
238
+ return (normalizedId.includes("/server/realtime/") || isInRealtimeDefinitionDirectory(directories, normalizedId)) && MODEL_FILE_EXTENSIONS.has(extname(normalizedId));
236
239
  }
237
240
  function resolveExistingRealtimeDefinitionFile(path) {
238
241
  if (MODEL_FILE_EXTENSIONS.has(extname(path)) && existsFile(path)) {
@@ -260,10 +263,39 @@ function resolveRealtimeDefinitionImport(source, importer) {
260
263
  const basePath = source.startsWith(".") ? importer ? resolve(dirname(importer.split("?")[0]), source) : void 0 : resolve(source);
261
264
  return basePath ? resolveExistingRealtimeDefinitionFile(basePath) : void 0;
262
265
  }
266
+ function collectRealtimeDefinitionFiles(rootDir) {
267
+ const realtimeRoot = resolve(rootDir, "server/realtime");
268
+ if (!existsSync(realtimeRoot)) {
269
+ return [];
270
+ }
271
+ return readdirSync(realtimeRoot, { recursive: true, withFileTypes: true }).filter((entry) => entry.isFile() && MODEL_FILE_EXTENSIONS.has(extname(entry.name))).map((entry) => resolve(entry.parentPath, entry.name)).sort((left, right) => left.localeCompare(right));
272
+ }
273
+ function renderRealtimeDefinitionsModule(rootDir) {
274
+ const files = collectRealtimeDefinitionFiles(rootDir);
275
+ const imports = files.map((filePath, index) => `import * as realtimeModule${index} from ${JSON.stringify(filePath)}`);
276
+ const values = files.map((_filePath, index) => `...Object.values(realtimeModule${index})`);
277
+ return [
278
+ ...imports,
279
+ "",
280
+ `export const realtimeDefinitions = [${values.join(", ")}]`,
281
+ ""
282
+ ].join("\n");
283
+ }
263
284
  function createRealtimeDefinitionVitePlugin(rootDir) {
285
+ const directories = resolveRealtimeDefinitionDirectories(rootDir);
286
+ let realtimeTreeChanged = false;
287
+ const loadedDefinitionIds = /* @__PURE__ */ new Set();
264
288
  return {
265
289
  name: "holo-realtime-client-definitions",
266
290
  enforce: "pre",
291
+ buildStart() {
292
+ assertRealtimeDefinitionTree(rootDir);
293
+ },
294
+ configureServer(server) {
295
+ server.watcher.on("all", (_event, path) => {
296
+ if (isInRealtimeDefinitionDirectory(directories, path)) realtimeTreeChanged = true;
297
+ });
298
+ },
267
299
  resolveId(source, importer, options) {
268
300
  if (options?.ssr) {
269
301
  return null;
@@ -271,22 +303,32 @@ function createRealtimeDefinitionVitePlugin(rootDir) {
271
303
  const resolved = resolveRealtimeDefinitionImport(source, importer);
272
304
  return resolved ? `${realtimeClientDefinitionPrefix}${resolved}` : null;
273
305
  },
274
- load(id) {
275
- if (!id.startsWith(realtimeClientDefinitionPrefix)) {
306
+ load(id, options) {
307
+ if (!options?.ssr && realtimeTreeChanged) {
308
+ assertRealtimeDefinitionTree(rootDir);
309
+ realtimeTreeChanged = false;
310
+ }
311
+ if (id.startsWith(realtimeClientDefinitionPrefix)) {
312
+ const sourcePath2 = id.slice(realtimeClientDefinitionPrefix.length);
313
+ loadedDefinitionIds.add(id);
314
+ return createRealtimeClientDefinitionModule(readFileSync(sourcePath2, "utf8"), sourcePath2);
315
+ }
316
+ if (options?.ssr || !isRealtimeDefinitionModule(rootDir, id, directories)) {
276
317
  return null;
277
318
  }
278
- const sourcePath = id.slice(realtimeClientDefinitionPrefix.length);
279
- return createRealtimeClientDefinitionModule(readFileSync(sourcePath, "utf8"));
319
+ const sourcePath = id.split("?")[0];
320
+ loadedDefinitionIds.add(id);
321
+ return createRealtimeClientDefinitionModule(readFileSync(sourcePath, "utf8"), sourcePath);
280
322
  },
281
323
  transform(code, id, options) {
282
324
  if (!options?.ssr && !id.includes("node_modules") && /\.[cm]?[jt]sx?$/.test(id)) {
283
325
  const compiled = compileBrowserValidation(code, id);
284
326
  if (compiled) return { code: compiled, map: null };
285
327
  }
286
- if (options?.ssr || !isRealtimeDefinitionModule(rootDir, id)) {
328
+ if (options?.ssr || loadedDefinitionIds.has(id) || !isRealtimeDefinitionModule(rootDir, id, directories)) {
287
329
  return null;
288
330
  }
289
- return createRealtimeClientDefinitionTransform(code);
331
+ return createRealtimeClientDefinitionTransform(code, id.split("?")[0]);
290
332
  }
291
333
  };
292
334
  }
@@ -327,20 +369,28 @@ function hasLoadedConfigFile(loaded, configName) {
327
369
  return normalizedPath.endsWith(`/config/${configName}.ts`) || normalizedPath.endsWith(`/config/${configName}.mts`) || normalizedPath.endsWith(`/config/${configName}.js`) || normalizedPath.endsWith(`/config/${configName}.mjs`) || normalizedPath.endsWith(`/config/${configName}.cts`) || normalizedPath.endsWith(`/config/${configName}.cjs`);
328
370
  });
329
371
  }
372
+ async function writeGeneratedFile(path, contents) {
373
+ const { atomicFileInternals } = await import('@holo-js/core');
374
+ await atomicFileInternals.writeTextFile(path, contents);
375
+ }
330
376
  async function ensureModelRegistryTypesPlaceholder(path) {
331
377
  try {
332
378
  await access(path);
333
379
  return;
334
380
  } catch {
335
381
  await mkdir(dirname(path), { recursive: true });
336
- await writeFile(path, "// Generated by holo prepare. Do not edit.\n\nexport {}\n", "utf8");
382
+ await writeGeneratedFile(path, "// Generated by holo prepare. Do not edit.\n\nexport {}\n");
337
383
  }
338
384
  }
385
+ const STORAGE_CREDENTIAL_KEYS = /* @__PURE__ */ new Set(["accessKeyId", "secretAccessKey", "sessionToken"]);
386
+ function withoutStorageCredentials(disk) {
387
+ return Object.fromEntries(Object.entries(disk).filter(([key]) => !STORAGE_CREDENTIAL_KEYS.has(key)));
388
+ }
339
389
  function toStorageModuleOptions(loaded) {
340
390
  return {
341
391
  defaultDisk: loaded.storage.defaultDisk,
342
392
  routePrefix: loaded.storage.routePrefix,
343
- disks: { ...loaded.storage.disks }
393
+ disks: Object.fromEntries(Object.entries(loaded.storage.disks).map(([name, disk]) => [name, withoutStorageCredentials(disk)]))
344
394
  };
345
395
  }
346
396
  function resolveStorageSetup(storageModule, loaded) {
@@ -356,11 +406,8 @@ function resolveStorageSetup(storageModule, loaded) {
356
406
  normalized: storageModule.normalizeModuleOptions(options)
357
407
  };
358
408
  }
359
- function finalizeStorageSetup(storageModule, opts, resolver, s3Driver) {
409
+ function finalizeStorageSetup(storageModule, opts, resolver) {
360
410
  const normalized = storageModule.normalizeModuleOptions(opts._holoStorageModuleOptions);
361
- opts.runtimeConfig = opts.runtimeConfig || {};
362
- opts.runtimeConfig.holoStorage = normalized;
363
- storageModule.applyNitroStorageConfig(opts, normalized, s3Driver);
364
411
  if (storageModule.hasPublicLocalDisk(normalized)) {
365
412
  addServerHandler({
366
413
  route: `${normalized.routePrefix}/**`,
@@ -368,11 +415,6 @@ function finalizeStorageSetup(storageModule, opts, resolver, s3Driver) {
368
415
  });
369
416
  }
370
417
  }
371
- function applyStorageRuntimeConfig(runtimeConfig, normalized) {
372
- if (normalized) {
373
- runtimeConfig.holoStorage = normalized;
374
- }
375
- }
376
418
  async function createServerModelImports(projectRoot, modelsRelativePath, generatedSchemaRelativePath) {
377
419
  const modelsDir = resolve(projectRoot, modelsRelativePath);
378
420
  const generatedSchemaPath = resolve(projectRoot, generatedSchemaRelativePath);
@@ -408,16 +450,16 @@ async function createServerModelImports(projectRoot, modelsRelativePath, generat
408
450
  "export default () => {}"
409
451
  ];
410
452
  await mkdir(modelImportDir, { recursive: true });
411
- await writeFile(modelImportFile, `${lines.join("\n")}
412
- `, "utf8");
413
- await writeFile(modelPluginFile, `${pluginLines.join("\n")}
414
- `, "utf8");
453
+ await writeGeneratedFile(modelImportFile, `${lines.join("\n")}
454
+ `);
455
+ await writeGeneratedFile(modelPluginFile, `${pluginLines.join("\n")}
456
+ `);
415
457
  return {
416
458
  importDir: modelImportDir,
417
459
  pluginFile: modelPluginFile
418
460
  };
419
461
  }
420
- const module$1 = defineNuxtModule({
462
+ const holoNuxtModule = defineNuxtModule({
421
463
  meta: {
422
464
  name: "@holo-js/adapter-nuxt"
423
465
  },
@@ -433,7 +475,6 @@ const module$1 = defineNuxtModule({
433
475
  addViteOptimizeDeps(opts, resolveClientOptimizeDeps(rootDir));
434
476
  const storageModule = await importOptionalStorageModule();
435
477
  const loaded = await loadConfigDirectory(rootDir, {
436
- preferCache: process.env.NODE_ENV === "production",
437
478
  processEnv: process.env
438
479
  });
439
480
  if ((loaded.app.plugins ?? []).includes("@holo-js/panels")) {
@@ -443,9 +484,7 @@ const module$1 = defineNuxtModule({
443
484
  }
444
485
  }
445
486
  const storageSetup = resolveStorageSetup(storageModule, loaded);
446
- const s3Driver = resolver.resolve("./runtime/drivers/s3.js");
447
- opts.nitro = opts.nitro || { storage: {} };
448
- opts.nitro.storage = opts.nitro.storage || {};
487
+ opts.nitro = opts.nitro || {};
449
488
  if (isProjectPackageLinked(rootDir, "@holo-js/core")) {
450
489
  opts.nitro.rollupConfig = {
451
490
  ...opts.nitro.rollupConfig,
@@ -466,11 +505,8 @@ const module$1 = defineNuxtModule({
466
505
  };
467
506
  opts.runtimeConfig.holo = {
468
507
  appUrl: loaded.app.url,
469
- appEnv: loaded.app.env,
470
- appDebug: loaded.app.debug,
471
508
  projectRoot: rootDir
472
509
  };
473
- opts.runtimeConfig.db = loaded.database;
474
510
  const mergedStorageOptions = storageSetup.options;
475
511
  const normalizedStorage = storageSetup.normalized;
476
512
  opts._holoStorageModuleOptions = mergedStorageOptions;
@@ -479,11 +515,10 @@ const module$1 = defineNuxtModule({
479
515
  throw new Error("[@holo-js/adapter-nuxt] S3 storage disks require @holo-js/storage-s3 to be installed.");
480
516
  }
481
517
  }
482
- applyStorageRuntimeConfig(opts.runtimeConfig, normalizedStorage);
483
518
  if (!opts._holoCoreRuntimeRegistered) {
484
519
  if (existsSync(resolve(rootDir, ".holo-js/generated/definition-importer.ts"))) {
485
520
  const initPluginPath = resolve(rootDir, ".holo-js/generated/nuxt-init.ts");
486
- await writeFile(initPluginPath, [
521
+ await writeGeneratedFile(initPluginPath, [
487
522
  `import init from ${JSON.stringify(resolver.resolve("./runtime/plugins/init"))}`,
488
523
  "import { installProjectDefinitionImporter } from './definition-importer'",
489
524
  "",
@@ -491,7 +526,7 @@ const module$1 = defineNuxtModule({
491
526
  "",
492
527
  "export default init",
493
528
  ""
494
- ].join("\n"), "utf8");
529
+ ].join("\n"));
495
530
  addServerPlugin(initPluginPath);
496
531
  } else {
497
532
  addServerPlugin(resolver.resolve("./runtime/plugins/init"));
@@ -510,10 +545,6 @@ const module$1 = defineNuxtModule({
510
545
  }
511
546
  opts._holoCoreRuntimeRegistered = true;
512
547
  }
513
- if (storageModule && !opts._holoStorageRuntimeRegistered) {
514
- addServerPlugin(resolver.resolve("./runtime/plugins/storage"));
515
- opts._holoStorageRuntimeRegistered = true;
516
- }
517
548
  if (hasProjectPackage(rootDir, "@holo-js/broadcast") && !opts._holoBroadcastAuthRouteRegistered) {
518
549
  addServerHandler({
519
550
  route: "/broadcasting/config",
@@ -550,11 +581,12 @@ const module$1 = defineNuxtModule({
550
581
  route: "/holo/realtime/mutation",
551
582
  handler: resolver.resolve("./runtime/server/routes/realtime-mutation.post")
552
583
  });
584
+ opts.nitro.virtual = {
585
+ ...opts.nitro.virtual,
586
+ [realtimeDefinitionsModuleId]: () => renderRealtimeDefinitionsModule(rootDir)
587
+ };
553
588
  opts._holoRealtimeRouteRegistered = true;
554
589
  }
555
- if (storageModule && normalizedStorage && (!opts.nitro.storage || Object.keys(opts.nitro.storage).every((key) => !key.startsWith("holo:")))) {
556
- storageModule.applyNitroStorageConfig(opts, normalizedStorage, s3Driver);
557
- }
558
590
  const runtimePath = resolver.resolve("./runtime");
559
591
  for (const packageName of [runtimePath, "@holo-js/auth"]) {
560
592
  if (!opts.build.transpile.includes(packageName)) {
@@ -564,7 +596,7 @@ const module$1 = defineNuxtModule({
564
596
  if (storageModule && !opts._holoStorageFinalizeRegistered) {
565
597
  opts._holoStorageFinalizeRegistered = true;
566
598
  nuxt.hook("modules:done", () => {
567
- finalizeStorageSetup(storageModule, opts, resolver, s3Driver);
599
+ finalizeStorageSetup(storageModule, opts, resolver);
568
600
  });
569
601
  }
570
602
  if (!opts._holoTypesRegistered) {
@@ -572,12 +604,27 @@ const module$1 = defineNuxtModule({
572
604
  await ensureModelRegistryTypesPlaceholder(authTypesPath);
573
605
  await ensureModelRegistryTypesPlaceholder(authorizationTypesPath);
574
606
  await ensureModelRegistryTypesPlaceholder(modelRegistryTypesPath);
575
- nuxt.hook("prepare:types", ({ references }) => {
576
- references.push({ types: "@holo-js/adapter-nuxt" });
577
- references.push({ path: authTypesPath });
578
- references.push({ path: authorizationTypesPath });
579
- references.push({ path: modelRegistryTypesPath });
580
- for (const path of pluginTypesPaths) references.push({ path });
607
+ const serverTypeReferences = [authTypesPath, authorizationTypesPath, modelRegistryTypesPath, ...pluginTypesPaths].map((path) => ({ path }));
608
+ const serverTypeIncludes = [resolve(rootDir, "config/**/*")];
609
+ nuxt.hook("nitro:prepare:types", ({ references }) => {
610
+ references.push(...serverTypeReferences);
611
+ });
612
+ nuxt.hook("nitro:config", (nitroConfig) => {
613
+ nitroConfig.typescript ??= {};
614
+ nitroConfig.typescript.tsConfig ??= {};
615
+ nitroConfig.typescript.tsConfig.include = [...nitroConfig.typescript.tsConfig.include ?? [], ...serverTypeIncludes];
616
+ });
617
+ nuxt.hook("prepare:types", async ({ references, serverReferences, tsConfig, serverTsConfig }) => {
618
+ references.push({ types: "@holo-js/adapter-nuxt" }, ...serverTypeReferences);
619
+ serverReferences?.push(...serverTypeReferences);
620
+ if (serverTsConfig) serverTsConfig.include = [...serverTsConfig.include ?? [], ...serverTypeIncludes];
621
+ const options = nuxt.options;
622
+ const { projectTsconfigInternals } = await import('@holo-js/core');
623
+ await projectTsconfigInternals.writeNuxtTsconfigSnapshot(
624
+ rootDir,
625
+ options.typesDir || options.buildDir || resolve(rootDir, ".nuxt"),
626
+ { tsConfig, serverTsConfig }
627
+ );
581
628
  });
582
629
  }
583
630
  }
@@ -593,7 +640,6 @@ const moduleInternals = {
593
640
  hasModuleNotFoundCode,
594
641
  hasLoadedConfigFile,
595
642
  importOptionalStorageS3Module,
596
- applyStorageRuntimeConfig,
597
643
  finalizeStorageSetup,
598
644
  resolveStorageSetup,
599
645
  isModuleResolutionFailure,
@@ -602,6 +648,7 @@ const moduleInternals = {
602
648
  isProjectPackageLinked,
603
649
  isRealtimeDefinitionModule,
604
650
  resolveClientOptimizeDeps,
651
+ renderRealtimeDefinitionsModule,
605
652
  resolveExistingRealtimeDefinitionFile,
606
653
  resolveRealtimeDefinitionImport
607
654
  };
@@ -609,4 +656,4 @@ const adapterNuxtInternals = {
609
656
  toStorageModuleOptions
610
657
  };
611
658
 
612
- export { adapterNuxtInternals, module$1 as default, moduleInternals };
659
+ export { adapterNuxtInternals, holoNuxtModule as default, moduleInternals };
@@ -1,4 +1,4 @@
1
- import { createError } from "h3";
1
+ import { createError } from "#imports";
2
2
  export function createNuxtAuthorizationError(decision) {
3
3
  const status = decision.status === 404 ? 404 : 403;
4
4
  return createError({
@@ -1,5 +1,4 @@
1
1
  import type { HoloAdapterProjectAccessors } from '@holo-js/core'
2
- import type { RuntimeDatabaseConfig } from '@holo-js/db'
3
2
 
4
3
  export interface HoloRuntimeConnection {
5
4
  driver?: 'sqlite' | 'postgres' | 'mysql'
@@ -29,12 +28,9 @@ export interface HoloRuntimeDefaultConnection extends HoloRuntimeConnection {
29
28
  export declare const holo: HoloAdapterProjectAccessors
30
29
  export declare function configureHoloRuntimeConfig(config: {
31
30
  holo: {
32
- appEnv: 'production' | 'development' | 'test'
33
- appDebug: boolean
34
31
  appUrl?: string
35
32
  projectRoot?: string
36
33
  }
37
- db?: RuntimeDatabaseConfig
38
34
  }): void
39
35
  export declare function resetHoloRuntimeConfig(): void
40
36
  export type NuxtAuthRequestEvent = {
@@ -52,8 +48,10 @@ export type NuxtAuthRequestEvent = {
52
48
  readonly headers?: Readonly<Record<string, string | readonly string[] | undefined>>
53
49
  }
54
50
  readonly res?: {
51
+ statusCode: number
55
52
  getHeader(name: string): number | string | readonly string[] | undefined
56
53
  setHeader(name: string, value: number | string | readonly string[]): void
54
+ end(): void
57
55
  }
58
56
  }
59
57
  }
@@ -1,8 +1,10 @@
1
+ import { resolveProjectAppEnvironmentSync } from "@holo-js/config";
1
2
  import {
2
3
  createHoloProjectAccessors,
4
+ getHolo,
3
5
  initializeHoloAdapterProject
4
6
  } from "@holo-js/core";
5
- import { createNuxtAuthorizationError } from "../authorization-error.js";
7
+ import { createCookieWriteUnavailableError } from "@holo-js/kernel";
6
8
  export function configureHoloRuntimeConfig(config) {
7
9
  const runtimeGlobals = globalThis;
8
10
  runtimeGlobals.__holoRuntimeConfig = config;
@@ -21,14 +23,12 @@ function getRuntimeConfig() {
21
23
  }
22
24
  return runtimeGlobals.useRuntimeConfig();
23
25
  }
24
- function resolveRuntimeEnvName(env) {
25
- return env;
26
- }
27
26
  function resolveRuntimeProjectRoot(config) {
28
27
  return config.holo.projectRoot?.trim() || process.cwd();
29
28
  }
30
- async function loadNitroContextModule() {
31
- return await import("nitropack/runtime/context");
29
+ async function resolveNitroEvent() {
30
+ const { useEvent } = await import("#imports");
31
+ return useEvent();
32
32
  }
33
33
  export function createNuxtAuthRequestAccessors(requestEvent) {
34
34
  function safeDecode(value) {
@@ -39,7 +39,7 @@ export function createNuxtAuthRequestAccessors(requestEvent) {
39
39
  }
40
40
  }
41
41
  async function readHeader(name) {
42
- const event = requestEvent ?? (await loadNitroContextModule()).useEvent();
42
+ const event = requestEvent ?? await resolveNitroEvent();
43
43
  if (!event) {
44
44
  return void 0;
45
45
  }
@@ -80,11 +80,14 @@ export function createNuxtAuthRequestAccessors(requestEvent) {
80
80
  }
81
81
  return void 0;
82
82
  }
83
+ async function resolveResponse() {
84
+ const event = requestEvent ?? await resolveNitroEvent();
85
+ return event?.node?.res;
86
+ }
83
87
  async function appendCookie(cookie) {
84
- const event = requestEvent ?? (await loadNitroContextModule()).useEvent();
85
- const response = event?.node?.res;
88
+ const response = await resolveResponse();
86
89
  if (!response) {
87
- return;
90
+ throw createCookieWriteUnavailableError("Authentication cookies cannot be set outside an active Nitro request.");
88
91
  }
89
92
  const current = response.getHeader("set-cookie");
90
93
  if (Array.isArray(current)) {
@@ -103,20 +106,26 @@ export function createNuxtAuthRequestAccessors(requestEvent) {
103
106
  const getHeaderValue = async (name) => {
104
107
  return await readHeader(name);
105
108
  };
109
+ const canAppendResponseCookie = async () => {
110
+ return Boolean(await resolveResponse());
111
+ };
106
112
  const appendResponseCookie = async (cookie) => {
107
113
  await appendCookie(cookie);
108
114
  };
109
115
  const redirectResponse = async (url, status) => {
110
- const event = requestEvent ?? (await loadNitroContextModule()).useEvent();
111
- if (!event) {
116
+ const event = requestEvent ?? await resolveNitroEvent();
117
+ const response = event?.node?.res;
118
+ if (!response) {
112
119
  throw new TypeError("Holo Nuxt auth redirect requires an active Nitro event.");
113
120
  }
114
- const { sendRedirect } = await import("h3");
115
- await sendRedirect(event, url, status);
121
+ response.statusCode = status ?? 302;
122
+ response.setHeader("location", url);
123
+ response.end();
116
124
  };
117
125
  return {
118
126
  getCookie: getCookieValue,
119
127
  getHeader: getHeaderValue,
128
+ canAppendResponseCookie,
120
129
  appendResponseCookie,
121
130
  redirectResponse
122
131
  };
@@ -130,9 +139,8 @@ export async function runWithNuxtRequest(event, callback) {
130
139
  export const holo = createHoloProjectAccessors(async () => {
131
140
  const config = getRuntimeConfig();
132
141
  const authRequest = createNuxtAuthRequestAccessors();
142
+ const { createNuxtAuthorizationError } = await import("../authorization-error.js");
133
143
  const project = await initializeHoloAdapterProject(resolveRuntimeProjectRoot(config), {
134
- envName: resolveRuntimeEnvName(config.holo.appEnv),
135
- preferCache: process.env.NODE_ENV === "production",
136
144
  processEnv: process.env,
137
145
  authRequest,
138
146
  authorizationError: {
@@ -142,17 +150,12 @@ export const holo = createHoloProjectAccessors(async () => {
142
150
  const runtimeGlobals = globalThis;
143
151
  runtimeGlobals.__holoNuxtAuthRequestRunner = (accessors, callback) => project.runtime.runWithAuthRequestAccessors(accessors, callback);
144
152
  return project;
145
- }, { cache: process.env.NODE_ENV === "production" });
146
- function resolveDefaultConnectionName(group) {
147
- if (group.defaultConnection) {
148
- return group.defaultConnection;
149
- }
150
- const connectionNames = Object.keys(group.connections);
151
- if (connectionNames.includes("default")) {
152
- return "default";
153
- }
154
- return connectionNames[0] ?? "default";
155
- }
153
+ }, {
154
+ cache: () => resolveProjectAppEnvironmentSync({
155
+ cwd: resolveRuntimeProjectRoot(getRuntimeConfig()),
156
+ processEnv: process.env
157
+ }) === "production"
158
+ });
156
159
  function normalizeConnection(connection) {
157
160
  const driver = connection.driver ?? (connection.filename ? "sqlite" : void 0);
158
161
  const database = connection.database ?? connection.filename;
@@ -171,14 +174,10 @@ function normalizeConnection(connection) {
171
174
  };
172
175
  }
173
176
  export function useHoloDb() {
174
- const config = getRuntimeConfig();
175
- const group = config.db ?? { connections: {} };
177
+ const group = getHolo().loadedConfig.database;
176
178
  const connections = group.connections ?? {};
177
179
  return {
178
- defaultConnection: resolveDefaultConnectionName({
179
- defaultConnection: group.defaultConnection,
180
- connections
181
- }),
180
+ defaultConnection: group.defaultConnection ?? "default",
182
181
  connections: Object.fromEntries(
183
182
  Object.entries(connections).map(([name, connection]) => {
184
183
  if (typeof connection === "string") {
@@ -190,10 +189,8 @@ export function useHoloDb() {
190
189
  };
191
190
  }
192
191
  export function useHoloEnv() {
193
- const config = getRuntimeConfig();
194
- return resolveRuntimeEnvName(config.holo.appEnv);
192
+ return getHolo().loadedConfig.environment.name;
195
193
  }
196
194
  export function useHoloDebug() {
197
- const config = getRuntimeConfig();
198
- return config.holo.appDebug;
195
+ return getHolo().loadedConfig.app.debug;
199
196
  }
@@ -1,4 +1,4 @@
1
- import { defineNitroPlugin } from "nitropack/runtime/plugin";
1
+ import { defineNitroPlugin } from "#imports";
2
2
  import {
3
3
  applyFormFailureRedirect,
4
4
  getFormFailurePayload,
@@ -3,31 +3,47 @@ import {
3
3
  configureHoloRuntimeConfig
4
4
  } from "../composables/index.js";
5
5
  import { createNuxtAuthorizationError } from "../authorization-error.js";
6
+ import { connectionAddress } from "../server/connection-address.js";
6
7
  import { initializeHoloAdapterProject } from "@holo-js/core";
7
- import { useRuntimeConfig } from "nitropack/runtime/config";
8
- import { defineNitroPlugin } from "nitropack/runtime/plugin";
8
+ import { requestUrlInternals } from "@holo-js/kernel";
9
+ import { captureErrorReporter } from "@holo-js/kernel/error-reporting";
10
+ import { defineNitroPlugin, useEvent, useRuntimeConfig } from "#imports";
9
11
  export default defineNitroPlugin((nitroApp) => {
10
12
  const config = useRuntimeConfig();
11
13
  configureHoloRuntimeConfig(config);
14
+ requestUrlInternals.provideConnectionAddress(() => connectionAddress(useEvent().node.req.socket));
12
15
  const project = initializeHoloAdapterProject(config.holo.projectRoot?.trim() || process.cwd(), {
13
- envName: config.holo.appEnv,
14
- preferCache: process.env.NODE_ENV === "production",
15
16
  processEnv: process.env,
16
17
  authRequest: createNuxtAuthRequestAccessors(),
17
18
  authorizationError: {
18
19
  createError: createNuxtAuthorizationError
19
20
  }
20
21
  });
22
+ let projectPending = true;
23
+ const markProjectSettled = () => {
24
+ projectPending = false;
25
+ };
26
+ const projectSettled = project.then(markProjectSettled, markProjectSettled);
21
27
  const onRequest = nitroApp.h3App.options.onRequest;
22
28
  nitroApp.h3App.options.onRequest = async (event) => {
23
29
  await project;
24
30
  return await onRequest?.(event);
25
31
  };
26
- nitroApp.hooks.hook("close", async () => {
32
+ const shutdownProject = async () => {
33
+ let report;
27
34
  try {
28
- await (await project).runtime.shutdown();
29
- } catch {
35
+ const { runtime } = await project;
36
+ report = captureErrorReporter();
37
+ await runtime.shutdown();
38
+ } catch (error) {
39
+ (report ?? captureErrorReporter())(error, { capability: "nuxt", operation: "shutdown" });
40
+ }
41
+ };
42
+ nitroApp.hooks.hook("close", async () => {
43
+ if (projectPending) {
44
+ void projectSettled.then(shutdownProject);
30
45
  return;
31
46
  }
47
+ await shutdownProject();
32
48
  });
33
49
  });
@@ -0,0 +1,7 @@
1
+ function isUnixSocket(socket) {
2
+ return !socket.destroyed && Object.keys(socket.address()).length === 0;
3
+ }
4
+ export function connectionAddress(socket) {
5
+ if (socket.remoteAddress) return socket.remoteAddress;
6
+ return isUnixSocket(socket) ? "127.0.0.1" : void 0;
7
+ }
@@ -1,26 +1,17 @@
1
- import { send, setHeader, setResponseStatus } from "h3";
2
- import { isValidationException } from "@holo-js/validation";
3
- import { serializeRateLimitError } from "@holo-js/adapter-shared/server-errors";
1
+ import { send, setHeader, setResponseStatus } from "#imports";
2
+ import { serializeValidationException } from "@holo-js/validation";
3
+ import { serializeRateLimitError, serializeRequestBodyTooLargeError } from "@holo-js/adapter-shared/server-errors";
4
4
  import {
5
5
  applyFormFailureRedirect,
6
6
  shouldRedirectFormFailure
7
7
  } from "./form-failure.js";
8
- function findValidationException(error) {
9
- if (isValidationException(error)) {
10
- return error;
11
- }
12
- if (!error || typeof error !== "object" || !("cause" in error)) {
13
- return void 0;
14
- }
15
- return findValidationException(error.cause);
16
- }
17
8
  export default async function handleValidationError(error, event) {
18
- const validationError = findValidationException(error);
19
- const payload = validationError?.toJSON() ?? serializeRateLimitError(error);
9
+ const bodyTooLarge = serializeRequestBodyTooLargeError(error);
10
+ const payload = bodyTooLarge ?? serializeValidationException(error) ?? serializeRateLimitError(error);
20
11
  if (!payload) {
21
12
  return;
22
13
  }
23
- if (shouldRedirectFormFailure(event)) {
14
+ if (!bodyTooLarge && shouldRedirectFormFailure(event)) {
24
15
  const failure = { ...payload };
25
16
  const response = {};
26
17
  applyFormFailureRedirect(event, response, failure);
@@ -1,3 +1,4 @@
1
+ import { resolveRequestUrl, sameOriginRedirectPath } from "@holo-js/kernel";
1
2
  const FORM_FAILURE_COOKIE = "holo_form_failure";
2
3
  function getHeader(event, name) {
3
4
  const value = event.node?.req?.headers?.[name.toLowerCase()];
@@ -42,12 +43,12 @@ function getRedirectLocation(event) {
42
43
  try {
43
44
  const url = new URL(referer);
44
45
  if (url.host === host) {
45
- return `${url.pathname}${url.search}`;
46
+ return sameOriginRedirectPath(`${url.pathname}${url.search}`);
46
47
  }
47
48
  } catch {
48
49
  }
49
50
  }
50
- return event.path ?? event.node?.req?.url ?? "/";
51
+ return sameOriginRedirectPath(event.path ?? event.node?.req?.url);
51
52
  }
52
53
  function appendSetCookie(event, response, cookie) {
53
54
  const responseCookie = event.node?.res?.getHeader?.("set-cookie");
@@ -79,9 +80,21 @@ function setHeader(event, response, name, value) {
79
80
  response.headers ??= {};
80
81
  response.headers[name] = value;
81
82
  }
82
- function serializeFormFailureCookie(payload) {
83
- const encoded = encodeURIComponent(JSON.stringify(payload));
84
- return `${FORM_FAILURE_COOKIE}=${encoded}; Path=/; Max-Age=60; SameSite=Lax`;
83
+ function isSecureRequest(event) {
84
+ const request = event.node?.req;
85
+ const socket = request?.socket;
86
+ const protocol = socket && "encrypted" in socket && socket.encrypted === true ? "https" : "http";
87
+ try {
88
+ return resolveRequestUrl({ url: `${protocol}://localhost/`, headers: request?.headers }).protocol === "https:";
89
+ } catch {
90
+ return protocol === "https";
91
+ }
92
+ }
93
+ function serializeFormFailureCookie(event, payload) {
94
+ const { values: _values, ...failure } = payload;
95
+ const encoded = encodeURIComponent(JSON.stringify(failure));
96
+ const secure = isSecureRequest(event) ? "; Secure" : "";
97
+ return `${FORM_FAILURE_COOKIE}=${encoded}; Path=/; Max-Age=60; SameSite=Lax${secure}`;
85
98
  }
86
99
  export function shouldRedirectFormFailure(event) {
87
100
  return isUnsafeMethod(event) && acceptsHtml(event) && !isApiRequest(event);
@@ -96,7 +109,7 @@ export function applyFormFailureRedirect(event, response, failure) {
96
109
  response.body = "";
97
110
  setHeader(event, response, "location", getRedirectLocation(event));
98
111
  setHeader(event, response, "content-type", "text/html; charset=utf-8");
99
- appendSetCookie(event, response, serializeFormFailureCookie(failure));
112
+ appendSetCookie(event, response, serializeFormFailureCookie(event, failure));
100
113
  }
101
114
  export const formFailureInternals = {
102
115
  appendSetCookie
@@ -0,0 +1,39 @@
1
+ import { createError, getHeaders, getRequestHeader, getRequestURL } from "#imports";
2
+ import { HoloRequestBodyTooLargeError, readBoundedBufferedBody, readBoundedNodeRequestBody, requestBodyLimitFor } from "@holo-js/kernel";
3
+ async function readBoundedEventBody(event) {
4
+ const limit = requestBodyLimitFor(getRequestHeader(event, "content-type"));
5
+ try {
6
+ const node = event.node.req;
7
+ const buffered = await readBoundedBufferedBody(
8
+ event._requestBody || event.web?.request?.body || node[Symbol.for("h3RawBody")] || node.rawBody || node.body,
9
+ limit
10
+ );
11
+ if (buffered) return buffered;
12
+ const bytes = await readBoundedNodeRequestBody(event.node.req, limit, getRequestHeader(event, "content-length"));
13
+ event._requestBody = bytes;
14
+ Object.assign(event.node.req, { [Symbol.for("h3RawBody")]: bytes });
15
+ return { bytes };
16
+ } catch (error) {
17
+ if (error instanceof HoloRequestBodyTooLargeError) {
18
+ throw createError({ statusCode: error.status, statusMessage: "Payload Too Large", cause: error });
19
+ }
20
+ throw error;
21
+ }
22
+ }
23
+ export async function createWebRequest(event) {
24
+ const buffered = await readBoundedEventBody(event);
25
+ const headers = new Headers();
26
+ for (const [key, value] of Object.entries(getHeaders(event))) {
27
+ if (typeof value === "string") {
28
+ headers.set(key, value);
29
+ }
30
+ }
31
+ if (buffered.contentType) {
32
+ headers.set("content-type", buffered.contentType);
33
+ }
34
+ return new Request(getRequestURL(event, { xForwardedProto: false }), {
35
+ body: buffered.bytes,
36
+ headers,
37
+ method: event.method
38
+ });
39
+ }
@@ -1,6 +1,7 @@
1
- import { defineEventHandler, getHeaders, getRequestURL, readRawBody } from "h3";
1
+ import { defineEventHandler } from "#imports";
2
2
  import { renderBroadcastAuthResponse } from "@holo-js/broadcast/auth";
3
3
  import { holo } from "../../composables/index.js";
4
+ import { createWebRequest } from "../route-request.js";
4
5
  function resolveBroadcastSigning(connection) {
5
6
  if (!connection || typeof connection !== "object") {
6
7
  return {};
@@ -20,18 +21,7 @@ export default defineEventHandler(async (event) => {
20
21
  const broadcast = app.config?.broadcast;
21
22
  const connection = broadcast ? broadcast.connections[broadcast.default] : void 0;
22
23
  const signing = resolveBroadcastSigning(connection);
23
- const headers = new Headers();
24
- for (const [key, value] of Object.entries(getHeaders(event))) {
25
- if (typeof value === "string") {
26
- headers.set(key, value);
27
- }
28
- }
29
- const request = new Request(getRequestURL(event), {
30
- method: event.method,
31
- headers,
32
- body: await readRawBody(event)
33
- });
34
- return await renderBroadcastAuthResponse(request, {
24
+ return await renderBroadcastAuthResponse(await createWebRequest(event), {
35
25
  ...signing,
36
26
  resolveUser: async (_request, context) => {
37
27
  const guardAuth = context.guard ? auth?.guard(context.guard) : void 0;
@@ -1,4 +1,4 @@
1
- import { defineEventHandler } from "h3";
1
+ import { defineEventHandler } from "#imports";
2
2
  import { renderBroadcastClientConfigResponse } from "@holo-js/broadcast/client-config";
3
3
  import { holo } from "../../composables/index.js";
4
4
  export default defineEventHandler(async () => {
@@ -1,9 +1,10 @@
1
- import { defineEventHandler } from "h3";
2
- import { useRuntimeConfig } from "#imports";
1
+ import { defineEventHandler, useRuntimeConfig } from "#imports";
3
2
  import { handleRealtimeMutationRequest } from "@holo-js/realtime/server";
4
- import { createRealtimeRequest } from "./realtime-request.js";
3
+ import { realtimeDefinitions } from "#holo/realtime-definitions";
4
+ import { createWebRequest } from "../route-request.js";
5
5
  export default defineEventHandler(async (event) => {
6
- return await handleRealtimeMutationRequest(await createRealtimeRequest(event), {
7
- projectRoot: useRuntimeConfig().holo.projectRoot ?? process.cwd()
6
+ return await handleRealtimeMutationRequest(await createWebRequest(event), {
7
+ projectRoot: useRuntimeConfig().holo.projectRoot ?? process.cwd(),
8
+ definitions: realtimeDefinitions
8
9
  });
9
10
  });
@@ -1,9 +1,10 @@
1
- import { defineEventHandler } from "h3";
2
- import { useRuntimeConfig } from "#imports";
1
+ import { defineEventHandler, useRuntimeConfig } from "#imports";
3
2
  import { handleRealtimeQueryRequest } from "@holo-js/realtime/server";
4
- import { createRealtimeRequest } from "./realtime-request.js";
3
+ import { realtimeDefinitions } from "#holo/realtime-definitions";
4
+ import { createWebRequest } from "../route-request.js";
5
5
  export default defineEventHandler(async (event) => {
6
- return await handleRealtimeQueryRequest(await createRealtimeRequest(event), {
7
- projectRoot: useRuntimeConfig().holo.projectRoot ?? process.cwd()
6
+ return await handleRealtimeQueryRequest(await createWebRequest(event), {
7
+ projectRoot: useRuntimeConfig().holo.projectRoot ?? process.cwd(),
8
+ definitions: realtimeDefinitions
8
9
  });
9
10
  });
@@ -1,8 +1,14 @@
1
1
  import { createPublicStorageResponse } from "@holo-js/storage";
2
- import { defineEventHandler, sendWebResponse, toWebRequest } from "h3";
2
+ import { defineEventHandler, getRequestURL, sendWebResponse } from "#imports";
3
3
  import { holo } from "../../composables/index.js";
4
+ function createStorageRequest(event) {
5
+ return event.web?.request ?? new Request(getRequestURL(event, { xForwardedProto: false }), {
6
+ method: event.method,
7
+ headers: event.headers
8
+ });
9
+ }
4
10
  export default defineEventHandler(async (event) => {
5
11
  const app = await holo.getApp();
6
- const response = await createPublicStorageResponse(app.projectRoot, app.config.storage, toWebRequest(event), app.config.app.key);
12
+ const response = await createPublicStorageResponse(app.projectRoot, app.config.storage, createStorageRequest(event), app.config.app.key);
7
13
  return sendWebResponse(event, response);
8
14
  });
@@ -1,45 +1,12 @@
1
- import type { RuntimeConfigInput, RuntimeConnectionConfig, RuntimeDatabaseConfig } from '@holo-js/db'
2
-
3
- type HoloConnectionRuntimeConfig = RuntimeConnectionConfig
4
- type HoloDatabaseRuntimeConfig = RuntimeDatabaseConfig
5
-
6
- interface StorageRuntimeDriverShim {
7
- name: string
8
- driver: 'local' | 'public' | 's3'
9
- visibility: 'private' | 'public'
10
- root?: string
11
- url?: string
12
- bucket?: string
13
- region?: string
14
- endpoint?: string
15
- accessKeyId?: string
16
- secretAccessKey?: string
17
- sessionToken?: string
18
- forcePathStyleEndpoint?: boolean
19
- }
1
+ import type { RuntimeConfigInput } from '@holo-js/db'
20
2
 
21
3
  interface HoloRuntimeConfig extends RuntimeConfigInput {
22
4
  holo: NonNullable<RuntimeConfigInput['holo']> & {
23
- appEnv: 'production' | 'development' | 'test'
24
- appDebug: boolean
25
5
  appUrl?: string
26
6
  projectRoot?: string
27
7
  }
28
- db?: HoloDatabaseRuntimeConfig
29
- holoStorage: {
30
- defaultDisk: string | undefined
31
- diskNames: string[]
32
- routePrefix: string
33
- disks: Record<string, StorageRuntimeDriverShim>
34
- }
35
8
  }
36
9
 
37
- /**
38
- * Minimal Nuxt runtime shims for adapter typechecking.
39
- *
40
- * Keep these declarations limited to the fields consumed by adapter runtime code:
41
- * runtime config, storage access, and Nitro route/plugin globals.
42
- */
43
10
  declare module '#app' {
44
11
  export function defineNuxtPlugin<T>(plugin: T): T
45
12
  export function useRuntimeConfig(): HoloRuntimeConfig
@@ -48,23 +15,9 @@ declare module '#app' {
48
15
 
49
16
  declare module '#imports' {
50
17
  export function useRuntimeConfig(): HoloRuntimeConfig
51
- export function useStorage(base: string): unknown
52
- }
53
-
54
- declare module 'nitropack/runtime/config' {
55
- export function useRuntimeConfig(): HoloRuntimeConfig
56
- }
57
-
58
- declare module 'nitropack/runtime/context' {
59
- export function useEvent(): unknown
60
- }
61
-
62
- declare module 'nitropack/runtime/plugin' {
18
+ export function useEvent(): import('h3').H3Event
63
19
  export function defineNitroPlugin<T>(plugin: T): T
64
- }
65
-
66
- declare module 'nitropack/runtime/storage' {
67
- export function useStorage(base: string): unknown
20
+ export * from 'h3'
68
21
  }
69
22
 
70
23
  declare global {
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "@holo-js/adapter-nuxt",
3
- "version": "0.3.27",
3
+ "version": "0.4.0",
4
4
  "description": "Holo-JS Framework - Nuxt adapter",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/cobraprojects/holo-js.git",
10
+ "directory": "packages/adapter-nuxt"
11
+ },
7
12
  "exports": {
8
13
  ".": {
9
14
  "types": "./dist/types.d.mts",
@@ -29,7 +34,8 @@
29
34
  "main": "./dist/module.mjs",
30
35
  "types": "./dist/types.d.mts",
31
36
  "files": [
32
- "dist"
37
+ "dist",
38
+ "LICENSE"
33
39
  ],
34
40
  "scripts": {
35
41
  "build": "nuxt-module-build build",
@@ -38,22 +44,22 @@
38
44
  "test": "vitest --run"
39
45
  },
40
46
  "dependencies": {
41
- "@holo-js/adapter-shared": "^0.3.27",
42
- "@nuxt/kit": "^4.4.4",
43
- "@holo-js/config": "^0.3.27",
44
- "@holo-js/core": "^0.3.27",
45
- "@holo-js/db": "^0.3.27",
46
- "@holo-js/validation": "^0.3.27",
47
- "h3": "^1.15.11",
48
- "nitropack": "^2.13.4"
47
+ "@holo-js/adapter-shared": "^0.4.0",
48
+ "@nuxt/kit": "^4.6.2",
49
+ "@holo-js/config": "^0.4.0",
50
+ "@holo-js/core": "^0.4.0",
51
+ "@holo-js/db": "^0.4.0",
52
+ "@holo-js/kernel": "^0.4.0",
53
+ "@holo-js/validation": "^0.4.0"
49
54
  },
50
55
  "peerDependencies": {
56
+ "nuxt": "^4.6.2",
51
57
  "vue": "^3.5.13",
52
- "@holo-js/broadcast": "^0.3.27",
53
- "@holo-js/forms": "^0.3.27",
54
- "@holo-js/realtime": "^0.3.27",
55
- "@holo-js/storage": "^0.3.27",
56
- "@holo-js/storage-s3": "^0.3.27"
58
+ "@holo-js/broadcast": "^0.4.0",
59
+ "@holo-js/forms": "^0.4.0",
60
+ "@holo-js/realtime": "^0.4.0",
61
+ "@holo-js/storage": "^0.4.0",
62
+ "@holo-js/storage-s3": "^0.4.0"
57
63
  },
58
64
  "peerDependenciesMeta": {
59
65
  "@holo-js/broadcast": {
@@ -74,17 +80,18 @@
74
80
  },
75
81
  "devDependencies": {
76
82
  "vue": "^3.5.13",
77
- "@holo-js/broadcast": "^0.3.27",
78
- "@holo-js/realtime": "^0.3.27",
79
- "@holo-js/storage-s3": "^0.3.27",
83
+ "@holo-js/broadcast": "^0.4.0",
84
+ "@holo-js/realtime": "^0.4.0",
85
+ "@holo-js/storage-s3": "^0.4.0",
80
86
  "@nuxt/module-builder": "^1.0.2",
81
- "@types/node": "^22.10.2",
82
- "nuxt": "^4.4.4",
83
- "typescript": "^5.7.2",
84
- "vitest": "^4.1.5",
85
- "@nuxt/nitro-server": "^4.4.4"
87
+ "@types/node": "^22.20.5",
88
+ "nuxt": "^4.6.2",
89
+ "typescript": "^6.0.3",
90
+ "vitest": "^5.0.5",
91
+ "@nuxt/nitro-server": "^4.6.2",
92
+ "h3": "^1.15.11"
86
93
  },
87
94
  "engines": {
88
- "node": "^22.12.0 || ^24.0.0 || ^26.0.0"
95
+ "node": "^22.18.0 || ^24.0.0 || ^26.0.0"
89
96
  }
90
97
  }
@@ -1 +0,0 @@
1
- export { default } from "@holo-js/storage-s3";
@@ -1,10 +0,0 @@
1
- import { configureStorageRuntime } from "@holo-js/storage/runtime";
2
- import { useRuntimeConfig } from "nitropack/runtime/config";
3
- import { defineNitroPlugin } from "nitropack/runtime/plugin";
4
- import { useStorage as useNitroStorage } from "nitropack/runtime/storage";
5
- export default defineNitroPlugin(() => {
6
- configureStorageRuntime({
7
- getRuntimeConfig: () => useRuntimeConfig(),
8
- getStorage: (base) => useNitroStorage(base)
9
- });
10
- });
File without changes
@@ -1,14 +0,0 @@
1
- import { getHeaders, getRequestURL, readRawBody } from "h3";
2
- export async function createRealtimeRequest(event) {
3
- const headers = new Headers();
4
- for (const [key, value] of Object.entries(getHeaders(event))) {
5
- if (typeof value === "string") {
6
- headers.set(key, value);
7
- }
8
- }
9
- return new Request(getRequestURL(event), {
10
- body: await readRawBody(event),
11
- headers,
12
- method: event.method
13
- });
14
- }