@holo-js/adapter-nuxt 0.3.28 → 0.4.1

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
+ a3ee6a1d83162db89678b9cb4ef2211ad9a3369497da63f74b3b24c7fd4f739a
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.28",
4
+ "version": "0.4.1",
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,23 +1,25 @@
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:";
20
- const VALIDATION_CLIENT_DEPENDENCIES = ["valibot", "file-type"];
21
+ const realtimeDefinitionsModuleId = "#holo/realtime-definitions";
22
+ const VALIDATION_CLIENT_DEPENDENCIES = ["valibot", "@holo-js/kernel > file-type"];
21
23
  const CLIENT_OPTIMIZE_DEPS = [
22
24
  {
23
25
  packageName: `${HOLO_PACKAGE_SCOPE}forms`,
@@ -174,8 +176,12 @@ function resolveProjectPackageTraceEntry(rootDir, packageName) {
174
176
  return resolveProjectPackageEntry(rootDir, packageName);
175
177
  }
176
178
  function isProjectPackageLinked(rootDir, packageRootName) {
177
- const projectPackageRoot = resolve(rootDir, "node_modules", packageRootName);
178
- return lstatSync(projectPackageRoot, { throwIfNoEntry: false })?.isSymbolicLink() === true;
179
+ const projectRequire = createRequire(resolve(rootDir, "package.json"));
180
+ for (const nodeModulesPath of projectRequire.resolve.paths(packageRootName) ?? []) {
181
+ const packageStats = lstatSync(resolve(nodeModulesPath, packageRootName), { throwIfNoEntry: false });
182
+ if (packageStats) return packageStats.isSymbolicLink();
183
+ }
184
+ return false;
179
185
  }
180
186
  function addNitroRuntimeTraceIncludes(opts, rootDir, pluginPackages = [], resolvePackage = resolveProjectPackageTraceEntry) {
181
187
  const externals = opts.nitro.externals ?? {};
@@ -230,10 +236,10 @@ function addViteOptimizeDeps(opts, deps) {
230
236
  ])
231
237
  ];
232
238
  }
233
- function isRealtimeDefinitionModule(_rootDir, id) {
239
+ function isRealtimeDefinitionModule(rootDir, id, directories = resolveRealtimeDefinitionDirectories(rootDir)) {
234
240
  const [sourcePath = ""] = id.split("?");
235
241
  const normalizedId = sourcePath.replaceAll("\\", "/");
236
- return normalizedId.includes("/server/realtime/") && MODEL_FILE_EXTENSIONS.has(extname(normalizedId));
242
+ return (normalizedId.includes("/server/realtime/") || isInRealtimeDefinitionDirectory(directories, normalizedId)) && MODEL_FILE_EXTENSIONS.has(extname(normalizedId));
237
243
  }
238
244
  function resolveExistingRealtimeDefinitionFile(path) {
239
245
  if (MODEL_FILE_EXTENSIONS.has(extname(path)) && existsFile(path)) {
@@ -261,10 +267,39 @@ function resolveRealtimeDefinitionImport(source, importer) {
261
267
  const basePath = source.startsWith(".") ? importer ? resolve(dirname(importer.split("?")[0]), source) : void 0 : resolve(source);
262
268
  return basePath ? resolveExistingRealtimeDefinitionFile(basePath) : void 0;
263
269
  }
270
+ function collectRealtimeDefinitionFiles(rootDir) {
271
+ const realtimeRoot = resolve(rootDir, "server/realtime");
272
+ if (!existsSync(realtimeRoot)) {
273
+ return [];
274
+ }
275
+ 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));
276
+ }
277
+ function renderRealtimeDefinitionsModule(rootDir) {
278
+ const files = collectRealtimeDefinitionFiles(rootDir);
279
+ const imports = files.map((filePath, index) => `import * as realtimeModule${index} from ${JSON.stringify(filePath)}`);
280
+ const values = files.map((_filePath, index) => `...Object.values(realtimeModule${index})`);
281
+ return [
282
+ ...imports,
283
+ "",
284
+ `export const realtimeDefinitions = [${values.join(", ")}]`,
285
+ ""
286
+ ].join("\n");
287
+ }
264
288
  function createRealtimeDefinitionVitePlugin(rootDir) {
289
+ const directories = resolveRealtimeDefinitionDirectories(rootDir);
290
+ let realtimeTreeChanged = false;
291
+ const loadedDefinitionIds = /* @__PURE__ */ new Set();
265
292
  return {
266
293
  name: "holo-realtime-client-definitions",
267
294
  enforce: "pre",
295
+ buildStart() {
296
+ assertRealtimeDefinitionTree(rootDir);
297
+ },
298
+ configureServer(server) {
299
+ server.watcher.on("all", (_event, path) => {
300
+ if (isInRealtimeDefinitionDirectory(directories, path)) realtimeTreeChanged = true;
301
+ });
302
+ },
268
303
  resolveId(source, importer, options) {
269
304
  if (options?.ssr) {
270
305
  return null;
@@ -272,22 +307,32 @@ function createRealtimeDefinitionVitePlugin(rootDir) {
272
307
  const resolved = resolveRealtimeDefinitionImport(source, importer);
273
308
  return resolved ? `${realtimeClientDefinitionPrefix}${resolved}` : null;
274
309
  },
275
- load(id) {
276
- if (!id.startsWith(realtimeClientDefinitionPrefix)) {
310
+ load(id, options) {
311
+ if (!options?.ssr && realtimeTreeChanged) {
312
+ assertRealtimeDefinitionTree(rootDir);
313
+ realtimeTreeChanged = false;
314
+ }
315
+ if (id.startsWith(realtimeClientDefinitionPrefix)) {
316
+ const sourcePath2 = id.slice(realtimeClientDefinitionPrefix.length);
317
+ loadedDefinitionIds.add(id);
318
+ return createRealtimeClientDefinitionModule(readFileSync(sourcePath2, "utf8"), sourcePath2);
319
+ }
320
+ if (options?.ssr || !isRealtimeDefinitionModule(rootDir, id, directories)) {
277
321
  return null;
278
322
  }
279
- const sourcePath = id.slice(realtimeClientDefinitionPrefix.length);
280
- return createRealtimeClientDefinitionModule(readFileSync(sourcePath, "utf8"));
323
+ const sourcePath = id.split("?")[0];
324
+ loadedDefinitionIds.add(id);
325
+ return createRealtimeClientDefinitionModule(readFileSync(sourcePath, "utf8"), sourcePath);
281
326
  },
282
327
  transform(code, id, options) {
283
328
  if (!options?.ssr && !id.includes("node_modules") && /\.[cm]?[jt]sx?$/.test(id)) {
284
329
  const compiled = compileBrowserValidation(code, id);
285
330
  if (compiled) return { code: compiled, map: null };
286
331
  }
287
- if (options?.ssr || !isRealtimeDefinitionModule(rootDir, id)) {
332
+ if (options?.ssr || loadedDefinitionIds.has(id) || !isRealtimeDefinitionModule(rootDir, id, directories)) {
288
333
  return null;
289
334
  }
290
- return createRealtimeClientDefinitionTransform(code);
335
+ return createRealtimeClientDefinitionTransform(code, id.split("?")[0]);
291
336
  }
292
337
  };
293
338
  }
@@ -328,20 +373,28 @@ function hasLoadedConfigFile(loaded, configName) {
328
373
  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`);
329
374
  });
330
375
  }
376
+ async function writeGeneratedFile(path, contents) {
377
+ const { atomicFileInternals } = await import('@holo-js/core');
378
+ await atomicFileInternals.writeTextFile(path, contents);
379
+ }
331
380
  async function ensureModelRegistryTypesPlaceholder(path) {
332
381
  try {
333
382
  await access(path);
334
383
  return;
335
384
  } catch {
336
385
  await mkdir(dirname(path), { recursive: true });
337
- await writeFile(path, "// Generated by holo prepare. Do not edit.\n\nexport {}\n", "utf8");
386
+ await writeGeneratedFile(path, "// Generated by holo prepare. Do not edit.\n\nexport {}\n");
338
387
  }
339
388
  }
389
+ const STORAGE_CREDENTIAL_KEYS = /* @__PURE__ */ new Set(["accessKeyId", "secretAccessKey", "sessionToken"]);
390
+ function withoutStorageCredentials(disk) {
391
+ return Object.fromEntries(Object.entries(disk).filter(([key]) => !STORAGE_CREDENTIAL_KEYS.has(key)));
392
+ }
340
393
  function toStorageModuleOptions(loaded) {
341
394
  return {
342
395
  defaultDisk: loaded.storage.defaultDisk,
343
396
  routePrefix: loaded.storage.routePrefix,
344
- disks: { ...loaded.storage.disks }
397
+ disks: Object.fromEntries(Object.entries(loaded.storage.disks).map(([name, disk]) => [name, withoutStorageCredentials(disk)]))
345
398
  };
346
399
  }
347
400
  function resolveStorageSetup(storageModule, loaded) {
@@ -357,11 +410,8 @@ function resolveStorageSetup(storageModule, loaded) {
357
410
  normalized: storageModule.normalizeModuleOptions(options)
358
411
  };
359
412
  }
360
- function finalizeStorageSetup(storageModule, opts, resolver, s3Driver) {
413
+ function finalizeStorageSetup(storageModule, opts, resolver) {
361
414
  const normalized = storageModule.normalizeModuleOptions(opts._holoStorageModuleOptions);
362
- opts.runtimeConfig = opts.runtimeConfig || {};
363
- opts.runtimeConfig.holoStorage = normalized;
364
- storageModule.applyNitroStorageConfig(opts, normalized, s3Driver);
365
415
  if (storageModule.hasPublicLocalDisk(normalized)) {
366
416
  addServerHandler({
367
417
  route: `${normalized.routePrefix}/**`,
@@ -369,11 +419,6 @@ function finalizeStorageSetup(storageModule, opts, resolver, s3Driver) {
369
419
  });
370
420
  }
371
421
  }
372
- function applyStorageRuntimeConfig(runtimeConfig, normalized) {
373
- if (normalized) {
374
- runtimeConfig.holoStorage = normalized;
375
- }
376
- }
377
422
  async function createServerModelImports(projectRoot, modelsRelativePath, generatedSchemaRelativePath) {
378
423
  const modelsDir = resolve(projectRoot, modelsRelativePath);
379
424
  const generatedSchemaPath = resolve(projectRoot, generatedSchemaRelativePath);
@@ -409,16 +454,16 @@ async function createServerModelImports(projectRoot, modelsRelativePath, generat
409
454
  "export default () => {}"
410
455
  ];
411
456
  await mkdir(modelImportDir, { recursive: true });
412
- await writeFile(modelImportFile, `${lines.join("\n")}
413
- `, "utf8");
414
- await writeFile(modelPluginFile, `${pluginLines.join("\n")}
415
- `, "utf8");
457
+ await writeGeneratedFile(modelImportFile, `${lines.join("\n")}
458
+ `);
459
+ await writeGeneratedFile(modelPluginFile, `${pluginLines.join("\n")}
460
+ `);
416
461
  return {
417
462
  importDir: modelImportDir,
418
463
  pluginFile: modelPluginFile
419
464
  };
420
465
  }
421
- const module$1 = defineNuxtModule({
466
+ const holoNuxtModule = defineNuxtModule({
422
467
  meta: {
423
468
  name: "@holo-js/adapter-nuxt"
424
469
  },
@@ -434,7 +479,6 @@ const module$1 = defineNuxtModule({
434
479
  addViteOptimizeDeps(opts, resolveClientOptimizeDeps(rootDir));
435
480
  const storageModule = await importOptionalStorageModule();
436
481
  const loaded = await loadConfigDirectory(rootDir, {
437
- preferCache: process.env.NODE_ENV === "production",
438
482
  processEnv: process.env
439
483
  });
440
484
  if ((loaded.app.plugins ?? []).includes("@holo-js/panels")) {
@@ -444,9 +488,7 @@ const module$1 = defineNuxtModule({
444
488
  }
445
489
  }
446
490
  const storageSetup = resolveStorageSetup(storageModule, loaded);
447
- const s3Driver = resolver.resolve("./runtime/drivers/s3.js");
448
- opts.nitro = opts.nitro || { storage: {} };
449
- opts.nitro.storage = opts.nitro.storage || {};
491
+ opts.nitro = opts.nitro || {};
450
492
  if (isProjectPackageLinked(rootDir, "@holo-js/core")) {
451
493
  opts.nitro.rollupConfig = {
452
494
  ...opts.nitro.rollupConfig,
@@ -467,11 +509,8 @@ const module$1 = defineNuxtModule({
467
509
  };
468
510
  opts.runtimeConfig.holo = {
469
511
  appUrl: loaded.app.url,
470
- appEnv: loaded.app.env,
471
- appDebug: loaded.app.debug,
472
512
  projectRoot: rootDir
473
513
  };
474
- opts.runtimeConfig.db = loaded.database;
475
514
  const mergedStorageOptions = storageSetup.options;
476
515
  const normalizedStorage = storageSetup.normalized;
477
516
  opts._holoStorageModuleOptions = mergedStorageOptions;
@@ -480,11 +519,10 @@ const module$1 = defineNuxtModule({
480
519
  throw new Error("[@holo-js/adapter-nuxt] S3 storage disks require @holo-js/storage-s3 to be installed.");
481
520
  }
482
521
  }
483
- applyStorageRuntimeConfig(opts.runtimeConfig, normalizedStorage);
484
522
  if (!opts._holoCoreRuntimeRegistered) {
485
523
  if (existsSync(resolve(rootDir, ".holo-js/generated/definition-importer.ts"))) {
486
524
  const initPluginPath = resolve(rootDir, ".holo-js/generated/nuxt-init.ts");
487
- await writeFile(initPluginPath, [
525
+ await writeGeneratedFile(initPluginPath, [
488
526
  `import init from ${JSON.stringify(resolver.resolve("./runtime/plugins/init"))}`,
489
527
  "import { installProjectDefinitionImporter } from './definition-importer'",
490
528
  "",
@@ -492,7 +530,7 @@ const module$1 = defineNuxtModule({
492
530
  "",
493
531
  "export default init",
494
532
  ""
495
- ].join("\n"), "utf8");
533
+ ].join("\n"));
496
534
  addServerPlugin(initPluginPath);
497
535
  } else {
498
536
  addServerPlugin(resolver.resolve("./runtime/plugins/init"));
@@ -511,10 +549,6 @@ const module$1 = defineNuxtModule({
511
549
  }
512
550
  opts._holoCoreRuntimeRegistered = true;
513
551
  }
514
- if (storageModule && !opts._holoStorageRuntimeRegistered) {
515
- addServerPlugin(resolver.resolve("./runtime/plugins/storage"));
516
- opts._holoStorageRuntimeRegistered = true;
517
- }
518
552
  if (hasProjectPackage(rootDir, "@holo-js/broadcast") && !opts._holoBroadcastAuthRouteRegistered) {
519
553
  addServerHandler({
520
554
  route: "/broadcasting/config",
@@ -551,11 +585,12 @@ const module$1 = defineNuxtModule({
551
585
  route: "/holo/realtime/mutation",
552
586
  handler: resolver.resolve("./runtime/server/routes/realtime-mutation.post")
553
587
  });
588
+ opts.nitro.virtual = {
589
+ ...opts.nitro.virtual,
590
+ [realtimeDefinitionsModuleId]: () => renderRealtimeDefinitionsModule(rootDir)
591
+ };
554
592
  opts._holoRealtimeRouteRegistered = true;
555
593
  }
556
- if (storageModule && normalizedStorage && (!opts.nitro.storage || Object.keys(opts.nitro.storage).every((key) => !key.startsWith("holo:")))) {
557
- storageModule.applyNitroStorageConfig(opts, normalizedStorage, s3Driver);
558
- }
559
594
  const runtimePath = resolver.resolve("./runtime");
560
595
  for (const packageName of [runtimePath, "@holo-js/auth"]) {
561
596
  if (!opts.build.transpile.includes(packageName)) {
@@ -565,7 +600,7 @@ const module$1 = defineNuxtModule({
565
600
  if (storageModule && !opts._holoStorageFinalizeRegistered) {
566
601
  opts._holoStorageFinalizeRegistered = true;
567
602
  nuxt.hook("modules:done", () => {
568
- finalizeStorageSetup(storageModule, opts, resolver, s3Driver);
603
+ finalizeStorageSetup(storageModule, opts, resolver);
569
604
  });
570
605
  }
571
606
  if (!opts._holoTypesRegistered) {
@@ -573,12 +608,27 @@ const module$1 = defineNuxtModule({
573
608
  await ensureModelRegistryTypesPlaceholder(authTypesPath);
574
609
  await ensureModelRegistryTypesPlaceholder(authorizationTypesPath);
575
610
  await ensureModelRegistryTypesPlaceholder(modelRegistryTypesPath);
576
- nuxt.hook("prepare:types", ({ references }) => {
577
- references.push({ types: "@holo-js/adapter-nuxt" });
578
- references.push({ path: authTypesPath });
579
- references.push({ path: authorizationTypesPath });
580
- references.push({ path: modelRegistryTypesPath });
581
- for (const path of pluginTypesPaths) references.push({ path });
611
+ const serverTypeReferences = [authTypesPath, authorizationTypesPath, modelRegistryTypesPath, ...pluginTypesPaths].map((path) => ({ path }));
612
+ const serverTypeIncludes = [resolve(rootDir, "config/**/*")];
613
+ nuxt.hook("nitro:prepare:types", ({ references }) => {
614
+ references.push(...serverTypeReferences);
615
+ });
616
+ nuxt.hook("nitro:config", (nitroConfig) => {
617
+ nitroConfig.typescript ??= {};
618
+ nitroConfig.typescript.tsConfig ??= {};
619
+ nitroConfig.typescript.tsConfig.include = [...nitroConfig.typescript.tsConfig.include ?? [], ...serverTypeIncludes];
620
+ });
621
+ nuxt.hook("prepare:types", async ({ references, serverReferences, tsConfig, serverTsConfig }) => {
622
+ references.push({ types: "@holo-js/adapter-nuxt" }, ...serverTypeReferences);
623
+ serverReferences?.push(...serverTypeReferences);
624
+ if (serverTsConfig) serverTsConfig.include = [...serverTsConfig.include ?? [], ...serverTypeIncludes];
625
+ const options = nuxt.options;
626
+ const { projectTsconfigInternals } = await import('@holo-js/core');
627
+ await projectTsconfigInternals.writeNuxtTsconfigSnapshot(
628
+ rootDir,
629
+ options.typesDir || options.buildDir || resolve(rootDir, ".nuxt"),
630
+ { tsConfig, serverTsConfig }
631
+ );
582
632
  });
583
633
  }
584
634
  }
@@ -594,7 +644,6 @@ const moduleInternals = {
594
644
  hasModuleNotFoundCode,
595
645
  hasLoadedConfigFile,
596
646
  importOptionalStorageS3Module,
597
- applyStorageRuntimeConfig,
598
647
  finalizeStorageSetup,
599
648
  resolveStorageSetup,
600
649
  isModuleResolutionFailure,
@@ -603,6 +652,7 @@ const moduleInternals = {
603
652
  isProjectPackageLinked,
604
653
  isRealtimeDefinitionModule,
605
654
  resolveClientOptimizeDeps,
655
+ renderRealtimeDefinitionsModule,
606
656
  resolveExistingRealtimeDefinitionFile,
607
657
  resolveRealtimeDefinitionImport
608
658
  };
@@ -610,4 +660,4 @@ const adapterNuxtInternals = {
610
660
  toStorageModuleOptions
611
661
  };
612
662
 
613
- export { adapterNuxtInternals, module$1 as default, moduleInternals };
663
+ 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,14 +28,19 @@ 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
36
+ export type NuxtRuntime = {
37
+ readonly useEvent: () => NuxtAuthRequestEvent | undefined
38
+ readonly createAuthorizationError: (decision: {
39
+ readonly message?: string
40
+ readonly status: 200 | 403 | 404
41
+ }) => Error
42
+ }
43
+ export declare function configureNuxtRuntime(runtime: NuxtRuntime): void
40
44
  export type NuxtAuthRequestEvent = {
41
45
  readonly headers?: Pick<Headers, 'get'>
42
46
  readonly request?: {
@@ -52,8 +56,10 @@ export type NuxtAuthRequestEvent = {
52
56
  readonly headers?: Readonly<Record<string, string | readonly string[] | undefined>>
53
57
  }
54
58
  readonly res?: {
59
+ statusCode: number
55
60
  getHeader(name: string): number | string | readonly string[] | undefined
56
61
  setHeader(name: string, value: number | string | readonly string[]): void
62
+ end(): void
57
63
  }
58
64
  }
59
65
  }
@@ -1,8 +1,12 @@
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";
8
+ import { getNuxtRuntime } from "../nitro-runtime.js";
9
+ export { configureNuxtRuntime } from "../nitro-runtime.js";
6
10
  export function configureHoloRuntimeConfig(config) {
7
11
  const runtimeGlobals = globalThis;
8
12
  runtimeGlobals.__holoRuntimeConfig = config;
@@ -21,15 +25,9 @@ function getRuntimeConfig() {
21
25
  }
22
26
  return runtimeGlobals.useRuntimeConfig();
23
27
  }
24
- function resolveRuntimeEnvName(env) {
25
- return env;
26
- }
27
28
  function resolveRuntimeProjectRoot(config) {
28
29
  return config.holo.projectRoot?.trim() || process.cwd();
29
30
  }
30
- async function loadNitroContextModule() {
31
- return await import("nitropack/runtime/context");
32
- }
33
31
  export function createNuxtAuthRequestAccessors(requestEvent) {
34
32
  function safeDecode(value) {
35
33
  try {
@@ -39,7 +37,7 @@ export function createNuxtAuthRequestAccessors(requestEvent) {
39
37
  }
40
38
  }
41
39
  async function readHeader(name) {
42
- const event = requestEvent ?? (await loadNitroContextModule()).useEvent();
40
+ const event = requestEvent ?? getNuxtRuntime().useEvent();
43
41
  if (!event) {
44
42
  return void 0;
45
43
  }
@@ -80,11 +78,14 @@ export function createNuxtAuthRequestAccessors(requestEvent) {
80
78
  }
81
79
  return void 0;
82
80
  }
81
+ async function resolveResponse() {
82
+ const event = requestEvent ?? getNuxtRuntime().useEvent();
83
+ return event?.node?.res;
84
+ }
83
85
  async function appendCookie(cookie) {
84
- const event = requestEvent ?? (await loadNitroContextModule()).useEvent();
85
- const response = event?.node?.res;
86
+ const response = await resolveResponse();
86
87
  if (!response) {
87
- return;
88
+ throw createCookieWriteUnavailableError("Authentication cookies cannot be set outside an active Nitro request.");
88
89
  }
89
90
  const current = response.getHeader("set-cookie");
90
91
  if (Array.isArray(current)) {
@@ -103,20 +104,26 @@ export function createNuxtAuthRequestAccessors(requestEvent) {
103
104
  const getHeaderValue = async (name) => {
104
105
  return await readHeader(name);
105
106
  };
107
+ const canAppendResponseCookie = async () => {
108
+ return Boolean(await resolveResponse());
109
+ };
106
110
  const appendResponseCookie = async (cookie) => {
107
111
  await appendCookie(cookie);
108
112
  };
109
113
  const redirectResponse = async (url, status) => {
110
- const event = requestEvent ?? (await loadNitroContextModule()).useEvent();
111
- if (!event) {
114
+ const event = requestEvent ?? getNuxtRuntime().useEvent();
115
+ const response = event?.node?.res;
116
+ if (!response) {
112
117
  throw new TypeError("Holo Nuxt auth redirect requires an active Nitro event.");
113
118
  }
114
- const { sendRedirect } = await import("h3");
115
- await sendRedirect(event, url, status);
119
+ response.statusCode = status ?? 302;
120
+ response.setHeader("location", url);
121
+ response.end();
116
122
  };
117
123
  return {
118
124
  getCookie: getCookieValue,
119
125
  getHeader: getHeaderValue,
126
+ canAppendResponseCookie,
120
127
  appendResponseCookie,
121
128
  redirectResponse
122
129
  };
@@ -131,28 +138,21 @@ export const holo = createHoloProjectAccessors(async () => {
131
138
  const config = getRuntimeConfig();
132
139
  const authRequest = createNuxtAuthRequestAccessors();
133
140
  const project = await initializeHoloAdapterProject(resolveRuntimeProjectRoot(config), {
134
- envName: resolveRuntimeEnvName(config.holo.appEnv),
135
- preferCache: process.env.NODE_ENV === "production",
136
141
  processEnv: process.env,
137
142
  authRequest,
138
143
  authorizationError: {
139
- createError: createNuxtAuthorizationError
144
+ createError: getNuxtRuntime().createAuthorizationError
140
145
  }
141
146
  });
142
147
  const runtimeGlobals = globalThis;
143
148
  runtimeGlobals.__holoNuxtAuthRequestRunner = (accessors, callback) => project.runtime.runWithAuthRequestAccessors(accessors, callback);
144
149
  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
- }
150
+ }, {
151
+ cache: () => resolveProjectAppEnvironmentSync({
152
+ cwd: resolveRuntimeProjectRoot(getRuntimeConfig()),
153
+ processEnv: process.env
154
+ }) === "production"
155
+ });
156
156
  function normalizeConnection(connection) {
157
157
  const driver = connection.driver ?? (connection.filename ? "sqlite" : void 0);
158
158
  const database = connection.database ?? connection.filename;
@@ -171,14 +171,10 @@ function normalizeConnection(connection) {
171
171
  };
172
172
  }
173
173
  export function useHoloDb() {
174
- const config = getRuntimeConfig();
175
- const group = config.db ?? { connections: {} };
174
+ const group = getHolo().loadedConfig.database;
176
175
  const connections = group.connections ?? {};
177
176
  return {
178
- defaultConnection: resolveDefaultConnectionName({
179
- defaultConnection: group.defaultConnection,
180
- connections
181
- }),
177
+ defaultConnection: group.defaultConnection ?? "default",
182
178
  connections: Object.fromEntries(
183
179
  Object.entries(connections).map(([name, connection]) => {
184
180
  if (typeof connection === "string") {
@@ -190,10 +186,8 @@ export function useHoloDb() {
190
186
  };
191
187
  }
192
188
  export function useHoloEnv() {
193
- const config = getRuntimeConfig();
194
- return resolveRuntimeEnvName(config.holo.appEnv);
189
+ return getHolo().loadedConfig.environment.name;
195
190
  }
196
191
  export function useHoloDebug() {
197
- const config = getRuntimeConfig();
198
- return config.holo.appDebug;
192
+ return getHolo().loadedConfig.app.debug;
199
193
  }
@@ -0,0 +1,9 @@
1
+ export function configureNuxtRuntime(runtime) {
2
+ const globals = globalThis;
3
+ globals.__holoNuxtRuntime = runtime;
4
+ }
5
+ export function getNuxtRuntime() {
6
+ const runtime = globalThis.__holoNuxtRuntime;
7
+ if (!runtime) throw new TypeError("Holo Nuxt runtime is not configured.");
8
+ return runtime;
9
+ }
@@ -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,
@@ -1,33 +1,51 @@
1
1
  import {
2
2
  createNuxtAuthRequestAccessors,
3
- configureHoloRuntimeConfig
3
+ configureHoloRuntimeConfig,
4
+ configureNuxtRuntime
4
5
  } from "../composables/index.js";
5
6
  import { createNuxtAuthorizationError } from "../authorization-error.js";
7
+ import { connectionAddress } from "../server/connection-address.js";
6
8
  import { initializeHoloAdapterProject } from "@holo-js/core";
7
- import { useRuntimeConfig } from "nitropack/runtime/config";
8
- import { defineNitroPlugin } from "nitropack/runtime/plugin";
9
+ import { requestUrlInternals } from "@holo-js/kernel";
10
+ import { captureErrorReporter } from "@holo-js/kernel/error-reporting";
11
+ import { defineNitroPlugin, useEvent, useRuntimeConfig } from "#imports";
9
12
  export default defineNitroPlugin((nitroApp) => {
10
13
  const config = useRuntimeConfig();
14
+ configureNuxtRuntime({ useEvent, createAuthorizationError: createNuxtAuthorizationError });
11
15
  configureHoloRuntimeConfig(config);
16
+ requestUrlInternals.provideConnectionAddress(() => connectionAddress(useEvent().node.req.socket));
12
17
  const project = initializeHoloAdapterProject(config.holo.projectRoot?.trim() || process.cwd(), {
13
- envName: config.holo.appEnv,
14
- preferCache: process.env.NODE_ENV === "production",
15
18
  processEnv: process.env,
16
19
  authRequest: createNuxtAuthRequestAccessors(),
17
20
  authorizationError: {
18
21
  createError: createNuxtAuthorizationError
19
22
  }
20
23
  });
24
+ let projectPending = true;
25
+ const markProjectSettled = () => {
26
+ projectPending = false;
27
+ };
28
+ const projectSettled = project.then(markProjectSettled, markProjectSettled);
21
29
  const onRequest = nitroApp.h3App.options.onRequest;
22
30
  nitroApp.h3App.options.onRequest = async (event) => {
23
31
  await project;
24
32
  return await onRequest?.(event);
25
33
  };
26
- nitroApp.hooks.hook("close", async () => {
34
+ const shutdownProject = async () => {
35
+ let report;
27
36
  try {
28
- await (await project).runtime.shutdown();
29
- } catch {
37
+ const { runtime } = await project;
38
+ report = captureErrorReporter();
39
+ await runtime.shutdown();
40
+ } catch (error) {
41
+ (report ?? captureErrorReporter())(error, { capability: "nuxt", operation: "shutdown" });
42
+ }
43
+ };
44
+ nitroApp.hooks.hook("close", async () => {
45
+ if (projectPending) {
46
+ void projectSettled.then(shutdownProject);
30
47
  return;
31
48
  }
49
+ await shutdownProject();
32
50
  });
33
51
  });
@@ -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.28",
3
+ "version": "0.4.1",
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.28",
42
- "@nuxt/kit": "^4.4.4",
43
- "@holo-js/config": "^0.3.28",
44
- "@holo-js/core": "^0.3.28",
45
- "@holo-js/db": "^0.3.28",
46
- "@holo-js/validation": "^0.3.28",
47
- "h3": "^1.15.11",
48
- "nitropack": "^2.13.4"
47
+ "@holo-js/adapter-shared": "^0.4.1",
48
+ "@nuxt/kit": "^4.6.2",
49
+ "@holo-js/config": "^0.4.1",
50
+ "@holo-js/core": "^0.4.1",
51
+ "@holo-js/db": "^0.4.1",
52
+ "@holo-js/kernel": "^0.4.1",
53
+ "@holo-js/validation": "^0.4.1"
49
54
  },
50
55
  "peerDependencies": {
56
+ "nuxt": "^4.6.2",
51
57
  "vue": "^3.5.13",
52
- "@holo-js/broadcast": "^0.3.28",
53
- "@holo-js/forms": "^0.3.28",
54
- "@holo-js/realtime": "^0.3.28",
55
- "@holo-js/storage": "^0.3.28",
56
- "@holo-js/storage-s3": "^0.3.28"
58
+ "@holo-js/broadcast": "^0.4.1",
59
+ "@holo-js/forms": "^0.4.1",
60
+ "@holo-js/realtime": "^0.4.1",
61
+ "@holo-js/storage": "^0.4.1",
62
+ "@holo-js/storage-s3": "^0.4.1"
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.28",
78
- "@holo-js/realtime": "^0.3.28",
79
- "@holo-js/storage-s3": "^0.3.28",
83
+ "@holo-js/broadcast": "^0.4.1",
84
+ "@holo-js/realtime": "^0.4.1",
85
+ "@holo-js/storage-s3": "^0.4.1",
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
- });
@@ -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
- }