@caiquecamargo/vite-plugin-netlify-cms 0.1.7 → 0.1.8
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/index.d.ts +3 -58
- package/dist/index.js +111 -170
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/oauth/config.ts +4 -2
- package/src/oauth/astro-callback.ts +0 -69
- package/src/oauth/astro-login.ts +0 -8
package/dist/index.d.ts
CHANGED
|
@@ -1,28 +1,5 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
2
|
|
|
3
|
-
interface OAuthPluginOptions {
|
|
4
|
-
/**
|
|
5
|
-
* OAuth login route
|
|
6
|
-
* @default '/oauth'
|
|
7
|
-
*/
|
|
8
|
-
loginRoute?: string;
|
|
9
|
-
/**
|
|
10
|
-
* OAuth callback route
|
|
11
|
-
* @default '/oauth/callback'
|
|
12
|
-
*/
|
|
13
|
-
callbackRoute?: string;
|
|
14
|
-
/**
|
|
15
|
-
* Disable OAuth plugin
|
|
16
|
-
* @default false
|
|
17
|
-
*/
|
|
18
|
-
disabled?: boolean;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Vite plugin for OAuth authentication routes
|
|
22
|
-
* Adds /oauth and /oauth/callback routes for GitHub authentication
|
|
23
|
-
*/
|
|
24
|
-
declare function oauthPlugin(options?: OAuthPluginOptions): Plugin;
|
|
25
|
-
|
|
26
3
|
type Widgets = 'boolean' | 'code' | 'color' | 'compute' | 'datetime' | 'hidden' | 'file' | 'image' | 'keyvalue' | 'list' | 'map' | 'markdown' | 'number' | 'object' | 'relation' | 'richtext' | 'select' | 'string' | 'text' | 'uuid';
|
|
27
4
|
type LocaleCode = string;
|
|
28
5
|
interface Widget {
|
|
@@ -834,6 +811,7 @@ interface NetlifyCMSConfig {
|
|
|
834
811
|
};
|
|
835
812
|
}
|
|
836
813
|
|
|
814
|
+
declare function updateAstroConfigWithOAuthEnv(root: string): Promise<void>;
|
|
837
815
|
declare function defineConfig(config: NetlifyCMSConfig): NetlifyCMSConfig;
|
|
838
816
|
declare function defineFolderCollection(collection: FolderCollection): FolderCollection;
|
|
839
817
|
declare const defineFileCollection: (collection: FileCollection) => FileCollection;
|
|
@@ -903,42 +881,9 @@ interface NetlifyCMSEntry {
|
|
|
903
881
|
* @default 'sveltia'
|
|
904
882
|
*/
|
|
905
883
|
type?: 'decap' | 'sveltia';
|
|
884
|
+
oauth?: boolean;
|
|
906
885
|
}
|
|
907
886
|
declare function createConfig(root: string, entry?: NetlifyCMSEntry): Promise<void>;
|
|
908
887
|
declare function export_default(entry?: NetlifyCMSEntry): Promise<Plugin>;
|
|
909
888
|
|
|
910
|
-
|
|
911
|
-
/**
|
|
912
|
-
* OAuth login route
|
|
913
|
-
* @default '/oauth'
|
|
914
|
-
*/
|
|
915
|
-
loginRoute?: string;
|
|
916
|
-
/**
|
|
917
|
-
* OAuth callback route
|
|
918
|
-
* @default '/oauth/callback'
|
|
919
|
-
*/
|
|
920
|
-
callbackRoute?: string;
|
|
921
|
-
/**
|
|
922
|
-
* Disable OAuth integration
|
|
923
|
-
* @default false
|
|
924
|
-
*/
|
|
925
|
-
disabled?: boolean;
|
|
926
|
-
}
|
|
927
|
-
/**
|
|
928
|
-
* Astro integration for OAuth authentication routes
|
|
929
|
-
* Adds /oauth and /oauth/callback routes for GitHub authentication
|
|
930
|
-
*
|
|
931
|
-
* @example
|
|
932
|
-
* ```ts
|
|
933
|
-
* import { defineConfig } from 'astro/config';
|
|
934
|
-
* import { githubOAuthIntegration } from 'vite-plugin-netlify-cms';
|
|
935
|
-
*
|
|
936
|
-
* export default defineConfig({
|
|
937
|
-
* integrations: [githubOAuthIntegration()],
|
|
938
|
-
* output: 'server', // or 'hybrid'
|
|
939
|
-
* });
|
|
940
|
-
* ```
|
|
941
|
-
*/
|
|
942
|
-
declare function githubOAuthIntegration(options?: AstroOAuthOptions): any;
|
|
943
|
-
|
|
944
|
-
export { type AstroOAuthOptions, type BooleanWidget, type CodeWidget, type Collection, type CollectionField, type ColorWidget, type ComputeWidget, type DateTimeWidget, type EditorComponent, type EditorMode, type FileCollection, type FileCollectionEntry, type FileWidget, type FolderCollection, type HiddenWidget, type ImageWidget, type KeyValueWidget, type ListWidget, type MapWidget, type MarkdownButtons, type MarkdownWidget, type NetlifyCMSConfig, type NetlifyCMSEntry, type NumberWidget, type OAuthPluginOptions, type ObjectWidget, type RelationWidget, type RichTextWidget, type SelectWidget, type StringWidget, type TextWidget, type UuidWidget, type VariableFieldType, type Widget, export_default as cmsPlugin, createConfig, export_default as default, defineBooleanWidget, defineCodeWidget, defineColorWidget, defineComputeWidget, defineConfig, defineDateTimeWidget, defineFileCollection, defineFileCollectionEntry, defineFileWidget, defineFolderCollection, defineHiddenWidget, defineImageWidget, defineKeyValueWidget, defineListWidget, defineMapWidget, defineMarkdownWidget, defineNumberWidget, defineObjectWidget, defineRelationWidget, defineRichTextWidget, defineSelectWidget, defineStringWidget, defineTextWidget, defineUuidWidget, githubOAuthIntegration, oauthPlugin };
|
|
889
|
+
export { type BooleanWidget, type CodeWidget, type Collection, type CollectionField, type ColorWidget, type ComputeWidget, type DateTimeWidget, type EditorComponent, type EditorMode, type FileCollection, type FileCollectionEntry, type FileWidget, type FolderCollection, type HiddenWidget, type ImageWidget, type KeyValueWidget, type ListWidget, type MapWidget, type MarkdownButtons, type MarkdownWidget, type NetlifyCMSConfig, type NetlifyCMSEntry, type NumberWidget, type ObjectWidget, type RelationWidget, type RichTextWidget, type SelectWidget, type StringWidget, type TextWidget, type UuidWidget, type VariableFieldType, type Widget, export_default as cmsPlugin, createConfig, export_default as default, defineBooleanWidget, defineCodeWidget, defineColorWidget, defineComputeWidget, defineConfig, defineDateTimeWidget, defineFileCollection, defineFileCollectionEntry, defineFileWidget, defineFolderCollection, defineHiddenWidget, defineImageWidget, defineKeyValueWidget, defineListWidget, defineMapWidget, defineMarkdownWidget, defineNumberWidget, defineObjectWidget, defineRelationWidget, defineRichTextWidget, defineSelectWidget, defineStringWidget, defineTextWidget, defineUuidWidget, updateAstroConfigWithOAuthEnv };
|
package/dist/index.js
CHANGED
|
@@ -1,133 +1,7 @@
|
|
|
1
|
-
// src/oauth/config.ts
|
|
2
|
-
var clientId = process.env.OAUTH_GITHUB_CLIENT_ID;
|
|
3
|
-
var clientSecret = process.env.OAUTH_GITHUB_CLIENT_SECRET;
|
|
4
|
-
var authUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&scope=repo,user`;
|
|
5
|
-
var tokenUrl = "https://github.com/login/oauth/access_token";
|
|
6
|
-
|
|
7
|
-
// src/oauth/callback.ts
|
|
8
|
-
async function handleOAuthCallback(code) {
|
|
9
|
-
const data = {
|
|
10
|
-
code,
|
|
11
|
-
client_id: clientId,
|
|
12
|
-
client_secret: clientSecret
|
|
13
|
-
};
|
|
14
|
-
try {
|
|
15
|
-
const response = await fetch(tokenUrl, {
|
|
16
|
-
method: "POST",
|
|
17
|
-
headers: {
|
|
18
|
-
"Accept": "application/json",
|
|
19
|
-
"Content-Type": "application/json"
|
|
20
|
-
},
|
|
21
|
-
body: JSON.stringify(data)
|
|
22
|
-
});
|
|
23
|
-
if (!response.ok) {
|
|
24
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
25
|
-
}
|
|
26
|
-
const body = await response.json();
|
|
27
|
-
const content = {
|
|
28
|
-
token: body.access_token,
|
|
29
|
-
provider: "github"
|
|
30
|
-
};
|
|
31
|
-
const script = `
|
|
32
|
-
<script>
|
|
33
|
-
const receiveMessage = (message) => {
|
|
34
|
-
window.opener.postMessage(
|
|
35
|
-
'authorization:${content.provider}:success:${JSON.stringify(content)}',
|
|
36
|
-
message.origin
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
window.removeEventListener("message", receiveMessage, false);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
window.addEventListener("message", receiveMessage, false);
|
|
43
|
-
|
|
44
|
-
window.opener.postMessage("authorizing:${content.provider}", "*");
|
|
45
|
-
</script>
|
|
46
|
-
`;
|
|
47
|
-
return {
|
|
48
|
-
statusCode: 200,
|
|
49
|
-
headers: {
|
|
50
|
-
"Content-Type": "text/html"
|
|
51
|
-
},
|
|
52
|
-
body: script
|
|
53
|
-
};
|
|
54
|
-
} catch (err) {
|
|
55
|
-
console.error("OAuth callback error:", err);
|
|
56
|
-
return {
|
|
57
|
-
statusCode: 500,
|
|
58
|
-
headers: {
|
|
59
|
-
"Content-Type": "text/html"
|
|
60
|
-
},
|
|
61
|
-
body: "<html><body><h1>OAuth Error</h1><p>Authentication failed. Please close this window and try again.</p></body></html>"
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// src/oauth/login.ts
|
|
67
|
-
function handleOAuthLogin() {
|
|
68
|
-
return {
|
|
69
|
-
statusCode: 302,
|
|
70
|
-
headers: {
|
|
71
|
-
Location: authUrl
|
|
72
|
-
},
|
|
73
|
-
body: ""
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// src/oauth-plugin.ts
|
|
78
|
-
function oauthPlugin(options) {
|
|
79
|
-
const {
|
|
80
|
-
loginRoute = "/oauth",
|
|
81
|
-
callbackRoute = "/oauth/callback",
|
|
82
|
-
disabled = false
|
|
83
|
-
} = options ?? {};
|
|
84
|
-
if (disabled) {
|
|
85
|
-
return {
|
|
86
|
-
name: "vite-plugin-oauth"
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
let warningShown = false;
|
|
90
|
-
return {
|
|
91
|
-
name: "vite-plugin-oauth",
|
|
92
|
-
configureServer(server) {
|
|
93
|
-
server.middlewares.use(async (req, res, next) => {
|
|
94
|
-
const url = req.url;
|
|
95
|
-
if (!warningShown) {
|
|
96
|
-
if (!clientId || !clientSecret) {
|
|
97
|
-
console.warn(
|
|
98
|
-
"\x1B[33m\u26A0 OAuth plugin enabled but OAUTH_GITHUB_CLIENT_ID or OAUTH_GITHUB_CLIENT_SECRET environment variables are not set.\x1B[0m"
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
warningShown = true;
|
|
102
|
-
}
|
|
103
|
-
if (url === loginRoute) {
|
|
104
|
-
const result = handleOAuthLogin();
|
|
105
|
-
res.writeHead(result.statusCode, result.headers);
|
|
106
|
-
res.end(result.body);
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
if (url?.startsWith(callbackRoute)) {
|
|
110
|
-
const urlParams = new URLSearchParams(url.split("?")[1]);
|
|
111
|
-
const code = urlParams.get("code");
|
|
112
|
-
if (!code) {
|
|
113
|
-
res.writeHead(400, { "Content-Type": "text/html" });
|
|
114
|
-
res.end("<html><body><h1>Error</h1><p>No code provided</p></body></html>");
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
const result = await handleOAuthCallback(code);
|
|
118
|
-
res.writeHead(result.statusCode, result.headers);
|
|
119
|
-
res.end(result.body);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
next();
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
1
|
// src/plugin.ts
|
|
129
|
-
import { mkdir, readdir, writeFile } from "fs/promises";
|
|
2
|
+
import fs, { mkdir, readdir, writeFile } from "fs/promises";
|
|
130
3
|
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
131
5
|
import { loadConfigFromFile } from "vite";
|
|
132
6
|
import YAML from "yaml";
|
|
133
7
|
|
|
@@ -147,6 +21,76 @@ var index_template_default = `<!DOCTYPE html>
|
|
|
147
21
|
</html>`;
|
|
148
22
|
|
|
149
23
|
// src/plugin.ts
|
|
24
|
+
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
async function updateAstroConfigWithOAuthEnv(root) {
|
|
26
|
+
try {
|
|
27
|
+
const astroConfigPath = path.join(root, "astro.config.mjs");
|
|
28
|
+
const configContent = await fs.readFile(astroConfigPath, "utf-8");
|
|
29
|
+
if (configContent.includes("OAUTH_GITHUB_CLIENT_ID") && configContent.includes("OAUTH_GITHUB_CLIENT_SECRET")) {
|
|
30
|
+
console.log("OAuth environment variables already exist in astro.config.mjs");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
let updatedContent = configContent;
|
|
34
|
+
if (!configContent.includes("env:")) {
|
|
35
|
+
const envConfig = ` env: {
|
|
36
|
+
schema: {
|
|
37
|
+
OAUTH_GITHUB_CLIENT_ID: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
context: 'server',
|
|
40
|
+
access: 'secret',
|
|
41
|
+
},
|
|
42
|
+
OAUTH_GITHUB_CLIENT_SECRET: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
context: 'server',
|
|
45
|
+
access: 'secret',
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
},`;
|
|
49
|
+
if (configContent.includes("output:")) {
|
|
50
|
+
updatedContent = configContent.replace(/( {2})output:/, `${envConfig}
|
|
51
|
+
$1output:`);
|
|
52
|
+
} else {
|
|
53
|
+
updatedContent = configContent.replace(/(defineConfig\(\{[^}]*)(\}\);)/, `$1 ${envConfig}
|
|
54
|
+
$2`);
|
|
55
|
+
}
|
|
56
|
+
} else if (!configContent.includes("schema:")) {
|
|
57
|
+
const schemaConfig = ` schema: {
|
|
58
|
+
OAUTH_GITHUB_CLIENT_ID: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
context: 'server',
|
|
61
|
+
access: 'secret',
|
|
62
|
+
},
|
|
63
|
+
OAUTH_GITHUB_CLIENT_SECRET: {
|
|
64
|
+
type: 'string',
|
|
65
|
+
context: 'server',
|
|
66
|
+
access: 'secret',
|
|
67
|
+
}
|
|
68
|
+
},`;
|
|
69
|
+
updatedContent = configContent.replace(/( {2}env: \{)/, `$1
|
|
70
|
+
${schemaConfig}`);
|
|
71
|
+
} else {
|
|
72
|
+
const oauthVars = ` OAUTH_GITHUB_CLIENT_ID: {
|
|
73
|
+
type: 'string',
|
|
74
|
+
context: 'server',
|
|
75
|
+
access: 'secret',
|
|
76
|
+
},
|
|
77
|
+
OAUTH_GITHUB_CLIENT_SECRET: {
|
|
78
|
+
type: 'string',
|
|
79
|
+
context: 'server',
|
|
80
|
+
access: 'secret',
|
|
81
|
+
},`;
|
|
82
|
+
updatedContent = configContent.replace(
|
|
83
|
+
/(schema: \{[^}]*\},)/,
|
|
84
|
+
`$1
|
|
85
|
+
${oauthVars}`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
await fs.writeFile(astroConfigPath, updatedContent, "utf-8");
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error("Error updating astro.config.mjs:", error);
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
150
94
|
function defineConfig(config) {
|
|
151
95
|
return config;
|
|
152
96
|
}
|
|
@@ -276,6 +220,14 @@ async function createFolderIfNotExists(path2) {
|
|
|
276
220
|
await mkdir(path2, { recursive: true });
|
|
277
221
|
}
|
|
278
222
|
}
|
|
223
|
+
async function verifyFileExists(filePath) {
|
|
224
|
+
try {
|
|
225
|
+
await fs.access(filePath);
|
|
226
|
+
return true;
|
|
227
|
+
} catch {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
279
231
|
async function saveConfig(document, pathTo) {
|
|
280
232
|
await writeFile(pathTo, document);
|
|
281
233
|
}
|
|
@@ -311,11 +263,25 @@ async function getConfigFile(root, configFile) {
|
|
|
311
263
|
}
|
|
312
264
|
function createIndex(title, iconUrl, useIdentityWidget, type = "sveltia") {
|
|
313
265
|
const icon = iconUrl ? `<link rel="icon" type="image/svg+xml" href="${iconUrl}" />` : "";
|
|
314
|
-
const identity = useIdentityWidget ? `<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>` : "";
|
|
315
|
-
const script = type === "decap" ? `<script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>` : `<script src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>`;
|
|
266
|
+
const identity = useIdentityWidget ? `<script is:inline src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>` : "";
|
|
267
|
+
const script = type === "decap" ? `<script is:inline src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>` : `<script is:inline src="https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js"></script>`;
|
|
316
268
|
const document = index_template_default.replace("{{ script }}", script).replace("{{ title }}", title).replace("{{ icon }}", icon).replace("{{ identity }}", identity);
|
|
317
269
|
return document;
|
|
318
270
|
}
|
|
271
|
+
async function createOAuthFiles(root) {
|
|
272
|
+
const oauthFiles = ["config.ts", "index.ts", "callback.ts"];
|
|
273
|
+
const oauthFolder = path.join(root, "src", "oauth");
|
|
274
|
+
await createFolderIfNotExists(oauthFolder);
|
|
275
|
+
for (const file of oauthFiles) {
|
|
276
|
+
const sourcePath = path.join(__dirname, "..", "src", "oauth", file);
|
|
277
|
+
const destPath = path.join(oauthFolder, file);
|
|
278
|
+
const fileExists = await verifyFileExists(destPath);
|
|
279
|
+
if (fileExists)
|
|
280
|
+
continue;
|
|
281
|
+
const content = await fs.readFile(sourcePath, "utf-8");
|
|
282
|
+
await writeFile(destPath, content);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
319
285
|
async function createConfig(root, entry) {
|
|
320
286
|
const {
|
|
321
287
|
configFile = "cms.config",
|
|
@@ -325,16 +291,25 @@ async function createConfig(root, entry) {
|
|
|
325
291
|
title = "Admin",
|
|
326
292
|
iconUrl = "https://decapcms.org/img/decap-logo.svg",
|
|
327
293
|
useIdentityWidget = false,
|
|
328
|
-
type = "sveltia"
|
|
294
|
+
type = "sveltia",
|
|
295
|
+
oauth = false
|
|
329
296
|
} = entry ?? {};
|
|
330
297
|
const resolvedConfig = config ?? await getConfigFile(root, configFile);
|
|
331
298
|
await createFolderIfNotExists(path.join(root, saveFolder));
|
|
332
299
|
const document = YAML.stringify(resolvedConfig);
|
|
333
300
|
await saveConfig(document, path.join(root, saveFolder, "config.yml"));
|
|
334
|
-
if (
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
301
|
+
if (createIndexHTML) {
|
|
302
|
+
const indexHTML = createIndex(title, iconUrl, useIdentityWidget, type);
|
|
303
|
+
const fileExists = await verifyFileExists(path.join(root, "src", "admin", "index.astro"));
|
|
304
|
+
if (!fileExists) {
|
|
305
|
+
await createFolderIfNotExists(path.join(root, "src", "admin"));
|
|
306
|
+
await saveConfig(indexHTML, path.join(root, "src", "admin", "index.astro"));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (oauth) {
|
|
310
|
+
await createOAuthFiles(root);
|
|
311
|
+
await updateAstroConfigWithOAuthEnv(root);
|
|
312
|
+
}
|
|
338
313
|
}
|
|
339
314
|
async function plugin_default(entry) {
|
|
340
315
|
let root = "";
|
|
@@ -362,39 +337,6 @@ async function plugin_default(entry) {
|
|
|
362
337
|
};
|
|
363
338
|
}
|
|
364
339
|
|
|
365
|
-
// src/astro-oauth-integration.ts
|
|
366
|
-
var defaultOptions = {
|
|
367
|
-
loginRoute: "/oauth",
|
|
368
|
-
callbackRoute: "/oauth/callback",
|
|
369
|
-
disabled: false
|
|
370
|
-
};
|
|
371
|
-
function githubOAuthIntegration(options) {
|
|
372
|
-
const { loginRoute, callbackRoute, disabled } = { ...defaultOptions, ...options };
|
|
373
|
-
if (!loginRoute?.startsWith("/") || !callbackRoute?.startsWith("/")) {
|
|
374
|
-
throw new Error('`loginRoute` and `callbackRoute` options must start with "/"');
|
|
375
|
-
}
|
|
376
|
-
return {
|
|
377
|
-
name: "github-oauth-integration",
|
|
378
|
-
hooks: {
|
|
379
|
-
"astro:config:setup": async ({ injectRoute }) => {
|
|
380
|
-
if (disabled) {
|
|
381
|
-
return;
|
|
382
|
-
}
|
|
383
|
-
injectRoute({
|
|
384
|
-
pattern: loginRoute,
|
|
385
|
-
entrypoint: "@caiquecamargo/vite-plugin-netlify-cms/src/oauth/astro-login.ts",
|
|
386
|
-
prerender: false
|
|
387
|
-
});
|
|
388
|
-
injectRoute({
|
|
389
|
-
pattern: callbackRoute,
|
|
390
|
-
entrypoint: "@caiquecamargo/vite-plugin-netlify-cms/src/oauth/astro-callback.ts",
|
|
391
|
-
prerender: false
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
|
|
398
340
|
// index.ts
|
|
399
341
|
var index_default = plugin_default;
|
|
400
342
|
export {
|
|
@@ -425,7 +367,6 @@ export {
|
|
|
425
367
|
defineStringWidget,
|
|
426
368
|
defineTextWidget,
|
|
427
369
|
defineUuidWidget,
|
|
428
|
-
|
|
429
|
-
oauthPlugin
|
|
370
|
+
updateAstroConfigWithOAuthEnv
|
|
430
371
|
};
|
|
431
372
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/oauth/config.ts","../src/oauth/callback.ts","../src/oauth/login.ts","../src/oauth-plugin.ts","../src/plugin.ts","../src/index.template.ts","../src/astro-oauth-integration.ts","../index.ts"],"sourcesContent":["export const clientId = process.env.OAUTH_GITHUB_CLIENT_ID;\nexport const clientSecret = process.env.OAUTH_GITHUB_CLIENT_SECRET;\n\nexport const authUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&scope=repo,user`;\nexport const tokenUrl = 'https://github.com/login/oauth/access_token';\n","import { clientId, clientSecret, tokenUrl } from './config';\n\n/**\n * OAuth callback handler - exchanges code for access token\n */\nexport async function handleOAuthCallback(code: string) {\n const data = {\n code,\n client_id: clientId,\n client_secret: clientSecret,\n };\n\n try {\n const response = await fetch(tokenUrl, {\n method: 'POST',\n headers: {\n 'Accept': 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(data),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n const body = await response.json();\n\n const content = {\n token: body.access_token,\n provider: 'github',\n };\n\n // Return HTML with postMessage script to communicate with CMS\n const script = `\n <script>\n const receiveMessage = (message) => {\n window.opener.postMessage(\n 'authorization:${content.provider}:success:${JSON.stringify(content)}',\n message.origin\n );\n\n window.removeEventListener(\"message\", receiveMessage, false);\n }\n\n window.addEventListener(\"message\", receiveMessage, false);\n\n window.opener.postMessage(\"authorizing:${content.provider}\", \"*\");\n </script>\n `;\n\n return {\n statusCode: 200,\n headers: {\n 'Content-Type': 'text/html',\n },\n body: script,\n };\n }\n catch (err) {\n console.error('OAuth callback error:', err);\n return {\n statusCode: 500,\n headers: {\n 'Content-Type': 'text/html',\n },\n body: '<html><body><h1>OAuth Error</h1><p>Authentication failed. Please close this window and try again.</p></body></html>',\n };\n }\n}\n","import { authUrl } from './config';\n\n/**\n * OAuth login handler - redirects to GitHub authorization\n */\nexport function handleOAuthLogin() {\n return {\n statusCode: 302,\n headers: {\n Location: authUrl,\n },\n body: '',\n };\n}\n","import type { Plugin } from 'vite';\nimport { handleOAuthCallback } from './oauth/callback';\nimport { clientId, clientSecret } from './oauth/config';\nimport { handleOAuthLogin } from './oauth/login';\n\nexport interface OAuthPluginOptions {\n /**\n * OAuth login route\n * @default '/oauth'\n */\n loginRoute?: string;\n\n /**\n * OAuth callback route\n * @default '/oauth/callback'\n */\n callbackRoute?: string;\n\n /**\n * Disable OAuth plugin\n * @default false\n */\n disabled?: boolean;\n}\n\n/**\n * Vite plugin for OAuth authentication routes\n * Adds /oauth and /oauth/callback routes for GitHub authentication\n */\nexport default function oauthPlugin(options?: OAuthPluginOptions): Plugin {\n const {\n loginRoute = '/oauth',\n callbackRoute = '/oauth/callback',\n disabled = false,\n } = options ?? {};\n\n if (disabled) {\n return {\n name: 'vite-plugin-oauth',\n };\n }\n\n let warningShown = false;\n\n return {\n name: 'vite-plugin-oauth',\n configureServer(server) {\n server.middlewares.use(async (req, res, next) => {\n const url = req.url;\n\n // Show warning once if environment variables are not set\n if (!warningShown) {\n if (!clientId || !clientSecret) {\n console.warn(\n '\\x1B[33m⚠ OAuth plugin enabled but OAUTH_GITHUB_CLIENT_ID or OAUTH_GITHUB_CLIENT_SECRET environment variables are not set.\\x1B[0m',\n );\n }\n warningShown = true;\n }\n\n // Handle OAuth login route\n if (url === loginRoute) {\n const result = handleOAuthLogin();\n res.writeHead(result.statusCode, result.headers);\n res.end(result.body);\n return;\n }\n\n // Handle OAuth callback route\n if (url?.startsWith(callbackRoute)) {\n const urlParams = new URLSearchParams(url.split('?')[1]);\n const code = urlParams.get('code');\n\n if (!code) {\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end('<html><body><h1>Error</h1><p>No code provided</p></body></html>');\n return;\n }\n\n const result = await handleOAuthCallback(code);\n res.writeHead(result.statusCode, result.headers);\n res.end(result.body);\n return;\n }\n\n next();\n });\n },\n };\n}\n","import type { Plugin } from 'vite';\nimport type {\n BooleanWidget,\n CodeWidget,\n ColorWidget,\n ComputeWidget,\n DateTimeWidget,\n FileCollection,\n FileCollectionEntry,\n FileWidget,\n FolderCollection,\n HiddenWidget,\n ImageWidget,\n KeyValueWidget,\n ListWidget,\n MapWidget,\n MarkdownWidget,\n NetlifyCMSConfig,\n NumberWidget,\n ObjectWidget,\n RelationWidget,\n RichTextWidget,\n SelectWidget,\n StringWidget,\n TextWidget,\n UuidWidget,\n} from './types';\nimport { mkdir, readdir, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { loadConfigFromFile } from 'vite';\nimport YAML from 'yaml';\nimport indexHTMLTemplate from './index.template';\n\nexport function defineConfig(config: NetlifyCMSConfig): NetlifyCMSConfig {\n return config;\n}\nexport function defineFolderCollection(collection: FolderCollection) {\n return collection;\n}\nexport const defineFileCollection = (collection: FileCollection) => collection;\nexport const defineFileCollectionEntry = (collection: FileCollectionEntry) => collection;\nexport function defineBooleanWidget(widget: Omit<BooleanWidget, 'widget'>): BooleanWidget {\n return {\n widget: 'boolean',\n ...widget,\n };\n}\nexport function defineCodeWidget(widget: Omit<CodeWidget, 'widget'>): CodeWidget {\n return {\n widget: 'code',\n ...widget,\n };\n}\nexport function defineColorWidget(widget: Omit<ColorWidget, 'widget'>): ColorWidget {\n return {\n widget: 'color',\n ...widget,\n };\n}\nexport function defineComputeWidget(widget: Omit<ComputeWidget, 'widget'>): ComputeWidget {\n return {\n widget: 'compute',\n ...widget,\n };\n}\nexport function defineDateTimeWidget(widget: Omit<DateTimeWidget, 'widget'>): DateTimeWidget {\n return { widget: 'datetime', ...widget };\n}\nexport function defineHiddenWidget(widget: Omit<HiddenWidget, 'widget'>): HiddenWidget {\n return {\n widget: 'hidden',\n ...widget,\n };\n}\nexport function defineFileWidget(widget: Omit<FileWidget, 'widget'>): FileWidget {\n return {\n widget: 'file',\n ...widget,\n };\n}\nexport function defineImageWidget(widget: Omit<ImageWidget, 'widget'>): ImageWidget {\n return {\n widget: 'image',\n ...widget,\n };\n}\nexport function defineKeyValueWidget(widget: Omit<KeyValueWidget, 'widget'>): KeyValueWidget {\n return {\n widget: 'keyvalue',\n ...widget,\n };\n}\nexport function defineListWidget(widget: Omit<ListWidget, 'widget'>): ListWidget {\n return {\n widget: 'list',\n ...widget,\n };\n}\nexport function defineMapWidget(widget: Omit<MapWidget, 'widget'>): MapWidget {\n return {\n widget: 'map',\n ...widget,\n };\n}\nexport function defineNumberWidget(widget: Omit<NumberWidget, 'widget'>): NumberWidget {\n return {\n widget: 'number',\n ...widget,\n };\n}\nexport function defineObjectWidget(widget: Omit<ObjectWidget, 'widget'>): ObjectWidget {\n return {\n widget: 'object',\n ...widget,\n };\n}\nexport function defineRelationWidget(widget: Omit<RelationWidget, 'widget'>): RelationWidget {\n return { widget: 'relation', ...widget };\n}\nexport function defineSelectWidget(widget: Omit<SelectWidget, 'widget'>): SelectWidget {\n return {\n widget: 'select',\n ...widget,\n };\n}\nexport function defineStringWidget(widget: Omit<StringWidget, 'widget'>): StringWidget {\n return {\n widget: 'string',\n ...widget,\n };\n}\nexport function defineTextWidget(widget: Omit<TextWidget, 'widget'>): TextWidget {\n return {\n widget: 'text',\n ...widget,\n };\n}\nexport function defineMarkdownWidget(widget: Omit<MarkdownWidget, 'widget'>): MarkdownWidget {\n return {\n widget: 'markdown',\n ...widget,\n };\n}\nexport function defineRichTextWidget(widget: Omit<RichTextWidget, 'widget'>): RichTextWidget {\n return {\n widget: 'richtext',\n ...widget,\n };\n}\nexport function defineUuidWidget(widget: Omit<UuidWidget, 'widget'>): UuidWidget {\n return {\n widget: 'uuid',\n ...widget,\n };\n}\n\nexport interface NetlifyCMSEntry {\n /**\n * Name of config file\n *\n * @default cms.config\n */\n configFile?: string;\n\n /**\n * Netlify CMS config object\n */\n config?: NetlifyCMSConfig;\n\n /**\n * Folder to save config file\n *\n * @default ./public/admin\n */\n saveFolder?: string;\n\n /**\n * If has to create index.html file in the save folder\n */\n createIndexHTML?: boolean;\n\n /**\n * Title of the admin page\n *\n * @default Admin\n */\n title?: string;\n\n /**\n * Icon URL of the admin page\n *\n * @default https://decapcms.org/img/decap-logo.svg\n */\n iconUrl?: string;\n\n /**\n * If has to use identity widget\n *\n * @default true\n */\n useIdentityWidget?: boolean;\n\n /**\n * Type of CMS to generate config for\n *\n * @default 'sveltia'\n */\n type?: 'decap' | 'sveltia';\n}\n\nasync function createFolderIfNotExists(path: string) {\n try {\n await readdir(path);\n }\n catch {\n await mkdir(path, { recursive: true });\n }\n}\n\nasync function saveConfig(document: string, pathTo: string) {\n await writeFile(pathTo, document);\n}\n\nfunction resolveConfigFilePath(configFile: string) {\n const _path = configFile.startsWith('.') ? configFile.slice(2) : configFile;\n\n if (!_path)\n return configFile;\n if (['ts', 'js', 'cjs', 'mjs'].some(ext => _path.includes(ext)))\n return _path.split('.').slice(0, -1).join('.');\n\n return _path;\n}\n\nasync function getConfigFile(root: string, configFile: string): Promise<NetlifyCMSConfig> {\n try {\n const files = await readdir(root);\n const configPath = resolveConfigFilePath(configFile);\n\n if (configPath.includes('/')) {\n const [folder, file] = configPath.split('/');\n return await getConfigFile(path.join(root, folder), file);\n }\n\n const file = files.find(file => file.startsWith(configPath));\n\n if (!file)\n throw new Error(`Config file not found`);\n\n const { config }\n = (await loadConfigFromFile(\n { command: 'build', mode: '' },\n path.join(root, file),\n )) ?? {};\n\n if (!config)\n throw new Error(`Config file not found`);\n\n return config as NetlifyCMSConfig;\n }\n catch {\n throw new Error(`Config file not found`);\n }\n}\n\nfunction createIndex(title: string, iconUrl: string, useIdentityWidget: boolean, type: 'decap' | 'sveltia' = 'sveltia') {\n const icon = iconUrl ? `<link rel=\"icon\" type=\"image/svg+xml\" href=\"${iconUrl}\" />` : '';\n const identity = useIdentityWidget ? `<script src=\"https://identity.netlify.com/v1/netlify-identity-widget.js\"></script>` : '';\n\n const script = type === 'decap'\n ? `<script src=\"https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js\"></script>`\n : `<script src=\"https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js\"></script>`;\n\n const document = indexHTMLTemplate\n .replace('{{ script }}', script)\n .replace('{{ title }}', title)\n .replace('{{ icon }}', icon)\n .replace('{{ identity }}', identity);\n\n return document;\n}\n\nexport async function createConfig(root: string, entry?: NetlifyCMSEntry) {\n const {\n configFile = 'cms.config',\n config,\n saveFolder = './public/admin',\n createIndexHTML = true,\n title = 'Admin',\n iconUrl = 'https://decapcms.org/img/decap-logo.svg',\n useIdentityWidget = false,\n type = 'sveltia',\n } = entry ?? {};\n\n const resolvedConfig = config ?? (await getConfigFile(root, configFile));\n await createFolderIfNotExists(path.join(root, saveFolder));\n\n const document = YAML.stringify(resolvedConfig);\n await saveConfig(document, path.join(root, saveFolder, 'config.yml'));\n\n if (!createIndexHTML)\n return;\n\n const indexHTML = createIndex(title, iconUrl, useIdentityWidget, type);\n await saveConfig(indexHTML, path.join(root, saveFolder, 'index.html'));\n}\n\nexport default async function (entry?: NetlifyCMSEntry): Promise<Plugin> {\n let root = '';\n\n return {\n name: 'vite-plugin-netlify-cms',\n configResolved: (config) => {\n root = config.root;\n },\n buildStart: async () => {\n try {\n await createConfig(root, entry);\n }\n catch (error) {\n console.log(error);\n }\n },\n handleHotUpdate: async ({ file }) => {\n if (file.includes(entry?.configFile ?? 'cms.config')) {\n try {\n await createConfig(root, entry);\n }\n catch (error) {\n console.log(error);\n }\n }\n },\n };\n}\n","export default `<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>{{ title }}</title>\n {{ icon }}\n {{ identity }}\n </head>\n <body>\n {{ script }}\n </body>\n</html>`;\n","export interface AstroOAuthOptions {\n /**\n * OAuth login route\n * @default '/oauth'\n */\n loginRoute?: string;\n\n /**\n * OAuth callback route\n * @default '/oauth/callback'\n */\n callbackRoute?: string;\n\n /**\n * Disable OAuth integration\n * @default false\n */\n disabled?: boolean;\n}\n\nconst defaultOptions: AstroOAuthOptions = {\n loginRoute: '/oauth',\n callbackRoute: '/oauth/callback',\n disabled: false,\n};\n\n/**\n * Astro integration for OAuth authentication routes\n * Adds /oauth and /oauth/callback routes for GitHub authentication\n *\n * @example\n * ```ts\n * import { defineConfig } from 'astro/config';\n * import { githubOAuthIntegration } from 'vite-plugin-netlify-cms';\n *\n * export default defineConfig({\n * integrations: [githubOAuthIntegration()],\n * output: 'server', // or 'hybrid'\n * });\n * ```\n */\nexport function githubOAuthIntegration(options?: AstroOAuthOptions): any {\n const { loginRoute, callbackRoute, disabled } = { ...defaultOptions, ...options };\n\n if (!loginRoute?.startsWith('/') || !callbackRoute?.startsWith('/')) {\n throw new Error('`loginRoute` and `callbackRoute` options must start with \"/\"');\n }\n\n return {\n name: 'github-oauth-integration',\n hooks: {\n 'astro:config:setup': async ({ injectRoute }: any) => {\n if (disabled) {\n return;\n }\n\n // Inject OAuth login route\n injectRoute({\n pattern: loginRoute,\n entrypoint: '@caiquecamargo/vite-plugin-netlify-cms/src/oauth/astro-login.ts',\n prerender: false,\n });\n\n // Inject OAuth callback route\n injectRoute({\n pattern: callbackRoute,\n entrypoint: '@caiquecamargo/vite-plugin-netlify-cms/src/oauth/astro-callback.ts',\n prerender: false,\n });\n },\n },\n };\n}\n","import oauthPlugin from './src/oauth-plugin.js';\nimport cmsPlugin from './src/plugin.js';\n\nexport * from './src/astro-oauth-integration.js';\nexport * from './src/oauth-plugin.js';\nexport * from './src/plugin.js';\nexport * from './src/types.js';\n\nexport { cmsPlugin, oauthPlugin };\nexport default cmsPlugin;\n"],"mappings":"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","names":["path","file"]}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/index.template.ts","../index.ts"],"sourcesContent":["import type { Plugin } from 'vite';\nimport type {\n BooleanWidget,\n CodeWidget,\n ColorWidget,\n ComputeWidget,\n DateTimeWidget,\n FileCollection,\n FileCollectionEntry,\n FileWidget,\n FolderCollection,\n HiddenWidget,\n ImageWidget,\n KeyValueWidget,\n ListWidget,\n MapWidget,\n MarkdownWidget,\n NetlifyCMSConfig,\n NumberWidget,\n ObjectWidget,\n RelationWidget,\n RichTextWidget,\n SelectWidget,\n StringWidget,\n TextWidget,\n UuidWidget,\n} from './types';\nimport { verify } from 'node:crypto';\nimport fs, { mkdir, readdir, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { loadConfigFromFile } from 'vite';\nimport YAML from 'yaml';\nimport indexHTMLTemplate from './index.template';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nexport async function updateAstroConfigWithOAuthEnv(root: string): Promise<void> {\n try {\n const astroConfigPath = path.join(root, 'astro.config.mjs');\n const configContent = await fs.readFile(astroConfigPath, 'utf-8');\n\n // Verifica se já possui as variáveis OAuth\n if (configContent.includes('OAUTH_GITHUB_CLIENT_ID')\n && configContent.includes('OAUTH_GITHUB_CLIENT_SECRET')) {\n console.log('OAuth environment variables already exist in astro.config.mjs');\n return;\n }\n\n let updatedContent = configContent;\n\n // Verifica se existe a propriedade env\n if (!configContent.includes('env:')) {\n // Adiciona a propriedade env completa antes de output ou no final do defineConfig\n const envConfig = ` env: {\n schema: {\n OAUTH_GITHUB_CLIENT_ID: {\n type: 'string',\n context: 'server',\n access: 'secret',\n },\n OAUTH_GITHUB_CLIENT_SECRET: {\n type: 'string',\n context: 'server',\n access: 'secret',\n }\n },\n },`;\n\n if (configContent.includes('output:')) {\n updatedContent = configContent.replace(/( {2})output:/, `${envConfig}\\n$1output:`);\n }\n else {\n updatedContent = configContent.replace(/(defineConfig\\(\\{[^}]*)(\\}\\);)/, `$1 ${envConfig}\\n$2`);\n }\n }\n else if (!configContent.includes('schema:')) {\n // Adiciona schema dentro de env existente\n const schemaConfig = ` schema: {\n OAUTH_GITHUB_CLIENT_ID: {\n type: 'string',\n context: 'server',\n access: 'secret',\n },\n OAUTH_GITHUB_CLIENT_SECRET: {\n type: 'string',\n context: 'server',\n access: 'secret',\n }\n },`;\n\n updatedContent = configContent.replace(/( {2}env: \\{)/, `$1\\n${schemaConfig}`);\n }\n else {\n // Adiciona as variáveis dentro de schema existente\n const oauthVars = ` OAUTH_GITHUB_CLIENT_ID: {\n type: 'string',\n context: 'server',\n access: 'secret',\n },\n OAUTH_GITHUB_CLIENT_SECRET: {\n type: 'string',\n context: 'server',\n access: 'secret',\n },`;\n\n // Encontra o último campo do schema e adiciona as novas variáveis\n updatedContent = configContent.replace(\n /(schema: \\{[^}]*\\},)/,\n `$1\\n${oauthVars}`,\n );\n }\n\n await fs.writeFile(astroConfigPath, updatedContent, 'utf-8');\n }\n catch (error) {\n console.error('Error updating astro.config.mjs:', error);\n throw error;\n }\n}\n\nexport function defineConfig(config: NetlifyCMSConfig): NetlifyCMSConfig {\n return config;\n}\nexport function defineFolderCollection(collection: FolderCollection) {\n return collection;\n}\nexport const defineFileCollection = (collection: FileCollection) => collection;\nexport const defineFileCollectionEntry = (collection: FileCollectionEntry) => collection;\nexport function defineBooleanWidget(widget: Omit<BooleanWidget, 'widget'>): BooleanWidget {\n return {\n widget: 'boolean',\n ...widget,\n };\n}\nexport function defineCodeWidget(widget: Omit<CodeWidget, 'widget'>): CodeWidget {\n return {\n widget: 'code',\n ...widget,\n };\n}\nexport function defineColorWidget(widget: Omit<ColorWidget, 'widget'>): ColorWidget {\n return {\n widget: 'color',\n ...widget,\n };\n}\nexport function defineComputeWidget(widget: Omit<ComputeWidget, 'widget'>): ComputeWidget {\n return {\n widget: 'compute',\n ...widget,\n };\n}\nexport function defineDateTimeWidget(widget: Omit<DateTimeWidget, 'widget'>): DateTimeWidget {\n return { widget: 'datetime', ...widget };\n}\nexport function defineHiddenWidget(widget: Omit<HiddenWidget, 'widget'>): HiddenWidget {\n return {\n widget: 'hidden',\n ...widget,\n };\n}\nexport function defineFileWidget(widget: Omit<FileWidget, 'widget'>): FileWidget {\n return {\n widget: 'file',\n ...widget,\n };\n}\nexport function defineImageWidget(widget: Omit<ImageWidget, 'widget'>): ImageWidget {\n return {\n widget: 'image',\n ...widget,\n };\n}\nexport function defineKeyValueWidget(widget: Omit<KeyValueWidget, 'widget'>): KeyValueWidget {\n return {\n widget: 'keyvalue',\n ...widget,\n };\n}\nexport function defineListWidget(widget: Omit<ListWidget, 'widget'>): ListWidget {\n return {\n widget: 'list',\n ...widget,\n };\n}\nexport function defineMapWidget(widget: Omit<MapWidget, 'widget'>): MapWidget {\n return {\n widget: 'map',\n ...widget,\n };\n}\nexport function defineNumberWidget(widget: Omit<NumberWidget, 'widget'>): NumberWidget {\n return {\n widget: 'number',\n ...widget,\n };\n}\nexport function defineObjectWidget(widget: Omit<ObjectWidget, 'widget'>): ObjectWidget {\n return {\n widget: 'object',\n ...widget,\n };\n}\nexport function defineRelationWidget(widget: Omit<RelationWidget, 'widget'>): RelationWidget {\n return { widget: 'relation', ...widget };\n}\nexport function defineSelectWidget(widget: Omit<SelectWidget, 'widget'>): SelectWidget {\n return {\n widget: 'select',\n ...widget,\n };\n}\nexport function defineStringWidget(widget: Omit<StringWidget, 'widget'>): StringWidget {\n return {\n widget: 'string',\n ...widget,\n };\n}\nexport function defineTextWidget(widget: Omit<TextWidget, 'widget'>): TextWidget {\n return {\n widget: 'text',\n ...widget,\n };\n}\nexport function defineMarkdownWidget(widget: Omit<MarkdownWidget, 'widget'>): MarkdownWidget {\n return {\n widget: 'markdown',\n ...widget,\n };\n}\nexport function defineRichTextWidget(widget: Omit<RichTextWidget, 'widget'>): RichTextWidget {\n return {\n widget: 'richtext',\n ...widget,\n };\n}\nexport function defineUuidWidget(widget: Omit<UuidWidget, 'widget'>): UuidWidget {\n return {\n widget: 'uuid',\n ...widget,\n };\n}\n\nexport interface NetlifyCMSEntry {\n /**\n * Name of config file\n *\n * @default cms.config\n */\n configFile?: string;\n\n /**\n * Netlify CMS config object\n */\n config?: NetlifyCMSConfig;\n\n /**\n * Folder to save config file\n *\n * @default ./public/admin\n */\n saveFolder?: string;\n\n /**\n * If has to create index.html file in the save folder\n */\n createIndexHTML?: boolean;\n\n /**\n * Title of the admin page\n *\n * @default Admin\n */\n title?: string;\n\n /**\n * Icon URL of the admin page\n *\n * @default https://decapcms.org/img/decap-logo.svg\n */\n iconUrl?: string;\n\n /**\n * If has to use identity widget\n *\n * @default true\n */\n useIdentityWidget?: boolean;\n\n /**\n * Type of CMS to generate config for\n *\n * @default 'sveltia'\n */\n type?: 'decap' | 'sveltia';\n\n oauth?: boolean;\n}\n\nasync function createFolderIfNotExists(path: string) {\n try {\n await readdir(path);\n }\n catch {\n await mkdir(path, { recursive: true });\n }\n}\n\nasync function verifyFileExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n }\n catch {\n return false;\n }\n}\n\nasync function saveConfig(document: string, pathTo: string) {\n await writeFile(pathTo, document);\n}\n\nfunction resolveConfigFilePath(configFile: string) {\n const _path = configFile.startsWith('.') ? configFile.slice(2) : configFile;\n\n if (!_path)\n return configFile;\n if (['ts', 'js', 'cjs', 'mjs'].some(ext => _path.includes(ext)))\n return _path.split('.').slice(0, -1).join('.');\n\n return _path;\n}\n\nasync function getConfigFile(root: string, configFile: string): Promise<NetlifyCMSConfig> {\n try {\n const files = await readdir(root);\n const configPath = resolveConfigFilePath(configFile);\n\n if (configPath.includes('/')) {\n const [folder, file] = configPath.split('/');\n return await getConfigFile(path.join(root, folder), file);\n }\n\n const file = files.find(file => file.startsWith(configPath));\n\n if (!file)\n throw new Error(`Config file not found`);\n\n const { config }\n = (await loadConfigFromFile(\n { command: 'build', mode: '' },\n path.join(root, file),\n )) ?? {};\n\n if (!config)\n throw new Error(`Config file not found`);\n\n return config as NetlifyCMSConfig;\n }\n catch {\n throw new Error(`Config file not found`);\n }\n}\n\nfunction createIndex(title: string, iconUrl: string, useIdentityWidget: boolean, type: 'decap' | 'sveltia' = 'sveltia') {\n const icon = iconUrl ? `<link rel=\"icon\" type=\"image/svg+xml\" href=\"${iconUrl}\" />` : '';\n const identity = useIdentityWidget ? `<script is:inline src=\"https://identity.netlify.com/v1/netlify-identity-widget.js\"></script>` : '';\n\n const script = type === 'decap'\n ? `<script is:inline src=\"https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js\"></script>`\n : `<script is:inline src=\"https://unpkg.com/@sveltia/cms/dist/sveltia-cms.js\"></script>`;\n\n const document = indexHTMLTemplate\n .replace('{{ script }}', script)\n .replace('{{ title }}', title)\n .replace('{{ icon }}', icon)\n .replace('{{ identity }}', identity);\n\n return document;\n}\n\nasync function createOAuthFiles(root: string) {\n const oauthFiles = ['config.ts', 'index.ts', 'callback.ts'];\n const oauthFolder = path.join(root, 'src', 'oauth');\n\n await createFolderIfNotExists(oauthFolder);\n\n for (const file of oauthFiles) {\n const sourcePath = path.join(__dirname, '..', 'src', 'oauth', file);\n const destPath = path.join(oauthFolder, file);\n\n const fileExists = await verifyFileExists(destPath);\n if (fileExists)\n continue;\n\n const content = await fs.readFile(sourcePath, 'utf-8');\n await writeFile(destPath, content);\n }\n}\n\nexport async function createConfig(root: string, entry?: NetlifyCMSEntry) {\n const {\n configFile = 'cms.config',\n config,\n saveFolder = './public/admin',\n createIndexHTML = true,\n title = 'Admin',\n iconUrl = 'https://decapcms.org/img/decap-logo.svg',\n useIdentityWidget = false,\n type = 'sveltia',\n oauth = false,\n } = entry ?? {};\n\n const resolvedConfig = config ?? (await getConfigFile(root, configFile));\n await createFolderIfNotExists(path.join(root, saveFolder));\n\n const document = YAML.stringify(resolvedConfig);\n await saveConfig(document, path.join(root, saveFolder, 'config.yml'));\n\n if (createIndexHTML) {\n const indexHTML = createIndex(title, iconUrl, useIdentityWidget, type);\n const fileExists = await verifyFileExists(path.join(root, 'src', 'admin', 'index.astro'));\n\n if (!fileExists) {\n await createFolderIfNotExists(path.join(root, 'src', 'admin'));\n await saveConfig(indexHTML, path.join(root, 'src', 'admin', 'index.astro'));\n }\n }\n\n if (oauth) {\n await createOAuthFiles(root);\n await updateAstroConfigWithOAuthEnv(root);\n }\n}\n\nexport default async function (entry?: NetlifyCMSEntry): Promise<Plugin> {\n let root = '';\n\n return {\n name: 'vite-plugin-netlify-cms',\n configResolved: (config) => {\n root = config.root;\n },\n buildStart: async () => {\n try {\n await createConfig(root, entry);\n }\n catch (error) {\n console.log(error);\n }\n },\n handleHotUpdate: async ({ file }) => {\n if (file.includes(entry?.configFile ?? 'cms.config')) {\n try {\n await createConfig(root, entry);\n }\n catch (error) {\n console.log(error);\n }\n }\n },\n };\n}\n","export default `<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>{{ title }}</title>\n {{ icon }}\n {{ identity }}\n </head>\n <body>\n {{ script }}\n </body>\n</html>`;\n","import cmsPlugin from './src/plugin.js';\n\nexport * from './src/plugin.js';\nexport * from './src/types.js';\n\nexport { cmsPlugin };\nexport default cmsPlugin;\n"],"mappings":"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","names":["path","file"]}
|
package/package.json
CHANGED
package/src/oauth/config.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { OAUTH_GITHUB_CLIENT_ID, OAUTH_GITHUB_CLIENT_SECRET } from 'astro:env/server';
|
|
2
|
+
|
|
3
|
+
export const clientId = OAUTH_GITHUB_CLIENT_ID;
|
|
4
|
+
export const clientSecret = OAUTH_GITHUB_CLIENT_SECRET;
|
|
3
5
|
|
|
4
6
|
export const authUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&scope=repo,user`;
|
|
5
7
|
export const tokenUrl = 'https://github.com/login/oauth/access_token';
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import type { APIRoute } from 'astro';
|
|
2
|
-
import { clientId, clientSecret, tokenUrl } from './config';
|
|
3
|
-
|
|
4
|
-
export const prerender = false;
|
|
5
|
-
|
|
6
|
-
export const GET: APIRoute = async ({ url, redirect }) => {
|
|
7
|
-
const code = url.searchParams.get('code');
|
|
8
|
-
|
|
9
|
-
if (!code) {
|
|
10
|
-
return new Response('<html><body><h1>Error</h1><p>No code provided</p></body></html>', {
|
|
11
|
-
status: 400,
|
|
12
|
-
headers: { 'Content-Type': 'text/html' },
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const data = {
|
|
17
|
-
code,
|
|
18
|
-
client_id: clientId,
|
|
19
|
-
client_secret: clientSecret,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const response = await fetch(tokenUrl, {
|
|
24
|
-
method: 'POST',
|
|
25
|
-
headers: {
|
|
26
|
-
'Accept': 'application/json',
|
|
27
|
-
'Content-Type': 'application/json',
|
|
28
|
-
},
|
|
29
|
-
body: JSON.stringify(data),
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
if (!response.ok) {
|
|
33
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const body = await response.json();
|
|
37
|
-
|
|
38
|
-
const content = {
|
|
39
|
-
token: body.access_token,
|
|
40
|
-
provider: 'github',
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// Return HTML with postMessage script to communicate with CMS
|
|
44
|
-
const script = `
|
|
45
|
-
<script>
|
|
46
|
-
const receiveMessage = (message) => {
|
|
47
|
-
window.opener.postMessage(
|
|
48
|
-
'authorization:${content.provider}:success:${JSON.stringify(content)}',
|
|
49
|
-
message.origin
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
window.removeEventListener("message", receiveMessage, false);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
window.addEventListener("message", receiveMessage, false);
|
|
56
|
-
|
|
57
|
-
window.opener.postMessage("authorizing:${content.provider}", "*");
|
|
58
|
-
</script>
|
|
59
|
-
`;
|
|
60
|
-
|
|
61
|
-
return new Response(script, {
|
|
62
|
-
headers: { 'Content-Type': 'text/html' },
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
catch (err) {
|
|
66
|
-
console.error('OAuth callback error:', err);
|
|
67
|
-
return redirect('/?error=oauth_failed');
|
|
68
|
-
}
|
|
69
|
-
};
|