nuxt-studio 1.3.3 → 1.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/dist/app/asciidoc-AY8u9WWM.js +1 -0
- package/dist/app/ayu-dark-DYE7WIF3.js +1 -0
- package/dist/app/ayu-light-BA47KaF1.js +1 -0
- package/dist/app/ayu-mirage-32ctXXKs.js +1 -0
- package/dist/app/bird2-DECYBE5b.js +1 -0
- package/dist/app/c3-BBJ779-z.js +1 -0
- package/dist/app/en-wvzTRdZ2.js +1 -0
- package/dist/app/{erb-BkKzIHzi.js → erb-BPZEWadm.js} +1 -1
- package/dist/app/horizon-bright-Cn-bp-IR.js +1 -0
- package/dist/app/{index-BemYRVDN.js → index-BzjOWvSV.js} +1 -1
- package/dist/app/index-DN_Tmc8V.js +1 -0
- package/dist/app/{index-BJwWKj3q.js → index-DnbSsQeV.js} +1 -1
- package/dist/app/just-BrBcRIfs.js +1 -0
- package/dist/app/latex-DFFaUVSZ.js +1 -0
- package/dist/app/{llvm-BMwXnwe8.js → llvm-w4szIS5k.js} +1 -1
- package/dist/app/main-BaiiAKHN.js +42 -0
- package/dist/app/main.d.ts +29 -23
- package/dist/app/main.js +1 -1
- package/dist/app/marko-CVUQDN1F.js +1 -0
- package/dist/app/{mdc-CKHPIY6R.js → mdc-E5Yo7yrS.js} +1 -1
- package/dist/app/mojo-C2cxD0aZ.js +1 -0
- package/dist/app/moonbit-B4gpyPjt.js +1 -0
- package/dist/app/nextflow-NhKJRLNF.js +1 -0
- package/dist/app/nextflow-groovy-CqvLf608.js +1 -0
- package/dist/app/nushell-Mk45ZIMx.js +1 -0
- package/dist/app/{rehype-B5jXSQHB.js → rehype-B0pzK8Ph.js} +1 -1
- package/dist/app/ron-DIZViclS.js +1 -0
- package/dist/app/{rst-Db6JICNt.js → rst-RpuXd47r.js} +1 -1
- package/dist/app/ruby-Bz6Ou-59.js +1 -0
- package/dist/app/service-worker.d.ts +23 -23
- package/dist/app/shared--ESjFm2d.js +1 -0
- package/dist/app/shared.d.ts +23 -25
- package/dist/app/shared.js +1 -1
- package/dist/app/{shiki-B5XDhU_3.js → shiki-DIDkQbrM.js} +1 -1
- package/dist/app/svelte-BuOg6tJl.js +1 -0
- package/dist/app/{swift-dg2QTUdp.js → swift-0qv2hBXI.js} +1 -1
- package/dist/app/tex-ByCZWQmN.js +1 -0
- package/dist/app/{twig-DL5s0dWc.js → twig-R-aCXzIu.js} +1 -1
- package/dist/module/module.d.mts +55 -0
- package/dist/module/module.json +1 -1
- package/dist/module/module.mjs +154 -99
- package/dist/module/runtime/host.js +30 -19
- package/dist/module/runtime/server/routes/ai/analyze.post.js +3 -17
- package/dist/module/runtime/server/routes/ai/generate.post.js +3 -17
- package/dist/module/runtime/server/routes/auth/github.get.d.ts +10 -3
- package/dist/module/runtime/server/routes/auth/github.get.js +7 -4
- package/dist/module/runtime/server/routes/auth/gitlab.get.js +2 -2
- package/dist/module/runtime/server/routes/dev/public/[...path].js +3 -2
- package/dist/module/runtime/server/routes/medias/[...path].d.ts +2 -0
- package/dist/module/runtime/server/routes/medias/[...path].js +71 -0
- package/dist/module/runtime/server/routes/meta.js +4 -19
- package/dist/module/runtime/server/utils/auth.d.ts +1 -0
- package/dist/module/runtime/server/utils/auth.js +20 -2
- package/dist/module/runtime/utils/collection.js +5 -7
- package/dist/module/runtime/utils/constants.d.ts +1 -0
- package/dist/module/runtime/utils/constants.js +1 -0
- package/dist/module/runtime/utils/media.js +2 -2
- package/package.json +23 -21
- package/dist/app/asciidoc-XTVL4-GN.js +0 -1
- package/dist/app/ayu-dark-CMjwMIkn.js +0 -1
- package/dist/app/ayu-light-C47S-Tmv.js +0 -1
- package/dist/app/ayu-mirage-CjoLj4QM.js +0 -1
- package/dist/app/c3-B5xr2KH_.js +0 -1
- package/dist/app/en-BLcCUEmi.js +0 -1
- package/dist/app/index-BNGZo_v7.js +0 -1
- package/dist/app/index-D-57dgKD.js +0 -1
- package/dist/app/index-DHS_I0O0.js +0 -2
- package/dist/app/latex-DHfEut71.js +0 -1
- package/dist/app/main-DIc-1QZK.js +0 -44
- package/dist/app/main-PbQDqQ97.js +0 -44
- package/dist/app/marko-2xMnbWEh.js +0 -1
- package/dist/app/mojo-CxwnvobC.js +0 -1
- package/dist/app/moonbit-Cu4LvJk1.js +0 -1
- package/dist/app/nextflow-D-awTbLA.js +0 -1
- package/dist/app/nushell-Cdolw_6l.js +0 -1
- package/dist/app/rehype-C7dZfu6l.js +0 -1
- package/dist/app/ron-1l4eGd0-.js +0 -1
- package/dist/app/ruby-DQYiaCa_.js +0 -1
- package/dist/app/shared-DSAAKzND.js +0 -1
- package/dist/app/shiki-BLgMZ_FB.js +0 -1
- package/dist/app/svelte-ChRP14-8.js +0 -1
- package/dist/app/tex-C-BO_DSa.js +0 -1
|
@@ -5,7 +5,7 @@ import { applyCollectionSchema, isDocumentMatchingContent, generateDocumentFromC
|
|
|
5
5
|
import { getHostStyles, getSidebarWidth, adjustFixedElements } from "./utils/sidebar.js";
|
|
6
6
|
import { clearError, getAppManifest, queryCollection, queryCollectionItemSurroundings, queryCollectionNavigation, queryCollectionSearchSections, useRuntimeConfig } from "#imports";
|
|
7
7
|
import { collections } from "#content/preview";
|
|
8
|
-
import { publicAssetsStorage } from "#build/studio-
|
|
8
|
+
import { publicAssetsStorage, externalAssetsStorage } from "#build/studio-assets";
|
|
9
9
|
import { useHostMeta } from "./composables/useMeta.js";
|
|
10
10
|
import { generateIdFromFsPath as generateMediaIdFromFsPath } from "./utils/media.js";
|
|
11
11
|
import { getCollectionSourceById } from "./utils/source.js";
|
|
@@ -52,11 +52,13 @@ export function useStudioHost(user, repository) {
|
|
|
52
52
|
function useContentCollectionQuery(collection) {
|
|
53
53
|
return useContent().queryCollection(collection);
|
|
54
54
|
}
|
|
55
|
-
const
|
|
56
|
-
const aiConfig =
|
|
55
|
+
const studioConfig = useRuntimeConfig().public.studio;
|
|
56
|
+
const aiConfig = studioConfig.ai;
|
|
57
|
+
const mediaConfig = studioConfig.media;
|
|
57
58
|
const host = {
|
|
58
59
|
meta: {
|
|
59
60
|
dev: false,
|
|
61
|
+
media: mediaConfig,
|
|
60
62
|
ai: {
|
|
61
63
|
enabled: aiConfig?.enabled ?? false,
|
|
62
64
|
experimental: {
|
|
@@ -68,7 +70,7 @@ export function useStudioHost(user, repository) {
|
|
|
68
70
|
}
|
|
69
71
|
},
|
|
70
72
|
getComponents: () => meta.components.value,
|
|
71
|
-
defaultLocale:
|
|
73
|
+
defaultLocale: studioConfig.i18n?.defaultLocale || "en",
|
|
72
74
|
getHighlightTheme: () => meta.highlightTheme.value
|
|
73
75
|
},
|
|
74
76
|
on: {
|
|
@@ -235,21 +237,30 @@ export function useStudioHost(user, repository) {
|
|
|
235
237
|
contentFromDocument: async (document2) => generateContentFromDocument(document2)
|
|
236
238
|
}
|
|
237
239
|
},
|
|
238
|
-
media: {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
240
|
+
media: /* @__PURE__ */ (() => {
|
|
241
|
+
const getStorage = () => host.meta.media?.external ? externalAssetsStorage : publicAssetsStorage;
|
|
242
|
+
return {
|
|
243
|
+
get: async (fsPath) => {
|
|
244
|
+
return await getStorage().getItem(generateMediaIdFromFsPath(fsPath));
|
|
245
|
+
},
|
|
246
|
+
list: async () => {
|
|
247
|
+
const storage = getStorage();
|
|
248
|
+
return await Promise.all(
|
|
249
|
+
await storage.getKeys().then(
|
|
250
|
+
(keys) => keys.map((key) => storage.getItem(key))
|
|
251
|
+
)
|
|
252
|
+
);
|
|
253
|
+
},
|
|
254
|
+
upsert: async (fsPath, media) => {
|
|
255
|
+
const id = generateMediaIdFromFsPath(fsPath);
|
|
256
|
+
await getStorage().setItem(id, { ...media, id });
|
|
257
|
+
},
|
|
258
|
+
delete: async (fsPath) => {
|
|
259
|
+
const id = generateMediaIdFromFsPath(fsPath);
|
|
260
|
+
await getStorage().removeItem(id);
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
})(),
|
|
253
264
|
app: {
|
|
254
265
|
getManifestId: async () => {
|
|
255
266
|
const manifest = await getAppManifest();
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { streamText } from "ai";
|
|
2
2
|
import { createGateway } from "@ai-sdk/gateway";
|
|
3
|
-
import { eventHandler, createError,
|
|
3
|
+
import { eventHandler, createError, readBody } from "h3";
|
|
4
4
|
import { consola } from "consola";
|
|
5
5
|
import { useRuntimeConfig } from "#imports";
|
|
6
|
+
import { requireStudioAuth } from "../../utils/auth.js";
|
|
6
7
|
import { queryCollection } from "@nuxt/content/server";
|
|
7
8
|
import {
|
|
8
9
|
detectContentType,
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
import { ContentType } from "../../types/ai.js";
|
|
15
16
|
const logger = consola.withTag("Nuxt Studio");
|
|
16
17
|
export default eventHandler(async (event) => {
|
|
18
|
+
await requireStudioAuth(event);
|
|
17
19
|
const config = useRuntimeConfig(event);
|
|
18
20
|
const body = await readBody(event).catch(() => ({}));
|
|
19
21
|
const collection = body.collection;
|
|
@@ -29,22 +31,6 @@ export default eventHandler(async (event) => {
|
|
|
29
31
|
statusMessage: "Invalid collection: name and type are required"
|
|
30
32
|
});
|
|
31
33
|
}
|
|
32
|
-
if (!config.public.studio.dev) {
|
|
33
|
-
const session = await useSession(event, {
|
|
34
|
-
name: "studio-session",
|
|
35
|
-
password: config.studio?.auth?.sessionSecret,
|
|
36
|
-
cookie: {
|
|
37
|
-
secure: getRequestProtocol(event) === "https",
|
|
38
|
-
path: "/"
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
if (!session.data || Object.keys(session.data).length === 0) {
|
|
42
|
-
throw createError({
|
|
43
|
-
statusCode: 401,
|
|
44
|
-
statusMessage: "Unauthorized. Please log in to use AI features."
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
34
|
const aiConfig = config.studio?.ai;
|
|
49
35
|
const apiKey = aiConfig?.apiKey;
|
|
50
36
|
if (!apiKey) {
|
|
@@ -1,30 +1,16 @@
|
|
|
1
1
|
import { streamText } from "ai";
|
|
2
2
|
import { createGateway } from "@ai-sdk/gateway";
|
|
3
|
-
import { eventHandler, readBody, createError
|
|
3
|
+
import { eventHandler, readBody, createError } from "h3";
|
|
4
4
|
import { useRuntimeConfig } from "#imports";
|
|
5
5
|
import {
|
|
6
6
|
buildAIContext,
|
|
7
7
|
calculateMaxTokens,
|
|
8
8
|
getSystem
|
|
9
9
|
} from "../../utils/ai/generate.js";
|
|
10
|
+
import { requireStudioAuth } from "../../utils/auth.js";
|
|
10
11
|
export default eventHandler(async (event) => {
|
|
12
|
+
await requireStudioAuth(event);
|
|
11
13
|
const config = useRuntimeConfig(event);
|
|
12
|
-
if (!config.public.studio.dev) {
|
|
13
|
-
const session = await useSession(event, {
|
|
14
|
-
name: "studio-session",
|
|
15
|
-
password: config.studio?.auth?.sessionSecret,
|
|
16
|
-
cookie: {
|
|
17
|
-
secure: getRequestProtocol(event) === "https",
|
|
18
|
-
path: "/"
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
if (!session.data || Object.keys(session.data).length === 0) {
|
|
22
|
-
throw createError({
|
|
23
|
-
statusCode: 401,
|
|
24
|
-
statusMessage: "Unauthorized. Please log in to use AI features."
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
14
|
const aiConfig = config.studio?.ai;
|
|
29
15
|
const apiKey = aiConfig?.apiKey;
|
|
30
16
|
if (!apiKey) {
|
|
@@ -21,19 +21,26 @@ export interface OAuthGitHubConfig {
|
|
|
21
21
|
* @default false
|
|
22
22
|
*/
|
|
23
23
|
emailRequired?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* GitHub instance base web URL (for GitHub Enterprise Server).
|
|
26
|
+
* Must be the web origin without a trailing slash and without `/api/v3`,
|
|
27
|
+
* for example: `https://github.com` or `https://ghe.example.com`.
|
|
28
|
+
* @default 'https://github.com'
|
|
29
|
+
*/
|
|
30
|
+
instanceUrl?: string;
|
|
24
31
|
/**
|
|
25
32
|
* GitHub OAuth Authorization URL
|
|
26
|
-
* @default '
|
|
33
|
+
* @default '{instanceUrl}/login/oauth/authorize'
|
|
27
34
|
*/
|
|
28
35
|
authorizationURL?: string;
|
|
29
36
|
/**
|
|
30
37
|
* GitHub OAuth Token URL
|
|
31
|
-
* @default '
|
|
38
|
+
* @default '{instanceUrl}/login/oauth/access_token'
|
|
32
39
|
*/
|
|
33
40
|
tokenURL?: string;
|
|
34
41
|
/**
|
|
35
42
|
* GitHub API URL
|
|
36
|
-
* @default 'https://api.github.com'
|
|
43
|
+
* @default 'https://api.github.com' (or '{instanceUrl}/api/v3' for GitHub Enterprise Server)
|
|
37
44
|
*/
|
|
38
45
|
apiURL?: string;
|
|
39
46
|
/**
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { useRuntimeConfig } from "#imports";
|
|
2
2
|
import { createError, deleteCookie, eventHandler, getCookie, getQuery, getRequestURL, sendRedirect } from "h3";
|
|
3
|
-
import { withQuery } from "ufo";
|
|
3
|
+
import { withQuery, withoutTrailingSlash } from "ufo";
|
|
4
4
|
import { generateOAuthState, requestAccessToken, validateOAuthState } from "../../utils/auth.js";
|
|
5
5
|
import { setInternalStudioUserSession } from "../../utils/session.js";
|
|
6
6
|
import { mergeConfig } from "../../utils/object.js";
|
|
7
7
|
export default eventHandler(async (event) => {
|
|
8
8
|
const studioConfig = useRuntimeConfig(event).studio;
|
|
9
|
+
const instanceUrl = withoutTrailingSlash(studioConfig?.auth?.github?.instanceUrl || studioConfig?.repository?.instanceUrl || "https://github.com");
|
|
10
|
+
const isEnterprise = new URL(instanceUrl).hostname !== "github.com";
|
|
9
11
|
const config = mergeConfig(studioConfig?.auth?.github, {
|
|
10
12
|
clientId: process.env.STUDIO_GITHUB_CLIENT_ID,
|
|
11
13
|
clientSecret: process.env.STUDIO_GITHUB_CLIENT_SECRET,
|
|
12
14
|
redirectURL: process.env.STUDIO_GITHUB_REDIRECT_URL,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
instanceUrl,
|
|
16
|
+
authorizationURL: `${instanceUrl}/login/oauth/authorize`,
|
|
17
|
+
tokenURL: `${instanceUrl}/login/oauth/access_token`,
|
|
18
|
+
apiURL: isEnterprise ? `${instanceUrl}/api/v3` : "https://api.github.com",
|
|
16
19
|
authorizationParams: {},
|
|
17
20
|
emailRequired: true
|
|
18
21
|
});
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { useRuntimeConfig } from "#imports";
|
|
2
2
|
import { createError, deleteCookie, eventHandler, getCookie, getQuery, getRequestURL, sendRedirect } from "h3";
|
|
3
3
|
import { FetchError } from "ofetch";
|
|
4
|
-
import { withQuery } from "ufo";
|
|
4
|
+
import { withQuery, withoutTrailingSlash } from "ufo";
|
|
5
5
|
import { generateOAuthState, validateOAuthState } from "../../utils/auth.js";
|
|
6
6
|
import { setInternalStudioUserSession } from "../../utils/session.js";
|
|
7
7
|
import { mergeConfig } from "../../utils/object.js";
|
|
8
8
|
export default eventHandler(async (event) => {
|
|
9
9
|
const studioConfig = useRuntimeConfig(event).studio;
|
|
10
|
-
const instanceUrl = studioConfig?.auth?.gitlab?.instanceUrl || "https://gitlab.com";
|
|
10
|
+
const instanceUrl = withoutTrailingSlash(studioConfig?.auth?.gitlab?.instanceUrl || studioConfig?.repository?.instanceUrl || "https://gitlab.com");
|
|
11
11
|
const config = mergeConfig(studioConfig?.auth?.gitlab, {
|
|
12
12
|
applicationId: process.env.STUDIO_GITLAB_APPLICATION_ID,
|
|
13
13
|
applicationSecret: process.env.STUDIO_GITLAB_APPLICATION_SECRET,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createError, eventHandler, getRequestHeader, readRawBody, setResponseHeader } from "h3";
|
|
2
2
|
import { withLeadingSlash } from "ufo";
|
|
3
3
|
import { useStorage } from "#imports";
|
|
4
|
+
import { VIRTUAL_MEDIA_COLLECTION_NAME } from "../../../../utils/constants.js";
|
|
4
5
|
export default eventHandler(async (event) => {
|
|
5
6
|
const path = event.path.replace("/__nuxt_studio/dev/public/", "");
|
|
6
|
-
const key = path.replace(/\//g, ":").replace(
|
|
7
|
+
const key = path.replace(/\//g, ":").replace(new RegExp(`^${VIRTUAL_MEDIA_COLLECTION_NAME}:`), "");
|
|
7
8
|
const storage = useStorage("nuxt_studio_public_assets");
|
|
8
9
|
if (event.method === "GET") {
|
|
9
10
|
const lastChar = key[key.length - 1];
|
|
@@ -20,7 +21,7 @@ export default eventHandler(async (event) => {
|
|
|
20
21
|
});
|
|
21
22
|
}
|
|
22
23
|
return {
|
|
23
|
-
id:
|
|
24
|
+
id: `${VIRTUAL_MEDIA_COLLECTION_NAME}/${key.replace(/:/g, "/")}`,
|
|
24
25
|
extension: key.split(".").pop(),
|
|
25
26
|
stem: key.split(".").join("."),
|
|
26
27
|
path: "/" + key.replace(/:/g, "/"),
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { joinURL, withLeadingSlash } from "ufo";
|
|
2
|
+
import { createError, eventHandler, readBody } from "h3";
|
|
3
|
+
import { useRuntimeConfig } from "#imports";
|
|
4
|
+
import { VIRTUAL_MEDIA_COLLECTION_NAME } from "../../../utils/constants.js";
|
|
5
|
+
import { requireStudioAuth } from "../../utils/auth.js";
|
|
6
|
+
import { blob } from "hub:blob";
|
|
7
|
+
export default eventHandler(async (event) => {
|
|
8
|
+
await requireStudioAuth(event);
|
|
9
|
+
const { prefix, publicUrl, maxFileSize, allowedTypes } = useRuntimeConfig(event).public.studio.media;
|
|
10
|
+
const path = event.path.replace("/__nuxt_studio/medias/", "");
|
|
11
|
+
const key = path.replace(/\//g, ":").replace(new RegExp(`^${VIRTUAL_MEDIA_COLLECTION_NAME}:`), "");
|
|
12
|
+
if (event.method === "GET") {
|
|
13
|
+
const isBaseKey = key.endsWith("/") || key.endsWith(":");
|
|
14
|
+
if (isBaseKey) {
|
|
15
|
+
const subPath = key.slice(0, -1).replace(/:/g, "/");
|
|
16
|
+
const effectivePrefix = prefix ? subPath ? `${prefix}/${subPath}` : prefix : subPath;
|
|
17
|
+
const { blobs } = await blob.list(effectivePrefix ? { prefix: `${effectivePrefix}/` } : {});
|
|
18
|
+
return blobs.map((b) => {
|
|
19
|
+
return prefix ? b.pathname.slice(`${prefix}/`.length) : b.pathname;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
const blobPath = key.replace(/:/g, "/");
|
|
23
|
+
const pathname = prefix ? `${prefix}/${blobPath}` : blobPath;
|
|
24
|
+
const meta = await blob.head(pathname);
|
|
25
|
+
if (!meta) {
|
|
26
|
+
throw createError({ statusCode: 404, message: "Item not found" });
|
|
27
|
+
}
|
|
28
|
+
const fsPath = withLeadingSlash(blobPath);
|
|
29
|
+
const resolvedPath = meta.url ?? joinURL(publicUrl, prefix, fsPath);
|
|
30
|
+
return {
|
|
31
|
+
id: path,
|
|
32
|
+
fsPath,
|
|
33
|
+
extension: fsPath.split(".").pop(),
|
|
34
|
+
stem: fsPath.split(".").slice(0, -1).join("."),
|
|
35
|
+
path: resolvedPath
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (event.method === "PUT") {
|
|
39
|
+
const body = await readBody(event);
|
|
40
|
+
const blobPath = key.replace(/:/g, "/");
|
|
41
|
+
const pathname = prefix ? `${prefix}/${blobPath}` : blobPath;
|
|
42
|
+
if (!body.raw) {
|
|
43
|
+
await blob.put(pathname, JSON.stringify(body), { contentType: "application/json" });
|
|
44
|
+
} else {
|
|
45
|
+
const raw = body.raw;
|
|
46
|
+
const [meta, data] = raw.split(";base64,");
|
|
47
|
+
const mimeType = meta.replace("data:", "");
|
|
48
|
+
const approximateSize = data.length * 3 / 4;
|
|
49
|
+
if (approximateSize > maxFileSize) {
|
|
50
|
+
throw createError({ statusCode: 413, message: `File size exceeds maximum of ${maxFileSize / 1024 / 1024}MB` });
|
|
51
|
+
}
|
|
52
|
+
if (!allowedTypes.some((t) => mimeType.startsWith(t.replace("*", "")))) {
|
|
53
|
+
throw createError({ statusCode: 415, message: `File type "${mimeType}" is not allowed` });
|
|
54
|
+
}
|
|
55
|
+
const binaryString = atob(data);
|
|
56
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
57
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
58
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
59
|
+
}
|
|
60
|
+
await blob.put(pathname, bytes, { contentType: mimeType });
|
|
61
|
+
}
|
|
62
|
+
return "OK";
|
|
63
|
+
}
|
|
64
|
+
if (event.method === "DELETE") {
|
|
65
|
+
const blobPath = key.replace(/:/g, "/");
|
|
66
|
+
const pathname = prefix ? `${prefix}/${blobPath}` : blobPath;
|
|
67
|
+
await blob.del(pathname);
|
|
68
|
+
return "OK";
|
|
69
|
+
}
|
|
70
|
+
throw createError({ statusCode: 405, message: "Method not allowed" });
|
|
71
|
+
});
|
|
@@ -1,27 +1,12 @@
|
|
|
1
|
-
import { eventHandler
|
|
2
|
-
import { useRuntimeConfig
|
|
1
|
+
import { eventHandler } from "h3";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
3
|
import components from "#nuxt-component-meta/nitro";
|
|
4
4
|
import { highlight } from "#mdc-imports";
|
|
5
5
|
import { filterComponents } from "../utils/meta.js";
|
|
6
|
+
import { requireStudioAuth } from "../utils/auth.js";
|
|
6
7
|
export default eventHandler(async (event) => {
|
|
8
|
+
await requireStudioAuth(event);
|
|
7
9
|
const config = useRuntimeConfig();
|
|
8
|
-
if (!import.meta.dev) {
|
|
9
|
-
const session = await useSession(event, {
|
|
10
|
-
name: "studio-session",
|
|
11
|
-
password: config.studio?.auth?.sessionSecret,
|
|
12
|
-
cookie: {
|
|
13
|
-
// Use secure cookies over HTTPS, required for locally testing purposes
|
|
14
|
-
secure: getRequestProtocol(event) === "https",
|
|
15
|
-
path: "/"
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
if (!session?.data?.user) {
|
|
19
|
-
throw createError({
|
|
20
|
-
statusCode: 404,
|
|
21
|
-
message: "Not found"
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
10
|
const mappedComponents = Object.values(components).map(({ pascalName, filePath, meta }) => {
|
|
26
11
|
return {
|
|
27
12
|
name: pascalName,
|
|
@@ -1,6 +1,24 @@
|
|
|
1
|
-
import { createError, deleteCookie, getCookie, getRequestProtocol, setCookie } from "h3";
|
|
2
|
-
import { FetchError } from "ofetch";
|
|
3
1
|
import { getRandomValues } from "uncrypto";
|
|
2
|
+
import { getCookie, deleteCookie, setCookie, useSession, getRequestProtocol, createError } from "h3";
|
|
3
|
+
import { FetchError } from "ofetch";
|
|
4
|
+
import { useRuntimeConfig } from "#imports";
|
|
5
|
+
export async function requireStudioAuth(event) {
|
|
6
|
+
if (import.meta.dev) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const config = useRuntimeConfig(event);
|
|
10
|
+
const session = await useSession(event, {
|
|
11
|
+
name: "studio-session",
|
|
12
|
+
password: config.studio?.auth?.sessionSecret,
|
|
13
|
+
cookie: {
|
|
14
|
+
secure: getRequestProtocol(event) === "https",
|
|
15
|
+
path: "/"
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
if (!session?.data?.user) {
|
|
19
|
+
throw createError({ statusCode: 404, message: "Not found" });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
4
22
|
export async function requestAccessToken(url, options) {
|
|
5
23
|
const headers = {
|
|
6
24
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
@@ -74,16 +74,14 @@ function computeValuesBasedOnCollectionSchema(collection, data) {
|
|
|
74
74
|
const defaultValue = value?.default !== void 0 ? value.default : "NULL";
|
|
75
75
|
const valueToInsert = typeof data[key] !== "undefined" ? data[key] : defaultValue;
|
|
76
76
|
fields.push(key);
|
|
77
|
-
if (
|
|
77
|
+
if (valueToInsert === null || valueToInsert === "NULL" || valueToInsert === "") {
|
|
78
|
+
values.push("NULL");
|
|
79
|
+
} else if (type === "json") {
|
|
78
80
|
values.push(`'${JSON.stringify(valueToInsert).replace(/'/g, "''")}'`);
|
|
79
81
|
} else if (type === "string" || ["string", "enum"].includes(value.type)) {
|
|
80
|
-
|
|
81
|
-
values.push(valueToInsert !== "NULL" ? `'${new Date(valueToInsert).toISOString()}'` : defaultValue);
|
|
82
|
-
} else {
|
|
83
|
-
values.push(`'${String(valueToInsert).replace(/\n/g, "\\n").replace(/'/g, "''")}'`);
|
|
84
|
-
}
|
|
82
|
+
values.push(`'${String(valueToInsert).replace(/\n/g, "\\n").replace(/'/g, "''")}'`);
|
|
85
83
|
} else if (type === "boolean") {
|
|
86
|
-
values.push(
|
|
84
|
+
values.push(!!valueToInsert);
|
|
87
85
|
} else {
|
|
88
86
|
values.push(valueToInsert);
|
|
89
87
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const VIRTUAL_MEDIA_COLLECTION_NAME: "public-assets";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const VIRTUAL_MEDIA_COLLECTION_NAME = "public-assets";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { join } from "pathe";
|
|
2
|
-
import {
|
|
2
|
+
import { VIRTUAL_MEDIA_COLLECTION_NAME } from "./constants.js";
|
|
3
3
|
export function generateIdFromFsPath(fsPath) {
|
|
4
|
-
return join(
|
|
4
|
+
return join(VIRTUAL_MEDIA_COLLECTION_NAME, fsPath);
|
|
5
5
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-studio",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Nuxt Studio for Nuxt Content",
|
|
5
5
|
"private": false,
|
|
6
6
|
"repository": {
|
|
@@ -48,59 +48,61 @@
|
|
|
48
48
|
"clean": "rm -rf dist .nuxt .output node_modules docs/node_modules docs/.output docs/.data docs/.nuxt playground/docus/node_modules playground/docus/.output playground/docus/.data playground/docus/.nuxt playground/minimal/node_modules playground/minimal/.output playground/minimal/.data playground/minimal/.nuxt pnpm-lock.yaml"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@ai-sdk/gateway": "^3.0.
|
|
52
|
-
"@ai-sdk/vue": "^3.0.
|
|
53
|
-
"@iconify-json/lucide": "^1.2.
|
|
51
|
+
"@ai-sdk/gateway": "^3.0.55",
|
|
52
|
+
"@ai-sdk/vue": "^3.0.101",
|
|
53
|
+
"@iconify-json/lucide": "^1.2.94",
|
|
54
54
|
"@nuxtjs/mdc": "^0.20.1",
|
|
55
55
|
"@vueuse/core": "^14.2.1",
|
|
56
|
-
"ai": "^6.0.
|
|
56
|
+
"ai": "^6.0.101",
|
|
57
57
|
"defu": "^6.1.4",
|
|
58
58
|
"destr": "^2.0.5",
|
|
59
59
|
"js-yaml": "^4.1.1",
|
|
60
|
-
"minimatch": "^10.
|
|
60
|
+
"minimatch": "^10.2.4",
|
|
61
61
|
"nuxt-component-meta": "^0.17.2",
|
|
62
62
|
"remark-mdc": "^3.10.0",
|
|
63
|
-
"shiki": "^3.
|
|
63
|
+
"shiki": "^3.23.0",
|
|
64
64
|
"unstorage": "1.17.4",
|
|
65
65
|
"zod": "^4.3.6",
|
|
66
66
|
"zod-to-json-schema": "^3.25.1"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@gitbeaker/core": "^43.8.0",
|
|
70
|
-
"@iconify-json/simple-icons": "^1.2.
|
|
71
|
-
"@nuxt/content": "^3.
|
|
72
|
-
"@nuxt/eslint-config": "^1.15.
|
|
70
|
+
"@iconify-json/simple-icons": "^1.2.71",
|
|
71
|
+
"@nuxt/content": "^3.12.0",
|
|
72
|
+
"@nuxt/eslint-config": "^1.15.2",
|
|
73
73
|
"@nuxt/kit": "^4.3.1",
|
|
74
74
|
"@nuxt/module-builder": "^1.0.2",
|
|
75
|
-
"@nuxt/ui": "^4.
|
|
75
|
+
"@nuxt/ui": "^4.5.0",
|
|
76
76
|
"@octokit/types": "^16.0.0",
|
|
77
77
|
"@release-it/conventional-changelog": "^10.0.5",
|
|
78
78
|
"@tailwindcss/typography": "^0.5.19",
|
|
79
|
-
"@tiptap/extension-emoji": "^3.
|
|
79
|
+
"@tiptap/extension-emoji": "^3.20.0",
|
|
80
80
|
"@types/js-yaml": "^4.0.9",
|
|
81
|
-
"@unhead/vue": "^2.1.
|
|
81
|
+
"@unhead/vue": "^2.1.9",
|
|
82
82
|
"@unpic/vue": "^1.0.0",
|
|
83
83
|
"@vitejs/plugin-vue": "^6.0.4",
|
|
84
|
-
"eslint": "^10.0.
|
|
84
|
+
"eslint": "^10.0.2",
|
|
85
85
|
"idb-keyval": "^6.2.2",
|
|
86
86
|
"minimark": "^0.2.0",
|
|
87
|
-
"modern-monaco": "^0.3.
|
|
87
|
+
"modern-monaco": "^0.3.8",
|
|
88
88
|
"nuxt-studio": "workspace:*",
|
|
89
89
|
"ofetch": "^1.5.1",
|
|
90
90
|
"release-it": "^19.2.4",
|
|
91
|
-
"tailwindcss": "^4.1
|
|
91
|
+
"tailwindcss": "^4.2.1",
|
|
92
92
|
"vite": "^7.3.1",
|
|
93
93
|
"vite-plugin-dts": "^4.5.4",
|
|
94
94
|
"vite-plugin-libcss": "^1.1.2",
|
|
95
95
|
"vitest": "^4.0.18",
|
|
96
|
-
"vue": "^3.5.
|
|
97
|
-
"vue-router": "^5.0.
|
|
98
|
-
"vue-tsc": "^3.2.
|
|
96
|
+
"vue": "^3.5.29",
|
|
97
|
+
"vue-router": "^5.0.3",
|
|
98
|
+
"vue-tsc": "^3.2.5"
|
|
99
99
|
},
|
|
100
100
|
"resolutions": {
|
|
101
|
-
"minimark": "^0.2.0"
|
|
101
|
+
"minimark": "^0.2.0",
|
|
102
|
+
"@nuxt/content": "^3.12.0",
|
|
103
|
+
"unimport": "5.6.0"
|
|
102
104
|
},
|
|
103
|
-
"packageManager": "pnpm@10.
|
|
105
|
+
"packageManager": "pnpm@10.30.3",
|
|
104
106
|
"keywords": [
|
|
105
107
|
"nuxt",
|
|
106
108
|
"content",
|