@holo-js/adapter-nuxt 0.3.16 → 0.3.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.d.mts +1 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +7 -7
- package/dist/runtime/composables/index.d.ts +11 -0
- package/dist/runtime/composables/index.js +3 -6
- package/dist/runtime/server/routes/storage.js +8 -0
- package/package.json +14 -14
- package/dist/runtime/server/routes/storage.get.js +0 -220
- /package/dist/runtime/server/routes/{storage.get.d.ts → storage.d.ts} +0 -0
package/dist/module.d.mts
CHANGED
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -364,7 +364,7 @@ function finalizeStorageSetup(storageModule, opts, resolver, s3Driver) {
|
|
|
364
364
|
if (storageModule.hasPublicLocalDisk(normalized)) {
|
|
365
365
|
addServerHandler({
|
|
366
366
|
route: `${normalized.routePrefix}/**`,
|
|
367
|
-
handler: resolver.resolve("./runtime/server/routes/storage
|
|
367
|
+
handler: resolver.resolve("./runtime/server/routes/storage")
|
|
368
368
|
});
|
|
369
369
|
}
|
|
370
370
|
}
|
|
@@ -373,10 +373,10 @@ function applyStorageRuntimeConfig(runtimeConfig, normalized) {
|
|
|
373
373
|
runtimeConfig.holoStorage = normalized;
|
|
374
374
|
}
|
|
375
375
|
}
|
|
376
|
-
async function createServerModelImports(
|
|
377
|
-
const modelsDir = resolve(
|
|
378
|
-
const generatedSchemaPath = resolve(
|
|
379
|
-
const modelImportDir = resolve(
|
|
376
|
+
async function createServerModelImports(projectRoot, modelsRelativePath, generatedSchemaRelativePath) {
|
|
377
|
+
const modelsDir = resolve(projectRoot, modelsRelativePath);
|
|
378
|
+
const generatedSchemaPath = resolve(projectRoot, generatedSchemaRelativePath);
|
|
379
|
+
const modelImportDir = resolve(projectRoot, ".holo-js/generated/nuxt-server-imports");
|
|
380
380
|
const modelImportFile = resolve(modelImportDir, "models.ts");
|
|
381
381
|
const modelPluginFile = resolve(modelImportDir, "plugin.ts");
|
|
382
382
|
let modelFiles;
|
|
@@ -426,7 +426,6 @@ const module$1 = defineNuxtModule({
|
|
|
426
426
|
const resolver = createResolver(import.meta.url);
|
|
427
427
|
const opts = nuxt.options;
|
|
428
428
|
const rootDir = opts.rootDir ?? opts.srcDir ?? process.cwd();
|
|
429
|
-
const sourceDir = opts.srcDir ?? rootDir;
|
|
430
429
|
const authTypesPath = resolve(rootDir, ".holo-js/generated/auth.d.ts");
|
|
431
430
|
const authorizationTypesPath = resolve(rootDir, ".holo-js/generated/authorization/types.d.ts");
|
|
432
431
|
const modelRegistryTypesPath = resolve(rootDir, ".holo-js/generated/model-registry.d.ts");
|
|
@@ -486,13 +485,14 @@ const module$1 = defineNuxtModule({
|
|
|
486
485
|
addServerPlugin(resolver.resolve("./runtime/plugins/forms"));
|
|
487
486
|
addServerImportsDir(resolver.resolve("./runtime/server/auto-imports"));
|
|
488
487
|
const serverModelImports = await createServerModelImports(
|
|
489
|
-
|
|
488
|
+
rootDir,
|
|
490
489
|
loaded.app.paths.models,
|
|
491
490
|
loaded.app.paths.generatedSchema
|
|
492
491
|
);
|
|
493
492
|
if (serverModelImports) {
|
|
494
493
|
addServerImportsDir(serverModelImports.importDir);
|
|
495
494
|
addServerPlugin(serverModelImports.pluginFile);
|
|
495
|
+
opts.nitro.moduleSideEffects = [.../* @__PURE__ */ new Set([...opts.nitro.moduleSideEffects ?? [], resolve(rootDir, loaded.app.paths.generatedSchema)])];
|
|
496
496
|
}
|
|
497
497
|
opts._holoCoreRuntimeRegistered = true;
|
|
498
498
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { HoloAdapterProjectAccessors } from '@holo-js/core'
|
|
2
|
+
import type { RuntimeDatabaseConfig } from '@holo-js/db'
|
|
2
3
|
|
|
3
4
|
export interface HoloRuntimeConnection {
|
|
4
5
|
driver?: 'sqlite' | 'postgres' | 'mysql'
|
|
@@ -26,6 +27,16 @@ export interface HoloRuntimeDefaultConnection extends HoloRuntimeConnection {
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export declare const holo: HoloAdapterProjectAccessors
|
|
30
|
+
export declare function configureHoloRuntimeConfig(config: {
|
|
31
|
+
holo: {
|
|
32
|
+
appEnv: 'production' | 'development' | 'test'
|
|
33
|
+
appDebug: boolean
|
|
34
|
+
appUrl?: string
|
|
35
|
+
projectRoot?: string
|
|
36
|
+
}
|
|
37
|
+
db?: RuntimeDatabaseConfig
|
|
38
|
+
}): void
|
|
39
|
+
export declare function resetHoloRuntimeConfig(): void
|
|
29
40
|
export type NuxtAuthRequestEvent = {
|
|
30
41
|
readonly headers?: Pick<Headers, 'get'>
|
|
31
42
|
readonly request?: {
|
|
@@ -39,8 +39,7 @@ export function createNuxtAuthRequestAccessors(requestEvent) {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
async function readHeader(name) {
|
|
42
|
-
const
|
|
43
|
-
const event = requestEvent ?? nitroContext.useEvent();
|
|
42
|
+
const event = requestEvent ?? (await loadNitroContextModule()).useEvent();
|
|
44
43
|
if (!event) {
|
|
45
44
|
return void 0;
|
|
46
45
|
}
|
|
@@ -82,8 +81,7 @@ export function createNuxtAuthRequestAccessors(requestEvent) {
|
|
|
82
81
|
return void 0;
|
|
83
82
|
}
|
|
84
83
|
async function appendCookie(cookie) {
|
|
85
|
-
const
|
|
86
|
-
const event = requestEvent ?? nitroContext.useEvent();
|
|
84
|
+
const event = requestEvent ?? (await loadNitroContextModule()).useEvent();
|
|
87
85
|
const response = event?.node?.res;
|
|
88
86
|
if (!response) {
|
|
89
87
|
return;
|
|
@@ -109,8 +107,7 @@ export function createNuxtAuthRequestAccessors(requestEvent) {
|
|
|
109
107
|
await appendCookie(cookie);
|
|
110
108
|
};
|
|
111
109
|
const redirectResponse = async (url, status) => {
|
|
112
|
-
const
|
|
113
|
-
const event = requestEvent ?? nitroContext.useEvent();
|
|
110
|
+
const event = requestEvent ?? (await loadNitroContextModule()).useEvent();
|
|
114
111
|
if (!event) {
|
|
115
112
|
throw new TypeError("Holo Nuxt auth redirect requires an active Nitro event.");
|
|
116
113
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createPublicStorageResponse } from "@holo-js/storage";
|
|
2
|
+
import { defineEventHandler, sendWebResponse, toWebRequest } from "h3";
|
|
3
|
+
import { holo } from "../../composables/index.js";
|
|
4
|
+
export default defineEventHandler(async (event) => {
|
|
5
|
+
const app = await holo.getApp();
|
|
6
|
+
const response = await createPublicStorageResponse(app.projectRoot, app.config.storage, toWebRequest(event), app.config.app.key);
|
|
7
|
+
return sendWebResponse(event, response);
|
|
8
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holo-js/adapter-nuxt",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.18",
|
|
4
4
|
"description": "Holo-JS Framework - Nuxt adapter",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,21 +38,21 @@
|
|
|
38
38
|
"test": "vitest --run"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@holo-js/adapter-shared": "^0.3.
|
|
41
|
+
"@holo-js/adapter-shared": "^0.3.18",
|
|
42
42
|
"@nuxt/kit": "^4.4.4",
|
|
43
|
-
"@holo-js/config": "^0.3.
|
|
44
|
-
"@holo-js/core": "^0.3.
|
|
45
|
-
"@holo-js/db": "^0.3.
|
|
46
|
-
"@holo-js/validation": "^0.3.
|
|
43
|
+
"@holo-js/config": "^0.3.18",
|
|
44
|
+
"@holo-js/core": "^0.3.18",
|
|
45
|
+
"@holo-js/db": "^0.3.18",
|
|
46
|
+
"@holo-js/validation": "^0.3.18",
|
|
47
47
|
"h3": "^1.15.11",
|
|
48
48
|
"nitropack": "^2.13.4"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"@holo-js/broadcast": "^0.3.
|
|
52
|
-
"@holo-js/forms": "^0.3.
|
|
53
|
-
"@holo-js/realtime": "^0.3.
|
|
54
|
-
"@holo-js/storage": "^0.3.
|
|
55
|
-
"@holo-js/storage-s3": "^0.3.
|
|
51
|
+
"@holo-js/broadcast": "^0.3.18",
|
|
52
|
+
"@holo-js/forms": "^0.3.18",
|
|
53
|
+
"@holo-js/realtime": "^0.3.18",
|
|
54
|
+
"@holo-js/storage": "^0.3.18",
|
|
55
|
+
"@holo-js/storage-s3": "^0.3.18"
|
|
56
56
|
},
|
|
57
57
|
"peerDependenciesMeta": {
|
|
58
58
|
"@holo-js/broadcast": {
|
|
@@ -72,9 +72,9 @@
|
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@holo-js/broadcast": "^0.3.
|
|
76
|
-
"@holo-js/realtime": "^0.3.
|
|
77
|
-
"@holo-js/storage-s3": "^0.3.
|
|
75
|
+
"@holo-js/broadcast": "^0.3.18",
|
|
76
|
+
"@holo-js/realtime": "^0.3.18",
|
|
77
|
+
"@holo-js/storage-s3": "^0.3.18",
|
|
78
78
|
"@nuxt/module-builder": "^1.0.2",
|
|
79
79
|
"@types/node": "^22.10.2",
|
|
80
80
|
"nuxt": "^4.4.4",
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
import { open, realpath, stat } from "node:fs/promises";
|
|
2
|
-
import { extname, resolve, sep } from "node:path";
|
|
3
|
-
import { createError, defineEventHandler, getRequestURL, setResponseHeader } from "h3";
|
|
4
|
-
import { useRuntimeConfig } from "#imports";
|
|
5
|
-
const NAMED_PUBLIC_DISK_ROUTE_SEGMENT = "__holo";
|
|
6
|
-
function normalizeRequestPath(value) {
|
|
7
|
-
return value.split("/").map((segment) => {
|
|
8
|
-
const trimmed = segment.trim();
|
|
9
|
-
if (!trimmed) {
|
|
10
|
-
return trimmed;
|
|
11
|
-
}
|
|
12
|
-
try {
|
|
13
|
-
return decodeURIComponent(trimmed);
|
|
14
|
-
} catch {
|
|
15
|
-
return trimmed;
|
|
16
|
-
}
|
|
17
|
-
}).filter(Boolean);
|
|
18
|
-
}
|
|
19
|
-
function isPublicLocalDisk(disk) {
|
|
20
|
-
return Boolean(disk && disk.visibility === "public" && disk.driver !== "s3" && typeof disk.root === "string");
|
|
21
|
-
}
|
|
22
|
-
function isMissingFileError(error) {
|
|
23
|
-
const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
24
|
-
return Boolean(
|
|
25
|
-
error && typeof error === "object" && (code === "ENOENT" || code === "EISDIR" || code === "ENOTDIR")
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
function resolveAbsolutePath(disk, fileSegments) {
|
|
29
|
-
const root = resolve(disk.root);
|
|
30
|
-
const absolutePath = resolve(root, ...fileSegments);
|
|
31
|
-
if (absolutePath !== root && !absolutePath.startsWith(`${root}${sep}`)) {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
return absolutePath;
|
|
35
|
-
}
|
|
36
|
-
function resolveContentType(absolutePath) {
|
|
37
|
-
switch (extname(absolutePath).toLowerCase()) {
|
|
38
|
-
case ".avif":
|
|
39
|
-
return "image/avif";
|
|
40
|
-
case ".css":
|
|
41
|
-
return "text/css; charset=utf-8";
|
|
42
|
-
case ".gif":
|
|
43
|
-
return "image/gif";
|
|
44
|
-
case ".jpeg":
|
|
45
|
-
case ".jpg":
|
|
46
|
-
return "image/jpeg";
|
|
47
|
-
case ".json":
|
|
48
|
-
return "application/json; charset=utf-8";
|
|
49
|
-
case ".mp3":
|
|
50
|
-
return "audio/mpeg";
|
|
51
|
-
case ".pdf":
|
|
52
|
-
return "application/pdf";
|
|
53
|
-
case ".png":
|
|
54
|
-
return "image/png";
|
|
55
|
-
case ".txt":
|
|
56
|
-
return "text/plain; charset=utf-8";
|
|
57
|
-
case ".webp":
|
|
58
|
-
return "image/webp";
|
|
59
|
-
case ".woff":
|
|
60
|
-
return "font/woff";
|
|
61
|
-
case ".woff2":
|
|
62
|
-
return "font/woff2";
|
|
63
|
-
default:
|
|
64
|
-
return "application/octet-stream";
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function isActiveContentPath(absolutePath) {
|
|
68
|
-
switch (extname(absolutePath).toLowerCase()) {
|
|
69
|
-
case ".html":
|
|
70
|
-
case ".js":
|
|
71
|
-
case ".mjs":
|
|
72
|
-
case ".svg":
|
|
73
|
-
return true;
|
|
74
|
-
default:
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
function setStorageResponseHeaders(event, absolutePath) {
|
|
79
|
-
if (isActiveContentPath(absolutePath)) {
|
|
80
|
-
setResponseHeader(event, "content-disposition", "attachment");
|
|
81
|
-
setResponseHeader(event, "content-type", "application/octet-stream");
|
|
82
|
-
setResponseHeader(event, "x-content-type-options", "nosniff");
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
setResponseHeader(event, "content-type", resolveContentType(absolutePath));
|
|
86
|
-
setResponseHeader(event, "x-content-type-options", "nosniff");
|
|
87
|
-
}
|
|
88
|
-
function createMissingFileError(message) {
|
|
89
|
-
const error = new Error(message);
|
|
90
|
-
error.code = "ENOENT";
|
|
91
|
-
return error;
|
|
92
|
-
}
|
|
93
|
-
function isPathWithinRoot(root, absolutePath) {
|
|
94
|
-
return absolutePath === root || absolutePath.startsWith(`${root}${sep}`);
|
|
95
|
-
}
|
|
96
|
-
function isSameFile(left, right) {
|
|
97
|
-
return left.dev === right.dev && left.ino === right.ino;
|
|
98
|
-
}
|
|
99
|
-
async function readPublicFile(event, disk, absolutePath) {
|
|
100
|
-
const resolvedRoot = await realpath(resolve(disk.root));
|
|
101
|
-
const file = await open(absolutePath, "r");
|
|
102
|
-
try {
|
|
103
|
-
const openedFile = await file.stat();
|
|
104
|
-
const resolvedPath = await realpath(absolutePath);
|
|
105
|
-
if (!isPathWithinRoot(resolvedRoot, resolvedPath)) {
|
|
106
|
-
throw createMissingFileError("Storage file not found.");
|
|
107
|
-
}
|
|
108
|
-
const resolvedFile = await stat(resolvedPath);
|
|
109
|
-
if (!isSameFile(openedFile, resolvedFile)) {
|
|
110
|
-
throw createMissingFileError("Storage file not found.");
|
|
111
|
-
}
|
|
112
|
-
const contents = await file.readFile();
|
|
113
|
-
setStorageResponseHeaders(event, absolutePath);
|
|
114
|
-
return contents;
|
|
115
|
-
} finally {
|
|
116
|
-
await file.close();
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
function resolveRouteSegments(routePath) {
|
|
120
|
-
const segments = normalizeRequestPath(routePath);
|
|
121
|
-
if (segments.length === 0 || segments.includes("..")) {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
return segments;
|
|
125
|
-
}
|
|
126
|
-
function resolveDefaultPublicStorageRequest(config, segments) {
|
|
127
|
-
const disk = isPublicLocalDisk(config.disks.public) ? config.disks.public : void 0;
|
|
128
|
-
if (!disk) {
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
const absolutePath = resolveAbsolutePath(disk, segments);
|
|
132
|
-
if (!absolutePath) {
|
|
133
|
-
return null;
|
|
134
|
-
}
|
|
135
|
-
return { disk, absolutePath };
|
|
136
|
-
}
|
|
137
|
-
function usesReservedNamedDiskNamespace(segments) {
|
|
138
|
-
return segments[0] === NAMED_PUBLIC_DISK_ROUTE_SEGMENT;
|
|
139
|
-
}
|
|
140
|
-
function resolveNamedPublicStorageRequest(config, segments) {
|
|
141
|
-
const namedPublicDisks = Object.values(config.disks).filter((disk2) => {
|
|
142
|
-
return isPublicLocalDisk(disk2) && disk2.name !== "public";
|
|
143
|
-
});
|
|
144
|
-
const usesReservedNamespace = segments[0] === NAMED_PUBLIC_DISK_ROUTE_SEGMENT;
|
|
145
|
-
const diskName = usesReservedNamespace ? segments[1] : segments[0];
|
|
146
|
-
const disk = diskName ? namedPublicDisks.find((candidate) => candidate.name === diskName) : void 0;
|
|
147
|
-
if (!disk) {
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
const fileSegments = usesReservedNamespace ? segments.slice(2) : segments.slice(1);
|
|
151
|
-
if (fileSegments.length === 0) {
|
|
152
|
-
return null;
|
|
153
|
-
}
|
|
154
|
-
const absolutePath = resolveAbsolutePath(disk, fileSegments);
|
|
155
|
-
if (!absolutePath) {
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
return { disk, absolutePath };
|
|
159
|
-
}
|
|
160
|
-
export function resolvePublicStorageRequest(config, routePath) {
|
|
161
|
-
const segments = resolveRouteSegments(routePath);
|
|
162
|
-
if (!segments) {
|
|
163
|
-
return null;
|
|
164
|
-
}
|
|
165
|
-
if (usesReservedNamedDiskNamespace(segments)) {
|
|
166
|
-
return resolveNamedPublicStorageRequest(config, segments) ?? resolveDefaultPublicStorageRequest(config, segments);
|
|
167
|
-
}
|
|
168
|
-
return resolveDefaultPublicStorageRequest(config, segments) ?? resolveNamedPublicStorageRequest(config, segments);
|
|
169
|
-
}
|
|
170
|
-
function resolveFallbackPublicStorageRequest(config, segments, attemptedDiskName) {
|
|
171
|
-
if (usesReservedNamedDiskNamespace(segments)) {
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
const candidates = [
|
|
175
|
-
resolveDefaultPublicStorageRequest(config, segments),
|
|
176
|
-
resolveNamedPublicStorageRequest(config, segments)
|
|
177
|
-
];
|
|
178
|
-
return candidates.find((candidate) => candidate && candidate.disk.name !== attemptedDiskName) ?? null;
|
|
179
|
-
}
|
|
180
|
-
export default defineEventHandler(async (event) => {
|
|
181
|
-
const runtimeConfig = useRuntimeConfig();
|
|
182
|
-
const { holoStorage } = runtimeConfig;
|
|
183
|
-
const pathname = getRequestURL(event).pathname;
|
|
184
|
-
const routePath = pathname.startsWith(holoStorage.routePrefix) ? pathname.slice(holoStorage.routePrefix.length) : pathname;
|
|
185
|
-
const segments = resolveRouteSegments(routePath);
|
|
186
|
-
if (!segments) {
|
|
187
|
-
throw createError({
|
|
188
|
-
statusCode: 404,
|
|
189
|
-
statusMessage: "Storage file not found."
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
const resolved = resolvePublicStorageRequest(holoStorage, routePath);
|
|
193
|
-
if (!resolved) {
|
|
194
|
-
throw createError({
|
|
195
|
-
statusCode: 404,
|
|
196
|
-
statusMessage: "Storage file not found."
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
try {
|
|
200
|
-
return await readPublicFile(event, resolved.disk, resolved.absolutePath);
|
|
201
|
-
} catch (error) {
|
|
202
|
-
if (!isMissingFileError(error)) {
|
|
203
|
-
throw error;
|
|
204
|
-
}
|
|
205
|
-
const fallback = resolveFallbackPublicStorageRequest(holoStorage, segments, resolved.disk.name);
|
|
206
|
-
if (fallback) {
|
|
207
|
-
try {
|
|
208
|
-
return await readPublicFile(event, fallback.disk, fallback.absolutePath);
|
|
209
|
-
} catch (fallbackError) {
|
|
210
|
-
if (!isMissingFileError(fallbackError)) {
|
|
211
|
-
throw fallbackError;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
throw createError({
|
|
216
|
-
statusCode: 404,
|
|
217
|
-
statusMessage: "Storage file not found."
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
});
|
|
File without changes
|