create-authhero 0.34.0 โ 0.35.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/cloudflare/copy-assets.js +35 -0
- package/dist/create-authhero.js +238 -173
- package/dist/local/src/app.ts +3 -1
- package/package.json +1 -1
|
@@ -86,6 +86,41 @@ try {
|
|
|
86
86
|
);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
// Copy admin UI files from @authhero/react-admin package
|
|
90
|
+
const adminSourceDir = path.join(
|
|
91
|
+
__dirname,
|
|
92
|
+
"node_modules",
|
|
93
|
+
"@authhero",
|
|
94
|
+
"react-admin",
|
|
95
|
+
"dist",
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
if (fs.existsSync(adminSourceDir)) {
|
|
99
|
+
console.log("๐ฆ Copying admin UI assets...");
|
|
100
|
+
const adminTargetDir = path.join(targetDir, "admin");
|
|
101
|
+
copyDirectory(adminSourceDir, adminTargetDir);
|
|
102
|
+
|
|
103
|
+
// Inject runtime config into index.html
|
|
104
|
+
// Uses window.location.origin so the admin UI automatically points to its own server
|
|
105
|
+
const adminIndexPath = path.join(adminSourceDir, "index.html");
|
|
106
|
+
const adminHtml = fs.readFileSync(adminIndexPath, "utf-8")
|
|
107
|
+
.replace(/src="\.\/assets\//g, 'src="/admin/assets/')
|
|
108
|
+
.replace(/href="\.\/assets\//g, 'href="/admin/assets/');
|
|
109
|
+
const configScript = `<script>window.__AUTHHERO_ADMIN_CONFIG__={domain:window.location.origin,basePath:"/admin"}</script>`;
|
|
110
|
+
const injectedHtml = adminHtml.replace("</head>", configScript + "\n</head>");
|
|
111
|
+
|
|
112
|
+
// Write injected HTML to CDN assets (for direct /admin/ access)
|
|
113
|
+
fs.writeFileSync(path.join(adminTargetDir, "index.html"), injectedHtml);
|
|
114
|
+
|
|
115
|
+
// Write as TS module for worker to import (for SPA fallback on deep links)
|
|
116
|
+
const srcDir = path.join(__dirname, "src");
|
|
117
|
+
fs.writeFileSync(
|
|
118
|
+
path.join(srcDir, "admin-index-html.ts"),
|
|
119
|
+
`export default ${JSON.stringify(injectedHtml)};\n`,
|
|
120
|
+
);
|
|
121
|
+
console.log("โ
Admin UI assets copied and configured");
|
|
122
|
+
}
|
|
123
|
+
|
|
89
124
|
console.log(`โ
Assets copied to ${targetDir}`);
|
|
90
125
|
} catch (error) {
|
|
91
126
|
console.error("โ Error copying assets:", error.message);
|
package/dist/create-authhero.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Command as
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
2
|
+
import { Command as P } from "commander";
|
|
3
|
+
import m from "inquirer";
|
|
4
|
+
import s from "fs";
|
|
5
|
+
import i from "path";
|
|
6
6
|
import { spawn as E } from "child_process";
|
|
7
|
-
const D = new
|
|
7
|
+
const D = new P(), p = {
|
|
8
8
|
local: {
|
|
9
9
|
name: "Local (SQLite)",
|
|
10
10
|
description: "Local development setup with SQLite database - great for getting started",
|
|
11
11
|
templateDir: "local",
|
|
12
|
-
packageJson: (
|
|
13
|
-
const t =
|
|
12
|
+
packageJson: (n, e, r, a, o) => {
|
|
13
|
+
const t = a ? "workspace:*" : "latest";
|
|
14
14
|
return {
|
|
15
|
-
name:
|
|
15
|
+
name: n,
|
|
16
16
|
version: "1.0.0",
|
|
17
17
|
type: "module",
|
|
18
18
|
scripts: {
|
|
@@ -23,6 +23,7 @@ const D = new I(), i = {
|
|
|
23
23
|
},
|
|
24
24
|
dependencies: {
|
|
25
25
|
"@authhero/kysely-adapter": t,
|
|
26
|
+
...o && { "@authhero/react-admin": t },
|
|
26
27
|
"@authhero/widget": t,
|
|
27
28
|
"@hono/swagger-ui": "^0.5.0",
|
|
28
29
|
"@hono/zod-openapi": "^0.19.0",
|
|
@@ -48,10 +49,10 @@ const D = new I(), i = {
|
|
|
48
49
|
name: "Cloudflare Workers (D1)",
|
|
49
50
|
description: "Cloudflare Workers setup with D1 database",
|
|
50
51
|
templateDir: "cloudflare",
|
|
51
|
-
packageJson: (
|
|
52
|
-
const t =
|
|
52
|
+
packageJson: (n, e, r, a, o) => {
|
|
53
|
+
const t = a ? "workspace:*" : "latest";
|
|
53
54
|
return {
|
|
54
|
-
name:
|
|
55
|
+
name: n,
|
|
55
56
|
version: "1.0.0",
|
|
56
57
|
type: "module",
|
|
57
58
|
scripts: {
|
|
@@ -71,6 +72,7 @@ const D = new I(), i = {
|
|
|
71
72
|
dependencies: {
|
|
72
73
|
"@authhero/drizzle": t,
|
|
73
74
|
"@authhero/kysely-adapter": t,
|
|
75
|
+
...o && { "@authhero/react-admin": t },
|
|
74
76
|
"@authhero/widget": t,
|
|
75
77
|
"@hono/swagger-ui": "^0.5.0",
|
|
76
78
|
"@hono/zod-openapi": "^0.19.0",
|
|
@@ -96,10 +98,10 @@ const D = new I(), i = {
|
|
|
96
98
|
name: "AWS SST (Lambda + DynamoDB)",
|
|
97
99
|
description: "Serverless AWS deployment with Lambda, DynamoDB, and SST",
|
|
98
100
|
templateDir: "aws-sst",
|
|
99
|
-
packageJson: (
|
|
100
|
-
const t =
|
|
101
|
+
packageJson: (n, e, r, a, o) => {
|
|
102
|
+
const t = a ? "workspace:*" : "latest";
|
|
101
103
|
return {
|
|
102
|
-
name:
|
|
104
|
+
name: n,
|
|
103
105
|
version: "1.0.0",
|
|
104
106
|
type: "module",
|
|
105
107
|
scripts: {
|
|
@@ -111,6 +113,7 @@ const D = new I(), i = {
|
|
|
111
113
|
},
|
|
112
114
|
dependencies: {
|
|
113
115
|
"@authhero/aws": t,
|
|
116
|
+
...o && { "@authhero/react-admin": t },
|
|
114
117
|
"@authhero/widget": t,
|
|
115
118
|
"@aws-sdk/client-dynamodb": "^3.0.0",
|
|
116
119
|
"@aws-sdk/lib-dynamodb": "^3.0.0",
|
|
@@ -133,27 +136,28 @@ const D = new I(), i = {
|
|
|
133
136
|
seedFile: "seed.ts"
|
|
134
137
|
}
|
|
135
138
|
};
|
|
136
|
-
function N(
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
|
|
139
|
+
function N(n, e) {
|
|
140
|
+
s.readdirSync(n).forEach((a) => {
|
|
141
|
+
const o = i.join(n, a), t = i.join(e, a);
|
|
142
|
+
s.lstatSync(o).isDirectory() ? (s.mkdirSync(t, { recursive: !0 }), N(o, t)) : s.copyFileSync(o, t);
|
|
140
143
|
});
|
|
141
144
|
}
|
|
142
|
-
function
|
|
143
|
-
const
|
|
145
|
+
function R(n, e = !1, r = "authhero-local", a) {
|
|
146
|
+
const o = n ? "control_plane" : "main", t = n ? "Control Plane" : "Main", c = [
|
|
144
147
|
"https://manage.authhero.net/auth-callback",
|
|
145
148
|
"https://local.authhero.net/auth-callback",
|
|
146
149
|
"http://localhost:5173/auth-callback",
|
|
147
|
-
"https://localhost:3000/auth-callback"
|
|
150
|
+
"https://localhost:3000/auth-callback",
|
|
151
|
+
...a ? ["https://localhost:3000/admin/auth-callback"] : []
|
|
148
152
|
], d = e ? [
|
|
149
153
|
`https://localhost.emobix.co.uk:8443/test/a/${r}/callback`,
|
|
150
154
|
`https://localhost:8443/test/a/${r}/callback`
|
|
151
|
-
] : [],
|
|
155
|
+
] : [], f = [...c, ...d], h = [
|
|
152
156
|
"https://manage.authhero.net",
|
|
153
157
|
"https://local.authhero.net",
|
|
154
158
|
"http://localhost:5173",
|
|
155
159
|
"https://localhost:3000"
|
|
156
|
-
],
|
|
160
|
+
], C = e ? ["https://localhost:8443/", "https://localhost.emobix.co.uk:8443/"] : [], y = [...h, ...C], S = e ? `
|
|
157
161
|
// Create OpenID Conformance Suite test clients and user
|
|
158
162
|
console.log("Creating conformance test clients and user...");
|
|
159
163
|
|
|
@@ -171,7 +175,7 @@ function P(o, e = !1, r = "authhero-local") {
|
|
|
171
175
|
];
|
|
172
176
|
|
|
173
177
|
try {
|
|
174
|
-
await adapters.clients.create("${
|
|
178
|
+
await adapters.clients.create("${o}", {
|
|
175
179
|
client_id: "conformance-test",
|
|
176
180
|
client_secret: "conformanceTestSecret123",
|
|
177
181
|
name: "Conformance Test Client",
|
|
@@ -189,7 +193,7 @@ function P(o, e = !1, r = "authhero-local") {
|
|
|
189
193
|
}
|
|
190
194
|
|
|
191
195
|
try {
|
|
192
|
-
await adapters.clients.create("${
|
|
196
|
+
await adapters.clients.create("${o}", {
|
|
193
197
|
client_id: "conformance-test2",
|
|
194
198
|
client_secret: "conformanceTestSecret456",
|
|
195
199
|
name: "Conformance Test Client 2",
|
|
@@ -209,7 +213,7 @@ function P(o, e = !1, r = "authhero-local") {
|
|
|
209
213
|
// Create a conformance test user with ALL OIDC profile claims populated
|
|
210
214
|
// This is required for OIDCC-5.4 (VerifyScopesReturnedInUserInfoClaims) test
|
|
211
215
|
try {
|
|
212
|
-
await adapters.users.create("${
|
|
216
|
+
await adapters.users.create("${o}", {
|
|
213
217
|
user_id: \`\${USERNAME_PASSWORD_PROVIDER}|conformance-user\`,
|
|
214
218
|
email: "conformance@example.com",
|
|
215
219
|
email_verified: true,
|
|
@@ -244,7 +248,7 @@ function P(o, e = !1, r = "authhero-local") {
|
|
|
244
248
|
try {
|
|
245
249
|
const bcrypt = await import("bcryptjs");
|
|
246
250
|
const hashedPassword = await bcrypt.hash("ConformanceTest123!", 10);
|
|
247
|
-
await adapters.passwords.create("${
|
|
251
|
+
await adapters.passwords.create("${o}", {
|
|
248
252
|
user_id: \`\${USERNAME_PASSWORD_PROVIDER}|conformance-user\`,
|
|
249
253
|
password: hashedPassword,
|
|
250
254
|
});
|
|
@@ -276,27 +280,58 @@ async function main() {
|
|
|
276
280
|
await seed(adapters, {
|
|
277
281
|
adminUsername,
|
|
278
282
|
adminPassword,
|
|
279
|
-
tenantId: "${
|
|
283
|
+
tenantId: "${o}",
|
|
280
284
|
tenantName: "${t}",
|
|
281
|
-
isControlPlane: ${!!
|
|
282
|
-
|
|
283
|
-
|
|
285
|
+
isControlPlane: ${!!n},${n ? `
|
|
286
|
+
clientId: "default_client",` : ""}
|
|
287
|
+
callbacks: ${JSON.stringify(f)},
|
|
288
|
+
allowedLogoutUrls: ${JSON.stringify(y)},
|
|
284
289
|
});
|
|
285
|
-
${
|
|
290
|
+
${S}
|
|
286
291
|
await db.destroy();
|
|
287
292
|
}
|
|
288
293
|
|
|
289
294
|
main().catch(console.error);
|
|
290
295
|
`;
|
|
291
296
|
}
|
|
292
|
-
function
|
|
293
|
-
|
|
297
|
+
function U(n, e) {
|
|
298
|
+
const r = e ? `import fs from "fs";
|
|
299
|
+
` : "", a = e ? `
|
|
300
|
+
const adminDistPath = path.resolve(
|
|
301
|
+
__dirname,
|
|
302
|
+
"../node_modules/@authhero/react-admin/dist",
|
|
303
|
+
);
|
|
304
|
+
const adminIndexPath = path.join(adminDistPath, "index.html");
|
|
305
|
+
` : "", o = e ? `
|
|
306
|
+
// Add admin UI handler if the package is installed
|
|
307
|
+
if (fs.existsSync(adminIndexPath)) {
|
|
308
|
+
const issuer =
|
|
309
|
+
process.env.ISSUER || \`https://localhost:\${process.env.PORT || 3000}/\`;
|
|
310
|
+
const rawHtml = fs.readFileSync(adminIndexPath, "utf-8")
|
|
311
|
+
.replace(/src="\\.\\//g, 'src="/admin/')
|
|
312
|
+
.replace(/href="\\.\\//g, 'href="/admin/');
|
|
313
|
+
const configJson = JSON.stringify({
|
|
314
|
+
domain: issuer.replace(/\\/$/, ""),${n ? `
|
|
315
|
+
clientId: CONTROL_PLANE_CLIENT_ID,` : ""}
|
|
316
|
+
basePath: "/admin",
|
|
317
|
+
}).replace(/</g, "\\\\u003c");
|
|
318
|
+
configWithHandlers.adminIndexHtml = rawHtml.replace(
|
|
319
|
+
"</head>",
|
|
320
|
+
\`<script>window.__AUTHHERO_ADMIN_CONFIG__=\${configJson};<\/script>\\n</head>\`,
|
|
321
|
+
);
|
|
322
|
+
configWithHandlers.adminHandler = serveStatic({
|
|
323
|
+
root: adminDistPath,
|
|
324
|
+
rewriteRequestPath: (p: string) => p.replace("/admin", ""),
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
` : "";
|
|
328
|
+
return n ? `import { Context } from "hono";
|
|
294
329
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
295
330
|
import { AuthHeroConfig, DataAdapters } from "authhero";
|
|
296
331
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
297
332
|
import { initMultiTenant } from "@authhero/multi-tenancy";
|
|
298
333
|
import path from "path";
|
|
299
|
-
import { fileURLToPath } from "url";
|
|
334
|
+
${r}import { fileURLToPath } from "url";
|
|
300
335
|
|
|
301
336
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
302
337
|
|
|
@@ -304,19 +339,23 @@ const widgetPath = path.resolve(
|
|
|
304
339
|
__dirname,
|
|
305
340
|
"../node_modules/@authhero/widget/dist/authhero-widget",
|
|
306
341
|
);
|
|
307
|
-
|
|
342
|
+
${a}
|
|
308
343
|
// Control plane configuration
|
|
309
344
|
const CONTROL_PLANE_TENANT_ID = "control_plane";
|
|
310
345
|
const CONTROL_PLANE_CLIENT_ID = "default_client";
|
|
311
346
|
|
|
312
347
|
export default function createApp(config: AuthHeroConfig & { dataAdapter: DataAdapters }) {
|
|
313
|
-
|
|
314
|
-
const { app } = initMultiTenant({
|
|
348
|
+
const configWithHandlers: AuthHeroConfig & { dataAdapter: DataAdapters } = {
|
|
315
349
|
...config,
|
|
316
350
|
widgetHandler: serveStatic({
|
|
317
351
|
root: widgetPath,
|
|
318
352
|
rewriteRequestPath: (p) => p.replace("/u/widget", ""),
|
|
319
353
|
}),
|
|
354
|
+
};
|
|
355
|
+
${o}
|
|
356
|
+
// Initialize multi-tenant AuthHero - syncs resource servers, roles, and connections by default
|
|
357
|
+
const { app } = initMultiTenant({
|
|
358
|
+
...configWithHandlers,
|
|
320
359
|
controlPlane: {
|
|
321
360
|
tenantId: CONTROL_PLANE_TENANT_ID,
|
|
322
361
|
clientId: CONTROL_PLANE_CLIENT_ID,
|
|
@@ -350,7 +389,7 @@ import { AuthHeroConfig, init } from "authhero";
|
|
|
350
389
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
351
390
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
352
391
|
import path from "path";
|
|
353
|
-
import { fileURLToPath } from "url";
|
|
392
|
+
${r}import { fileURLToPath } from "url";
|
|
354
393
|
|
|
355
394
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
356
395
|
|
|
@@ -358,15 +397,17 @@ const widgetPath = path.resolve(
|
|
|
358
397
|
__dirname,
|
|
359
398
|
"../node_modules/@authhero/widget/dist/authhero-widget",
|
|
360
399
|
);
|
|
361
|
-
|
|
400
|
+
${a}
|
|
362
401
|
export default function createApp(config: AuthHeroConfig) {
|
|
363
|
-
const
|
|
402
|
+
const configWithHandlers: AuthHeroConfig = {
|
|
364
403
|
...config,
|
|
365
404
|
widgetHandler: serveStatic({
|
|
366
405
|
root: widgetPath,
|
|
367
406
|
rewriteRequestPath: (p) => p.replace("/u/widget", ""),
|
|
368
407
|
}),
|
|
369
|
-
}
|
|
408
|
+
};
|
|
409
|
+
${o}
|
|
410
|
+
const { app } = init(configWithHandlers);
|
|
370
411
|
|
|
371
412
|
app
|
|
372
413
|
.onError((err, ctx) => {
|
|
@@ -389,7 +430,7 @@ export default function createApp(config: AuthHeroConfig) {
|
|
|
389
430
|
}
|
|
390
431
|
`;
|
|
391
432
|
}
|
|
392
|
-
function O(
|
|
433
|
+
function O(n) {
|
|
393
434
|
return `import { D1Dialect } from "kysely-d1";
|
|
394
435
|
import { Kysely } from "kysely";
|
|
395
436
|
import createAdapters from "@authhero/kysely-adapter";
|
|
@@ -416,9 +457,9 @@ export default {
|
|
|
416
457
|
adminUsername,
|
|
417
458
|
adminPassword,
|
|
418
459
|
issuer,
|
|
419
|
-
tenantId: "${
|
|
420
|
-
tenantName: "${
|
|
421
|
-
isControlPlane: ${!!
|
|
460
|
+
tenantId: "${n ? "control_plane" : "main"}",
|
|
461
|
+
tenantName: "${n ? "Control Plane" : "Main"}",
|
|
462
|
+
isControlPlane: ${!!n},
|
|
422
463
|
});
|
|
423
464
|
|
|
424
465
|
return new Response(
|
|
@@ -449,12 +490,15 @@ export default {
|
|
|
449
490
|
};
|
|
450
491
|
`;
|
|
451
492
|
}
|
|
452
|
-
function
|
|
453
|
-
|
|
493
|
+
function L(n, e) {
|
|
494
|
+
const r = e ? `import adminIndexHtml from "./admin-index-html";
|
|
495
|
+
` : "", a = e ? ` adminIndexHtml,
|
|
496
|
+
` : "";
|
|
497
|
+
return n ? `import { Context } from "hono";
|
|
454
498
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
455
499
|
import { AuthHeroConfig, DataAdapters } from "authhero";
|
|
456
500
|
import { initMultiTenant } from "@authhero/multi-tenancy";
|
|
457
|
-
|
|
501
|
+
${r}
|
|
458
502
|
// Control plane configuration
|
|
459
503
|
const CONTROL_PLANE_TENANT_ID = "control_plane";
|
|
460
504
|
const CONTROL_PLANE_CLIENT_ID = "default_client";
|
|
@@ -463,7 +507,7 @@ export default function createApp(config: AuthHeroConfig & { dataAdapter: DataAd
|
|
|
463
507
|
// Initialize multi-tenant AuthHero - syncs resource servers, roles, and connections by default
|
|
464
508
|
const { app } = initMultiTenant({
|
|
465
509
|
...config,
|
|
466
|
-
controlPlane: {
|
|
510
|
+
${a} controlPlane: {
|
|
467
511
|
tenantId: CONTROL_PLANE_TENANT_ID,
|
|
468
512
|
clientId: CONTROL_PLANE_CLIENT_ID,
|
|
469
513
|
},
|
|
@@ -495,9 +539,11 @@ export default function createApp(config: AuthHeroConfig & { dataAdapter: DataAd
|
|
|
495
539
|
import { cors } from "hono/cors";
|
|
496
540
|
import { AuthHeroConfig, init } from "authhero";
|
|
497
541
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
498
|
-
|
|
542
|
+
${r}
|
|
499
543
|
export default function createApp(config: AuthHeroConfig) {
|
|
500
|
-
const { app } = init(
|
|
544
|
+
const { app } = init({
|
|
545
|
+
...config,
|
|
546
|
+
${a} });
|
|
501
547
|
|
|
502
548
|
// Enable CORS for all origins in development
|
|
503
549
|
app.use("*", cors({
|
|
@@ -529,8 +575,8 @@ export default function createApp(config: AuthHeroConfig) {
|
|
|
529
575
|
}
|
|
530
576
|
`;
|
|
531
577
|
}
|
|
532
|
-
function
|
|
533
|
-
return
|
|
578
|
+
function j(n) {
|
|
579
|
+
return n ? `import { Context } from "hono";
|
|
534
580
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
535
581
|
import { AuthHeroConfig, DataAdapters } from "authhero";
|
|
536
582
|
import { initMultiTenant } from "@authhero/multi-tenancy";
|
|
@@ -635,7 +681,7 @@ export default function createApp(config: AppConfig) {
|
|
|
635
681
|
}
|
|
636
682
|
`;
|
|
637
683
|
}
|
|
638
|
-
function
|
|
684
|
+
function $(n) {
|
|
639
685
|
return `import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
640
686
|
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
|
|
641
687
|
import createAdapters from "@authhero/aws";
|
|
@@ -664,9 +710,9 @@ async function main() {
|
|
|
664
710
|
await seed(adapters, {
|
|
665
711
|
adminUsername,
|
|
666
712
|
adminPassword,
|
|
667
|
-
tenantId: "${
|
|
668
|
-
tenantName: "${
|
|
669
|
-
isControlPlane: ${!!
|
|
713
|
+
tenantId: "${n ? "control_plane" : "main"}",
|
|
714
|
+
tenantName: "${n ? "Control Plane" : "Main"}",
|
|
715
|
+
isControlPlane: ${!!n},
|
|
670
716
|
});
|
|
671
717
|
|
|
672
718
|
console.log("โ
Database seeded successfully!");
|
|
@@ -675,24 +721,24 @@ async function main() {
|
|
|
675
721
|
main().catch(console.error);
|
|
676
722
|
`;
|
|
677
723
|
}
|
|
678
|
-
function
|
|
679
|
-
const r =
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
L(e)
|
|
683
|
-
), a.writeFileSync(
|
|
684
|
-
l.join(r, "seed.ts"),
|
|
724
|
+
function H(n, e) {
|
|
725
|
+
const r = i.join(n, "src");
|
|
726
|
+
s.writeFileSync(
|
|
727
|
+
i.join(r, "app.ts"),
|
|
685
728
|
j(e)
|
|
729
|
+
), s.writeFileSync(
|
|
730
|
+
i.join(r, "seed.ts"),
|
|
731
|
+
$(e)
|
|
686
732
|
);
|
|
687
733
|
}
|
|
688
|
-
function
|
|
734
|
+
function I() {
|
|
689
735
|
console.log("\\n" + "โ".repeat(50)), console.log("๐ AuthHero deployed to AWS!"), console.log("๐ Check SST output for your API URL"), console.log(
|
|
690
736
|
"๐ Open your server URL /setup to complete initial setup"
|
|
691
737
|
), console.log("๐ Portal available at https://local.authhero.net"), console.log("โ".repeat(50) + "\\n");
|
|
692
738
|
}
|
|
693
|
-
function
|
|
694
|
-
const e =
|
|
695
|
-
|
|
739
|
+
function M(n) {
|
|
740
|
+
const e = i.join(n, ".github", "workflows");
|
|
741
|
+
s.mkdirSync(e, { recursive: !0 });
|
|
696
742
|
const r = `name: Unit tests
|
|
697
743
|
|
|
698
744
|
on: push
|
|
@@ -714,7 +760,7 @@ jobs:
|
|
|
714
760
|
|
|
715
761
|
- run: npm run type-check
|
|
716
762
|
- run: npm test
|
|
717
|
-
`,
|
|
763
|
+
`, a = `name: Deploy to Dev
|
|
718
764
|
|
|
719
765
|
on:
|
|
720
766
|
push:
|
|
@@ -750,7 +796,7 @@ jobs:
|
|
|
750
796
|
with:
|
|
751
797
|
apiToken: \${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
752
798
|
command: deploy
|
|
753
|
-
`,
|
|
799
|
+
`, o = `name: Deploy to Production
|
|
754
800
|
|
|
755
801
|
on:
|
|
756
802
|
release:
|
|
@@ -779,9 +825,9 @@ jobs:
|
|
|
779
825
|
apiToken: \${{ secrets.PROD_CLOUDFLARE_API_TOKEN }}
|
|
780
826
|
command: deploy --env production
|
|
781
827
|
`;
|
|
782
|
-
|
|
828
|
+
s.writeFileSync(i.join(e, "unit-tests.yml"), r), s.writeFileSync(i.join(e, "deploy-dev.yml"), a), s.writeFileSync(i.join(e, "release.yml"), o), console.log("\\n๐ฆ GitHub CI workflows created!");
|
|
783
829
|
}
|
|
784
|
-
function
|
|
830
|
+
function F(n) {
|
|
785
831
|
const e = {
|
|
786
832
|
branches: ["main"],
|
|
787
833
|
plugins: [
|
|
@@ -790,39 +836,39 @@ function M(o) {
|
|
|
790
836
|
"@semantic-release/github"
|
|
791
837
|
]
|
|
792
838
|
};
|
|
793
|
-
|
|
794
|
-
|
|
839
|
+
s.writeFileSync(
|
|
840
|
+
i.join(n, ".releaserc.json"),
|
|
795
841
|
JSON.stringify(e, null, 2)
|
|
796
842
|
);
|
|
797
|
-
const r =
|
|
798
|
-
|
|
799
|
-
...
|
|
843
|
+
const r = i.join(n, "package.json"), a = JSON.parse(s.readFileSync(r, "utf-8"));
|
|
844
|
+
a.devDependencies = {
|
|
845
|
+
...a.devDependencies,
|
|
800
846
|
"semantic-release": "^24.0.0"
|
|
801
|
-
},
|
|
802
|
-
...
|
|
847
|
+
}, a.scripts = {
|
|
848
|
+
...a.scripts,
|
|
803
849
|
test: 'echo "No tests yet"',
|
|
804
850
|
"type-check": "tsc --noEmit"
|
|
805
|
-
},
|
|
851
|
+
}, s.writeFileSync(r, JSON.stringify(a, null, 2));
|
|
806
852
|
}
|
|
807
|
-
function
|
|
808
|
-
return new Promise((r,
|
|
809
|
-
const
|
|
853
|
+
function b(n, e) {
|
|
854
|
+
return new Promise((r, a) => {
|
|
855
|
+
const o = E(n, [], {
|
|
810
856
|
cwd: e,
|
|
811
857
|
shell: !0,
|
|
812
858
|
stdio: "inherit"
|
|
813
859
|
});
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
}),
|
|
860
|
+
o.on("close", (t) => {
|
|
861
|
+
t === 0 ? r() : a(new Error(`Command failed with exit code ${t}`));
|
|
862
|
+
}), o.on("error", a);
|
|
817
863
|
});
|
|
818
864
|
}
|
|
819
|
-
function
|
|
820
|
-
const
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
),
|
|
825
|
-
|
|
865
|
+
function W(n, e, r) {
|
|
866
|
+
const a = i.join(n, "src");
|
|
867
|
+
s.writeFileSync(
|
|
868
|
+
i.join(a, "app.ts"),
|
|
869
|
+
L(e, r)
|
|
870
|
+
), s.writeFileSync(
|
|
871
|
+
i.join(a, "seed.ts"),
|
|
826
872
|
O(e)
|
|
827
873
|
);
|
|
828
874
|
}
|
|
@@ -833,7 +879,7 @@ function x() {
|
|
|
833
879
|
), console.log("๐ Portal available at https://local.authhero.net"), console.log("โ".repeat(50) + `
|
|
834
880
|
`);
|
|
835
881
|
}
|
|
836
|
-
function
|
|
882
|
+
function k() {
|
|
837
883
|
console.log(`
|
|
838
884
|
` + "โ".repeat(50)), console.log("โ
Self-signed certificates generated with openssl"), console.log("โ ๏ธ You may need to trust the certificate in your browser"), console.log("๐ AuthHero server running at https://localhost:3000"), console.log("๐ API documentation available at https://localhost:3000/docs"), console.log(
|
|
839
885
|
"๐ Open https://localhost:3000/setup to complete initial setup"
|
|
@@ -843,105 +889,124 @@ function _() {
|
|
|
843
889
|
D.version("1.0.0").description("Create a new AuthHero project").argument("[project-name]", "name of the project").option("-t, --template <type>", "template type: local or cloudflare").option(
|
|
844
890
|
"--package-manager <pm>",
|
|
845
891
|
"package manager to use: npm, yarn, pnpm, or bun"
|
|
846
|
-
).option("--multi-tenant", "enable multi-tenant mode").option("--skip-install", "skip installing dependencies").option("--skip-migrate", "skip running database migrations").option("--skip-start", "skip starting the development server").option("--github-ci", "include GitHub CI workflows with semantic versioning").option("--conformance", "add OpenID conformance suite test clients").option(
|
|
892
|
+
).option("--multi-tenant", "enable multi-tenant mode").option("--admin-ui", "include admin UI at /admin").option("--skip-install", "skip installing dependencies").option("--skip-migrate", "skip running database migrations").option("--skip-start", "skip starting the development server").option("--github-ci", "include GitHub CI workflows with semantic versioning").option("--conformance", "add OpenID conformance suite test clients").option(
|
|
847
893
|
"--conformance-alias <alias>",
|
|
848
894
|
"alias for conformance suite (default: authhero-local)"
|
|
849
895
|
).option(
|
|
850
896
|
"--workspace",
|
|
851
897
|
"use workspace:* dependencies for local monorepo development"
|
|
852
|
-
).option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (
|
|
898
|
+
).option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (n, e) => {
|
|
853
899
|
const r = e.yes === !0;
|
|
854
900
|
console.log(`
|
|
855
901
|
๐ Welcome to AuthHero!
|
|
856
902
|
`);
|
|
857
|
-
let
|
|
858
|
-
|
|
903
|
+
let a = n;
|
|
904
|
+
a || (r ? (a = "auth-server", console.log(`Using default project name: ${a}`)) : a = (await m.prompt([
|
|
859
905
|
{
|
|
860
906
|
type: "input",
|
|
861
907
|
name: "projectName",
|
|
862
908
|
message: "Project name:",
|
|
863
909
|
default: "auth-server",
|
|
864
|
-
validate: (
|
|
910
|
+
validate: (u) => u !== "" || "Project name cannot be empty"
|
|
865
911
|
}
|
|
866
912
|
])).projectName);
|
|
867
|
-
const
|
|
868
|
-
|
|
869
|
-
let
|
|
870
|
-
e.template ? (["local", "cloudflare", "aws-sst"].includes(e.template) || (console.error(`โ Invalid template: ${e.template}`), console.error("Valid options: local, cloudflare, aws-sst"), process.exit(1)),
|
|
913
|
+
const o = i.join(process.cwd(), a);
|
|
914
|
+
s.existsSync(o) && (console.error(`โ Project "${a}" already exists.`), process.exit(1));
|
|
915
|
+
let t;
|
|
916
|
+
e.template ? (["local", "cloudflare", "aws-sst"].includes(e.template) || (console.error(`โ Invalid template: ${e.template}`), console.error("Valid options: local, cloudflare, aws-sst"), process.exit(1)), t = e.template, console.log(`Using template: ${p[t].name}`)) : t = (await m.prompt([
|
|
871
917
|
{
|
|
872
918
|
type: "list",
|
|
873
919
|
name: "setupType",
|
|
874
920
|
message: "Select your setup type:",
|
|
875
921
|
choices: [
|
|
876
922
|
{
|
|
877
|
-
name: `${
|
|
878
|
-
${
|
|
923
|
+
name: `${p.local.name}
|
|
924
|
+
${p.local.description}`,
|
|
879
925
|
value: "local",
|
|
880
|
-
short:
|
|
926
|
+
short: p.local.name
|
|
881
927
|
},
|
|
882
928
|
{
|
|
883
|
-
name: `${
|
|
884
|
-
${
|
|
929
|
+
name: `${p.cloudflare.name}
|
|
930
|
+
${p.cloudflare.description}`,
|
|
885
931
|
value: "cloudflare",
|
|
886
|
-
short:
|
|
932
|
+
short: p.cloudflare.name
|
|
887
933
|
},
|
|
888
934
|
{
|
|
889
|
-
name: `${
|
|
890
|
-
${
|
|
935
|
+
name: `${p["aws-sst"].name}
|
|
936
|
+
${p["aws-sst"].description}`,
|
|
891
937
|
value: "aws-sst",
|
|
892
|
-
short:
|
|
938
|
+
short: p["aws-sst"].name
|
|
893
939
|
}
|
|
894
940
|
]
|
|
895
941
|
}
|
|
896
942
|
])).setupType;
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
943
|
+
let c;
|
|
944
|
+
e.multiTenant !== void 0 ? c = e.multiTenant : r ? c = !1 : c = (await m.prompt([
|
|
945
|
+
{
|
|
946
|
+
type: "confirm",
|
|
947
|
+
name: "multiTenant",
|
|
948
|
+
message: "Would you like to enable multi-tenant mode?",
|
|
949
|
+
default: !1
|
|
950
|
+
}
|
|
951
|
+
])).multiTenant, c && console.log("Multi-tenant mode: enabled");
|
|
952
|
+
let d = !1;
|
|
953
|
+
(t === "local" || t === "cloudflare") && (e.adminUi !== void 0 ? d = e.adminUi : r ? d = !0 : d = (await m.prompt([
|
|
954
|
+
{
|
|
955
|
+
type: "confirm",
|
|
956
|
+
name: "adminUi",
|
|
957
|
+
message: "Would you like to include the admin UI at /admin?",
|
|
958
|
+
default: !0
|
|
959
|
+
}
|
|
960
|
+
])).adminUi, d && console.log("Admin UI: enabled (available at /admin)"));
|
|
961
|
+
const f = e.conformance || !1, h = e.conformanceAlias || "authhero-local";
|
|
962
|
+
f && console.log(
|
|
963
|
+
`OpenID Conformance Suite: enabled (alias: ${h})`
|
|
900
964
|
);
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
const
|
|
904
|
-
|
|
905
|
-
|
|
965
|
+
const C = e.workspace || !1;
|
|
966
|
+
C && console.log("Workspace mode: enabled (using workspace:* dependencies)");
|
|
967
|
+
const y = p[t];
|
|
968
|
+
s.mkdirSync(o, { recursive: !0 }), s.writeFileSync(
|
|
969
|
+
i.join(o, "package.json"),
|
|
906
970
|
JSON.stringify(
|
|
907
|
-
|
|
971
|
+
y.packageJson(a, c, f, C, d),
|
|
908
972
|
null,
|
|
909
973
|
2
|
|
910
974
|
)
|
|
911
975
|
);
|
|
912
|
-
const
|
|
976
|
+
const S = y.templateDir, _ = i.join(
|
|
913
977
|
import.meta.url.replace("file://", "").replace("/create-authhero.js", ""),
|
|
914
|
-
|
|
978
|
+
S
|
|
915
979
|
);
|
|
916
|
-
if (
|
|
917
|
-
const
|
|
918
|
-
|
|
919
|
-
const
|
|
920
|
-
|
|
980
|
+
if (s.existsSync(_) ? N(_, o) : (console.error(`โ Template directory not found: ${_}`), process.exit(1)), t === "cloudflare" && W(o, c, d), t === "cloudflare") {
|
|
981
|
+
const l = i.join(o, "wrangler.toml"), u = i.join(o, "wrangler.local.toml");
|
|
982
|
+
s.existsSync(l) && s.copyFileSync(l, u);
|
|
983
|
+
const g = i.join(o, ".dev.vars.example"), w = i.join(o, ".dev.vars");
|
|
984
|
+
s.existsSync(g) && s.copyFileSync(g, w), console.log(
|
|
921
985
|
"๐ Created wrangler.local.toml and .dev.vars for local development"
|
|
922
986
|
);
|
|
923
987
|
}
|
|
924
|
-
let
|
|
925
|
-
if (
|
|
988
|
+
let A = !1;
|
|
989
|
+
if (t === "cloudflare" && (e.githubCi !== void 0 ? (A = e.githubCi, A && console.log("Including GitHub CI workflows with semantic versioning")) : r || (A = (await m.prompt([
|
|
926
990
|
{
|
|
927
991
|
type: "confirm",
|
|
928
992
|
name: "includeGithubCi",
|
|
929
993
|
message: "Would you like to include GitHub CI with semantic versioning?",
|
|
930
994
|
default: !1
|
|
931
995
|
}
|
|
932
|
-
])).includeGithubCi),
|
|
933
|
-
const
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
996
|
+
])).includeGithubCi), A && (M(o), F(o))), t === "local") {
|
|
997
|
+
const l = R(
|
|
998
|
+
c,
|
|
999
|
+
f,
|
|
1000
|
+
h,
|
|
1001
|
+
d
|
|
937
1002
|
);
|
|
938
|
-
|
|
939
|
-
const
|
|
940
|
-
|
|
1003
|
+
s.writeFileSync(i.join(o, "src/seed.ts"), l);
|
|
1004
|
+
const u = U(c, d);
|
|
1005
|
+
s.writeFileSync(i.join(o, "src/app.ts"), u);
|
|
941
1006
|
}
|
|
942
|
-
if (
|
|
943
|
-
const
|
|
944
|
-
alias:
|
|
1007
|
+
if (t === "aws-sst" && H(o, c), f) {
|
|
1008
|
+
const l = {
|
|
1009
|
+
alias: h,
|
|
945
1010
|
description: "AuthHero Conformance Test",
|
|
946
1011
|
server: {
|
|
947
1012
|
discoveryUrl: "http://host.docker.internal:3000/.well-known/openid-configuration"
|
|
@@ -958,32 +1023,32 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
958
1023
|
resourceUrl: "http://host.docker.internal:3000/userinfo"
|
|
959
1024
|
}
|
|
960
1025
|
};
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
JSON.stringify(
|
|
1026
|
+
s.writeFileSync(
|
|
1027
|
+
i.join(o, "conformance-config.json"),
|
|
1028
|
+
JSON.stringify(l, null, 2)
|
|
964
1029
|
), console.log(
|
|
965
1030
|
"๐ Created conformance-config.json for OpenID Conformance Suite"
|
|
966
1031
|
);
|
|
967
1032
|
}
|
|
968
|
-
const T =
|
|
1033
|
+
const T = c ? "multi-tenant" : "single-tenant";
|
|
969
1034
|
console.log(
|
|
970
1035
|
`
|
|
971
|
-
โ
Project "${
|
|
1036
|
+
โ
Project "${a}" has been created with ${y.name} (${T}) setup!
|
|
972
1037
|
`
|
|
973
1038
|
);
|
|
974
|
-
let
|
|
975
|
-
if (e.skipInstall ?
|
|
1039
|
+
let v;
|
|
1040
|
+
if (e.skipInstall ? v = !1 : r ? v = !0 : v = (await m.prompt([
|
|
976
1041
|
{
|
|
977
1042
|
type: "confirm",
|
|
978
1043
|
name: "shouldInstall",
|
|
979
1044
|
message: "Would you like to install dependencies now?",
|
|
980
1045
|
default: !0
|
|
981
1046
|
}
|
|
982
|
-
])).shouldInstall,
|
|
983
|
-
let
|
|
1047
|
+
])).shouldInstall, v) {
|
|
1048
|
+
let l;
|
|
984
1049
|
e.packageManager ? (["npm", "yarn", "pnpm", "bun"].includes(e.packageManager) || (console.error(
|
|
985
1050
|
`โ Invalid package manager: ${e.packageManager}`
|
|
986
|
-
), console.error("Valid options: npm, yarn, pnpm, bun"), process.exit(1)),
|
|
1051
|
+
), console.error("Valid options: npm, yarn, pnpm, bun"), process.exit(1)), l = e.packageManager) : r ? l = "pnpm" : l = (await m.prompt([
|
|
987
1052
|
{
|
|
988
1053
|
type: "list",
|
|
989
1054
|
name: "packageManager",
|
|
@@ -997,64 +1062,64 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
997
1062
|
default: "pnpm"
|
|
998
1063
|
}
|
|
999
1064
|
])).packageManager, console.log(`
|
|
1000
|
-
๐ฆ Installing dependencies with ${
|
|
1065
|
+
๐ฆ Installing dependencies with ${l}...
|
|
1001
1066
|
`);
|
|
1002
1067
|
try {
|
|
1003
|
-
const
|
|
1004
|
-
if (await
|
|
1068
|
+
const u = l === "pnpm" ? "pnpm install --ignore-workspace" : `${l} install`;
|
|
1069
|
+
if (await b(u, o), t === "local" && (console.log(`
|
|
1005
1070
|
๐ง Building native modules...
|
|
1006
|
-
`), await
|
|
1071
|
+
`), await b("npm rebuild better-sqlite3", o)), console.log(`
|
|
1007
1072
|
โ
Dependencies installed successfully!
|
|
1008
|
-
`), (
|
|
1009
|
-
let
|
|
1010
|
-
r ?
|
|
1073
|
+
`), (t === "local" || t === "cloudflare") && !e.skipMigrate) {
|
|
1074
|
+
let w;
|
|
1075
|
+
r ? w = !0 : w = (await m.prompt([
|
|
1011
1076
|
{
|
|
1012
1077
|
type: "confirm",
|
|
1013
1078
|
name: "shouldMigrate",
|
|
1014
1079
|
message: "Would you like to run database migrations?",
|
|
1015
1080
|
default: !0
|
|
1016
1081
|
}
|
|
1017
|
-
])).shouldMigrate,
|
|
1082
|
+
])).shouldMigrate, w && (console.log(`
|
|
1018
1083
|
๐ Running migrations...
|
|
1019
|
-
`), await
|
|
1084
|
+
`), await b(`${l} run migrate`, o));
|
|
1020
1085
|
}
|
|
1021
|
-
let
|
|
1022
|
-
e.skipStart || r ?
|
|
1086
|
+
let g;
|
|
1087
|
+
e.skipStart || r ? g = !1 : g = (await m.prompt([
|
|
1023
1088
|
{
|
|
1024
1089
|
type: "confirm",
|
|
1025
1090
|
name: "shouldStart",
|
|
1026
1091
|
message: "Would you like to start the development server?",
|
|
1027
1092
|
default: !0
|
|
1028
1093
|
}
|
|
1029
|
-
])).shouldStart,
|
|
1030
|
-
`), await
|
|
1094
|
+
])).shouldStart, g && (t === "cloudflare" ? x() : t === "aws-sst" ? I() : k(), console.log(`๐ Starting development server...
|
|
1095
|
+
`), await b(`${l} run dev`, o)), r && !g && (console.log(`
|
|
1031
1096
|
โ
Setup complete!`), console.log(`
|
|
1032
|
-
To start the development server:`), console.log(` cd ${
|
|
1033
|
-
} catch (
|
|
1097
|
+
To start the development server:`), console.log(` cd ${a}`), console.log(" npm run dev"), t === "cloudflare" ? x() : t === "aws-sst" ? I() : k());
|
|
1098
|
+
} catch (u) {
|
|
1034
1099
|
console.error(`
|
|
1035
|
-
โ An error occurred:`,
|
|
1100
|
+
โ An error occurred:`, u), process.exit(1);
|
|
1036
1101
|
}
|
|
1037
1102
|
}
|
|
1038
|
-
|
|
1103
|
+
v || (console.log("Next steps:"), console.log(` cd ${a}`), t === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(" npm run dev"), console.log(
|
|
1039
1104
|
`
|
|
1040
1105
|
Open https://localhost:3000/setup to complete initial setup`
|
|
1041
|
-
)) :
|
|
1106
|
+
)) : t === "cloudflare" ? (console.log(" npm install"), console.log(
|
|
1042
1107
|
" npm run migrate # or npm run db:migrate:remote for production"
|
|
1043
1108
|
), console.log(" npm run dev # or npm run dev:remote for production"), console.log(
|
|
1044
1109
|
`
|
|
1045
1110
|
Open https://localhost:3000/setup to complete initial setup`
|
|
1046
|
-
)) :
|
|
1111
|
+
)) : t === "aws-sst" && (console.log(" npm install"), console.log(" npm run dev # Deploys to AWS in development mode"), console.log(
|
|
1047
1112
|
`
|
|
1048
1113
|
Open your server URL /setup to complete initial setup`
|
|
1049
1114
|
)), console.log(`
|
|
1050
|
-
Server will be available at: https://localhost:3000`), console.log("Portal available at: https://local.authhero.net"),
|
|
1115
|
+
Server will be available at: https://localhost:3000`), console.log("Portal available at: https://local.authhero.net"), f && (console.log(`
|
|
1051
1116
|
๐งช OpenID Conformance Suite Testing:`), console.log(
|
|
1052
1117
|
" 1. Clone and start the conformance suite (if not already running):"
|
|
1053
1118
|
), console.log(
|
|
1054
1119
|
" git clone https://gitlab.com/openid/conformance-suite.git"
|
|
1055
1120
|
), console.log(" cd conformance-suite && mvn clean package"), console.log(" docker-compose up -d"), console.log(" 2. Open https://localhost.emobix.co.uk:8443"), console.log(
|
|
1056
1121
|
" 3. Create a test plan and use conformance-config.json for settings"
|
|
1057
|
-
), console.log(` 4. Use alias: ${
|
|
1122
|
+
), console.log(` 4. Use alias: ${h}`)), console.log(`
|
|
1058
1123
|
For more information, visit: https://authhero.net/docs
|
|
1059
1124
|
`));
|
|
1060
1125
|
});
|
package/dist/local/src/app.ts
CHANGED
|
@@ -34,7 +34,9 @@ export default function createApp(config: AuthHeroConfig) {
|
|
|
34
34
|
if (fs.existsSync(adminIndexPath)) {
|
|
35
35
|
const issuer =
|
|
36
36
|
process.env.ISSUER || `https://localhost:${process.env.PORT || 3000}/`;
|
|
37
|
-
const rawHtml = fs.readFileSync(adminIndexPath, "utf-8")
|
|
37
|
+
const rawHtml = fs.readFileSync(adminIndexPath, "utf-8")
|
|
38
|
+
.replace(/src="\.\/assets\//g, 'src="/admin/assets/')
|
|
39
|
+
.replace(/href="\.\/assets\//g, 'href="/admin/assets/');
|
|
38
40
|
const configJson = JSON.stringify({
|
|
39
41
|
domain: issuer.replace(/\/$/, ""),
|
|
40
42
|
basePath: "/admin",
|