@holo-js/adapter-nuxt 0.3.28 → 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.28",
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,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`,
@@ -230,10 +232,10 @@ function addViteOptimizeDeps(opts, deps) {
230
232
  ])
231
233
  ];
232
234
  }
233
- function isRealtimeDefinitionModule(_rootDir, id) {
235
+ function isRealtimeDefinitionModule(rootDir, id, directories = resolveRealtimeDefinitionDirectories(rootDir)) {
234
236
  const [sourcePath = ""] = id.split("?");
235
237
  const normalizedId = sourcePath.replaceAll("\\", "/");
236
- 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));
237
239
  }
238
240
  function resolveExistingRealtimeDefinitionFile(path) {
239
241
  if (MODEL_FILE_EXTENSIONS.has(extname(path)) && existsFile(path)) {
@@ -261,10 +263,39 @@ function resolveRealtimeDefinitionImport(source, importer) {
261
263
  const basePath = source.startsWith(".") ? importer ? resolve(dirname(importer.split("?")[0]), source) : void 0 : resolve(source);
262
264
  return basePath ? resolveExistingRealtimeDefinitionFile(basePath) : void 0;
263
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
+ }
264
284
  function createRealtimeDefinitionVitePlugin(rootDir) {
285
+ const directories = resolveRealtimeDefinitionDirectories(rootDir);
286
+ let realtimeTreeChanged = false;
287
+ const loadedDefinitionIds = /* @__PURE__ */ new Set();
265
288
  return {
266
289
  name: "holo-realtime-client-definitions",
267
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
+ },
268
299
  resolveId(source, importer, options) {
269
300
  if (options?.ssr) {
270
301
  return null;
@@ -272,22 +303,32 @@ function createRealtimeDefinitionVitePlugin(rootDir) {
272
303
  const resolved = resolveRealtimeDefinitionImport(source, importer);
273
304
  return resolved ? `${realtimeClientDefinitionPrefix}${resolved}` : null;
274
305
  },
275
- load(id) {
276
- 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)) {
277
317
  return null;
278
318
  }
279
- const sourcePath = id.slice(realtimeClientDefinitionPrefix.length);
280
- return createRealtimeClientDefinitionModule(readFileSync(sourcePath, "utf8"));
319
+ const sourcePath = id.split("?")[0];
320
+ loadedDefinitionIds.add(id);
321
+ return createRealtimeClientDefinitionModule(readFileSync(sourcePath, "utf8"), sourcePath);
281
322
  },
282
323
  transform(code, id, options) {
283
324
  if (!options?.ssr && !id.includes("node_modules") && /\.[cm]?[jt]sx?$/.test(id)) {
284
325
  const compiled = compileBrowserValidation(code, id);
285
326
  if (compiled) return { code: compiled, map: null };
286
327
  }
287
- if (options?.ssr || !isRealtimeDefinitionModule(rootDir, id)) {
328
+ if (options?.ssr || loadedDefinitionIds.has(id) || !isRealtimeDefinitionModule(rootDir, id, directories)) {
288
329
  return null;
289
330
  }
290
- return createRealtimeClientDefinitionTransform(code);
331
+ return createRealtimeClientDefinitionTransform(code, id.split("?")[0]);
291
332
  }
292
333
  };
293
334
  }
@@ -328,20 +369,28 @@ function hasLoadedConfigFile(loaded, configName) {
328
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`);
329
370
  });
330
371
  }
372
+ async function writeGeneratedFile(path, contents) {
373
+ const { atomicFileInternals } = await import('@holo-js/core');
374
+ await atomicFileInternals.writeTextFile(path, contents);
375
+ }
331
376
  async function ensureModelRegistryTypesPlaceholder(path) {
332
377
  try {
333
378
  await access(path);
334
379
  return;
335
380
  } catch {
336
381
  await mkdir(dirname(path), { recursive: true });
337
- 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");
338
383
  }
339
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
+ }
340
389
  function toStorageModuleOptions(loaded) {
341
390
  return {
342
391
  defaultDisk: loaded.storage.defaultDisk,
343
392
  routePrefix: loaded.storage.routePrefix,
344
- disks: { ...loaded.storage.disks }
393
+ disks: Object.fromEntries(Object.entries(loaded.storage.disks).map(([name, disk]) => [name, withoutStorageCredentials(disk)]))
345
394
  };
346
395
  }
347
396
  function resolveStorageSetup(storageModule, loaded) {
@@ -357,11 +406,8 @@ function resolveStorageSetup(storageModule, loaded) {
357
406
  normalized: storageModule.normalizeModuleOptions(options)
358
407
  };
359
408
  }
360
- function finalizeStorageSetup(storageModule, opts, resolver, s3Driver) {
409
+ function finalizeStorageSetup(storageModule, opts, resolver) {
361
410
  const normalized = storageModule.normalizeModuleOptions(opts._holoStorageModuleOptions);
362
- opts.runtimeConfig = opts.runtimeConfig || {};
363
- opts.runtimeConfig.holoStorage = normalized;
364
- storageModule.applyNitroStorageConfig(opts, normalized, s3Driver);
365
411
  if (storageModule.hasPublicLocalDisk(normalized)) {
366
412
  addServerHandler({
367
413
  route: `${normalized.routePrefix}/**`,
@@ -369,11 +415,6 @@ function finalizeStorageSetup(storageModule, opts, resolver, s3Driver) {
369
415
  });
370
416
  }
371
417
  }
372
- function applyStorageRuntimeConfig(runtimeConfig, normalized) {
373
- if (normalized) {
374
- runtimeConfig.holoStorage = normalized;
375
- }
376
- }
377
418
  async function createServerModelImports(projectRoot, modelsRelativePath, generatedSchemaRelativePath) {
378
419
  const modelsDir = resolve(projectRoot, modelsRelativePath);
379
420
  const generatedSchemaPath = resolve(projectRoot, generatedSchemaRelativePath);
@@ -409,16 +450,16 @@ async function createServerModelImports(projectRoot, modelsRelativePath, generat
409
450
  "export default () => {}"
410
451
  ];
411
452
  await mkdir(modelImportDir, { recursive: true });
412
- await writeFile(modelImportFile, `${lines.join("\n")}
413
- `, "utf8");
414
- await writeFile(modelPluginFile, `${pluginLines.join("\n")}
415
- `, "utf8");
453
+ await writeGeneratedFile(modelImportFile, `${lines.join("\n")}
454
+ `);
455
+ await writeGeneratedFile(modelPluginFile, `${pluginLines.join("\n")}
456
+ `);
416
457
  return {
417
458
  importDir: modelImportDir,
418
459
  pluginFile: modelPluginFile
419
460
  };
420
461
  }
421
- const module$1 = defineNuxtModule({
462
+ const holoNuxtModule = defineNuxtModule({
422
463
  meta: {
423
464
  name: "@holo-js/adapter-nuxt"
424
465
  },
@@ -434,7 +475,6 @@ const module$1 = defineNuxtModule({
434
475
  addViteOptimizeDeps(opts, resolveClientOptimizeDeps(rootDir));
435
476
  const storageModule = await importOptionalStorageModule();
436
477
  const loaded = await loadConfigDirectory(rootDir, {
437
- preferCache: process.env.NODE_ENV === "production",
438
478
  processEnv: process.env
439
479
  });
440
480
  if ((loaded.app.plugins ?? []).includes("@holo-js/panels")) {
@@ -444,9 +484,7 @@ const module$1 = defineNuxtModule({
444
484
  }
445
485
  }
446
486
  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 || {};
487
+ opts.nitro = opts.nitro || {};
450
488
  if (isProjectPackageLinked(rootDir, "@holo-js/core")) {
451
489
  opts.nitro.rollupConfig = {
452
490
  ...opts.nitro.rollupConfig,
@@ -467,11 +505,8 @@ const module$1 = defineNuxtModule({
467
505
  };
468
506
  opts.runtimeConfig.holo = {
469
507
  appUrl: loaded.app.url,
470
- appEnv: loaded.app.env,
471
- appDebug: loaded.app.debug,
472
508
  projectRoot: rootDir
473
509
  };
474
- opts.runtimeConfig.db = loaded.database;
475
510
  const mergedStorageOptions = storageSetup.options;
476
511
  const normalizedStorage = storageSetup.normalized;
477
512
  opts._holoStorageModuleOptions = mergedStorageOptions;
@@ -480,11 +515,10 @@ const module$1 = defineNuxtModule({
480
515
  throw new Error("[@holo-js/adapter-nuxt] S3 storage disks require @holo-js/storage-s3 to be installed.");
481
516
  }
482
517
  }
483
- applyStorageRuntimeConfig(opts.runtimeConfig, normalizedStorage);
484
518
  if (!opts._holoCoreRuntimeRegistered) {
485
519
  if (existsSync(resolve(rootDir, ".holo-js/generated/definition-importer.ts"))) {
486
520
  const initPluginPath = resolve(rootDir, ".holo-js/generated/nuxt-init.ts");
487
- await writeFile(initPluginPath, [
521
+ await writeGeneratedFile(initPluginPath, [
488
522
  `import init from ${JSON.stringify(resolver.resolve("./runtime/plugins/init"))}`,
489
523
  "import { installProjectDefinitionImporter } from './definition-importer'",
490
524
  "",
@@ -492,7 +526,7 @@ const module$1 = defineNuxtModule({
492
526
  "",
493
527
  "export default init",
494
528
  ""
495
- ].join("\n"), "utf8");
529
+ ].join("\n"));
496
530
  addServerPlugin(initPluginPath);
497
531
  } else {
498
532
  addServerPlugin(resolver.resolve("./runtime/plugins/init"));
@@ -511,10 +545,6 @@ const module$1 = defineNuxtModule({
511
545
  }
512
546
  opts._holoCoreRuntimeRegistered = true;
513
547
  }
514
- if (storageModule && !opts._holoStorageRuntimeRegistered) {
515
- addServerPlugin(resolver.resolve("./runtime/plugins/storage"));
516
- opts._holoStorageRuntimeRegistered = true;
517
- }
518
548
  if (hasProjectPackage(rootDir, "@holo-js/broadcast") && !opts._holoBroadcastAuthRouteRegistered) {
519
549
  addServerHandler({
520
550
  route: "/broadcasting/config",
@@ -551,11 +581,12 @@ const module$1 = defineNuxtModule({
551
581
  route: "/holo/realtime/mutation",
552
582
  handler: resolver.resolve("./runtime/server/routes/realtime-mutation.post")
553
583
  });
584
+ opts.nitro.virtual = {
585
+ ...opts.nitro.virtual,
586
+ [realtimeDefinitionsModuleId]: () => renderRealtimeDefinitionsModule(rootDir)
587
+ };
554
588
  opts._holoRealtimeRouteRegistered = true;
555
589
  }
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
590
  const runtimePath = resolver.resolve("./runtime");
560
591
  for (const packageName of [runtimePath, "@holo-js/auth"]) {
561
592
  if (!opts.build.transpile.includes(packageName)) {
@@ -565,7 +596,7 @@ const module$1 = defineNuxtModule({
565
596
  if (storageModule && !opts._holoStorageFinalizeRegistered) {
566
597
  opts._holoStorageFinalizeRegistered = true;
567
598
  nuxt.hook("modules:done", () => {
568
- finalizeStorageSetup(storageModule, opts, resolver, s3Driver);
599
+ finalizeStorageSetup(storageModule, opts, resolver);
569
600
  });
570
601
  }
571
602
  if (!opts._holoTypesRegistered) {
@@ -573,12 +604,27 @@ const module$1 = defineNuxtModule({
573
604
  await ensureModelRegistryTypesPlaceholder(authTypesPath);
574
605
  await ensureModelRegistryTypesPlaceholder(authorizationTypesPath);
575
606
  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 });
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
+ );
582
628
  });
583
629
  }
584
630
  }
@@ -594,7 +640,6 @@ const moduleInternals = {
594
640
  hasModuleNotFoundCode,
595
641
  hasLoadedConfigFile,
596
642
  importOptionalStorageS3Module,
597
- applyStorageRuntimeConfig,
598
643
  finalizeStorageSetup,
599
644
  resolveStorageSetup,
600
645
  isModuleResolutionFailure,
@@ -603,6 +648,7 @@ const moduleInternals = {
603
648
  isProjectPackageLinked,
604
649
  isRealtimeDefinitionModule,
605
650
  resolveClientOptimizeDeps,
651
+ renderRealtimeDefinitionsModule,
606
652
  resolveExistingRealtimeDefinitionFile,
607
653
  resolveRealtimeDefinitionImport
608
654
  };
@@ -610,4 +656,4 @@ const adapterNuxtInternals = {
610
656
  toStorageModuleOptions
611
657
  };
612
658
 
613
- 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.28",
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.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.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.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.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.28",
78
- "@holo-js/realtime": "^0.3.28",
79
- "@holo-js/storage-s3": "^0.3.28",
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
- }