seamless-cli 0.2.0 → 0.5.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/README.md +5 -6
- package/dist/commands/help.js +18 -1
- package/dist/commands/help.js.map +1 -1
- package/dist/commands/init.js +104 -21
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/verify.js +259 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/core/bootstrapSecret.js +12 -4
- package/dist/core/bootstrapSecret.js.map +1 -1
- package/dist/core/exec.js +2 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/fetch.js +2 -1
- package/dist/core/fetch.js.map +1 -1
- package/dist/core/images.js +11 -0
- package/dist/core/images.js.map +1 -0
- package/dist/core/oauthProviders.js +89 -0
- package/dist/core/oauthProviders.js.map +1 -0
- package/dist/core/templates.js +185 -0
- package/dist/core/templates.js.map +1 -0
- package/dist/generators/auth/auth.js +40 -19
- package/dist/generators/auth/auth.js.map +1 -1
- package/dist/generators/config/config.js +3 -4
- package/dist/generators/config/config.js.map +1 -1
- package/dist/generators/docker/docker.js +51 -31
- package/dist/generators/docker/docker.js.map +1 -1
- package/dist/index.js +11 -2
- package/dist/index.js.map +1 -1
- package/dist/prompts/oauthSetup.js +36 -0
- package/dist/prompts/oauthSetup.js.map +1 -0
- package/dist/prompts/projectSetup.js +43 -19
- package/dist/prompts/projectSetup.js.map +1 -1
- package/package.json +6 -1
- package/verify/adapter-app/Dockerfile +14 -0
- package/verify/adapter-app/package.json +13 -0
- package/verify/adapter-app/server.mjs +62 -0
- package/verify/adapter-app/vendor/.gitignore +3 -0
- package/verify/adapter-app/vendor/.gitkeep +0 -0
- package/verify/docker-compose.verify.yml +154 -0
- package/verify/harness/adapter/emailOtpLogin.spec.ts +12 -0
- package/verify/harness/adapter/magicLink.spec.ts +14 -0
- package/verify/harness/adapter/oauth.spec.ts +11 -0
- package/verify/harness/adapter/registration.spec.ts +11 -0
- package/verify/harness/adapter/sessionLifecycle.spec.ts +20 -0
- package/verify/harness/api/adminBootstrap.spec.ts +34 -0
- package/verify/harness/api/emailOtp.spec.ts +17 -0
- package/verify/harness/api/jwks.spec.ts +17 -0
- package/verify/harness/api/magicLink.spec.ts +36 -0
- package/verify/harness/api/oauth.spec.ts +12 -0
- package/verify/harness/api/organizations.spec.ts +28 -0
- package/verify/harness/api/phoneOtp.spec.ts +19 -0
- package/verify/harness/api/sessionLifecycle.spec.ts +26 -0
- package/verify/harness/api/stepUp.spec.ts +39 -0
- package/verify/harness/api/totp.spec.ts +24 -0
- package/verify/harness/global-setup.ts +45 -0
- package/verify/harness/lib/adapterFlows.ts +57 -0
- package/verify/harness/lib/client.ts +32 -0
- package/verify/harness/lib/env.ts +45 -0
- package/verify/harness/lib/fixtures.ts +20 -0
- package/verify/harness/lib/flows.ts +204 -0
- package/verify/harness/lib/matrixReporter.ts +73 -0
- package/verify/harness/lib/reactFlows.ts +117 -0
- package/verify/harness/lib/serviceToken.ts +26 -0
- package/verify/harness/lib/totp.ts +36 -0
- package/verify/harness/mock-oidc.ts +112 -0
- package/verify/harness/package-lock.json +93 -0
- package/verify/harness/package.json +14 -0
- package/verify/harness/playwright.config.ts +30 -0
- package/verify/harness/react/emailOtpLogin.spec.ts +13 -0
- package/verify/harness/react/logout.spec.ts +17 -0
- package/verify/harness/react/magicLinkLogin.spec.ts +29 -0
- package/verify/harness/react/oauth.spec.ts +13 -0
- package/verify/harness/react/passkeyLogin.spec.ts +24 -0
- package/verify/harness/react/passkeyRegister.spec.ts +15 -0
- package/verify/harness/react/register.spec.ts +18 -0
- package/verify/react-vendor/.gitkeep +0 -0
- package/dist/commands/contribute.js +0 -121
- package/dist/commands/contribute.js.map +0 -1
- package/dist/commands/deploy.js +0 -190
- package/dist/commands/deploy.js.map +0 -1
- package/dist/commands/destroy.js +0 -122
- package/dist/commands/destroy.js.map +0 -1
- package/dist/contributor/catalog.js +0 -129
- package/dist/contributor/catalog.js.map +0 -1
- package/dist/contributor/workspace.js +0 -551
- package/dist/contributor/workspace.js.map +0 -1
- package/dist/core/acm.js +0 -24
- package/dist/core/acm.js.map +0 -1
- package/dist/core/aws.js +0 -374
- package/dist/core/aws.js.map +0 -1
- package/dist/core/buildPush.js +0 -91
- package/dist/core/buildPush.js.map +0 -1
- package/dist/core/configure.js +0 -25
- package/dist/core/configure.js.map +0 -1
- package/dist/core/deployConfig.js +0 -66
- package/dist/core/deployConfig.js.map +0 -1
- package/dist/core/deployManifest.js +0 -163
- package/dist/core/deployManifest.js.map +0 -1
- package/dist/core/deploySecrets.js +0 -31
- package/dist/core/deploySecrets.js.map +0 -1
- package/dist/core/destroy.js +0 -38
- package/dist/core/destroy.js.map +0 -1
- package/dist/core/envDiscovery.js +0 -153
- package/dist/core/envDiscovery.js.map +0 -1
- package/dist/core/envRegistry.js +0 -76
- package/dist/core/envRegistry.js.map +0 -1
- package/dist/core/health.js +0 -11
- package/dist/core/health.js.map +0 -1
- package/dist/core/help.js +0 -75
- package/dist/core/help.js.map +0 -1
- package/dist/core/preReqs.js +0 -14
- package/dist/core/preReqs.js.map +0 -1
- package/dist/core/terraform.js +0 -34
- package/dist/core/terraform.js.map +0 -1
- package/dist/core/tfVars.js +0 -69
- package/dist/core/tfVars.js.map +0 -1
- package/dist/generators/backend/express.js +0 -13
- package/dist/generators/backend/express.js.map +0 -1
- package/dist/generators/deploy/aws/dev/files.js +0 -36
- package/dist/generators/deploy/aws/dev/files.js.map +0 -1
- package/dist/generators/deploy/aws/dev/template.js +0 -1240
- package/dist/generators/deploy/aws/dev/template.js.map +0 -1
- package/dist/generators/frontend/react.js +0 -13
- package/dist/generators/frontend/react.js.map +0 -1
- package/dist/prompts/contributeSetup.js +0 -39
- package/dist/prompts/contributeSetup.js.map +0 -1
- package/dist/prompts/deploySetup.js +0 -244
- package/dist/prompts/deploySetup.js.map +0 -1
- package/dist/utils/repoUtils.js +0 -23
- package/dist/utils/repoUtils.js.map +0 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const POSTGRES_IMAGE = "postgres:17";
|
|
2
|
+
export const SEAMLESS_AUTH_API_VERSION = "v0.2.1";
|
|
3
|
+
export const SEAMLESS_AUTH_API_IMAGE = `ghcr.io/fells-code/seamless-auth-api:${SEAMLESS_AUTH_API_VERSION}`;
|
|
4
|
+
export const SEAMLESS_AUTH_ADMIN_DASHBOARD_VERSION = "v0.1.0";
|
|
5
|
+
export const SEAMLESS_AUTH_ADMIN_DASHBOARD_IMAGE = `ghcr.io/fells-code/seamless-auth-admin-dashboard:${SEAMLESS_AUTH_ADMIN_DASHBOARD_VERSION}`;
|
|
6
|
+
// The starter templates monorepo the CLI scaffolds from. Pinned to a tag so a given
|
|
7
|
+
// CLI version always produces the same project. Override the ref with
|
|
8
|
+
// SEAMLESS_TEMPLATES_REF, or point at a local checkout with SEAMLESS_TEMPLATES_DIR.
|
|
9
|
+
export const SEAMLESS_TEMPLATES_REPO = "fells-code/seamless-templates";
|
|
10
|
+
export const SEAMLESS_TEMPLATES_REF = "v0.2.1";
|
|
11
|
+
//# sourceMappingURL=images.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"images.js","sourceRoot":"","sources":["../../src/core/images.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,aAAa,CAAC;AAE5C,MAAM,CAAC,MAAM,yBAAyB,GAAG,QAAQ,CAAC;AAElD,MAAM,CAAC,MAAM,uBAAuB,GAAG,wCAAwC,yBAAyB,EAAE,CAAC;AAE3G,MAAM,CAAC,MAAM,qCAAqC,GAAG,QAAQ,CAAC;AAE9D,MAAM,CAAC,MAAM,mCAAmC,GAAG,oDAAoD,qCAAqC,EAAE,CAAC;AAE/I,oFAAoF;AACpF,sEAAsE;AACtE,oFAAoF;AACpF,MAAM,CAAC,MAAM,uBAAuB,GAAG,+BAA+B,CAAC;AAEvE,MAAM,CAAC,MAAM,sBAAsB,GAAG,QAAQ,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { generateSecret } from "./secrets.js";
|
|
2
|
+
// The web app's OAuth callback route. The scaffolded web container serves the app
|
|
3
|
+
// at :5173, and the react-oauth template redirects to /oauth/callback there.
|
|
4
|
+
const REDIRECT_URI = "http://localhost:5173/oauth/callback";
|
|
5
|
+
export const OAUTH_PROVIDER_CATALOG = [
|
|
6
|
+
{
|
|
7
|
+
id: "google",
|
|
8
|
+
label: "Google",
|
|
9
|
+
authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
10
|
+
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
11
|
+
userInfoUrl: "https://openidconnect.googleapis.com/v1/userinfo",
|
|
12
|
+
scopes: ["openid", "email", "profile"],
|
|
13
|
+
pkce: true,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "github",
|
|
17
|
+
label: "GitHub",
|
|
18
|
+
authorizationUrl: "https://github.com/login/oauth/authorize",
|
|
19
|
+
tokenUrl: "https://github.com/login/oauth/access_token",
|
|
20
|
+
userInfoUrl: "https://api.github.com/user",
|
|
21
|
+
scopes: ["read:user", "user:email"],
|
|
22
|
+
extra: { subjectJsonPath: "id", nameJsonPath: "name" },
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "microsoft",
|
|
26
|
+
label: "Microsoft",
|
|
27
|
+
authorizationUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
|
|
28
|
+
tokenUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
|
29
|
+
userInfoUrl: "https://graph.microsoft.com/oidc/userinfo",
|
|
30
|
+
scopes: ["openid", "email", "profile"],
|
|
31
|
+
pkce: true,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "gitlab",
|
|
35
|
+
label: "GitLab",
|
|
36
|
+
authorizationUrl: "https://gitlab.com/oauth/authorize",
|
|
37
|
+
tokenUrl: "https://gitlab.com/oauth/token",
|
|
38
|
+
userInfoUrl: "https://gitlab.com/oauth/userinfo",
|
|
39
|
+
scopes: ["openid", "email", "profile"],
|
|
40
|
+
pkce: true,
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
function secretEnvName(id) {
|
|
44
|
+
return `${id.toUpperCase().replace(/-/g, "_")}_CLIENT_SECRET`;
|
|
45
|
+
}
|
|
46
|
+
// Turns the chosen providers into the auth-server env: the OAUTH_PROVIDERS JSON, a
|
|
47
|
+
// per-provider client-secret env var, and OAUTH_STATE_SECRET. A provider missing
|
|
48
|
+
// either credential is scaffolded disabled (so the stack still boots) and reported
|
|
49
|
+
// in `pending` so the CLI can tell the user what to fill in.
|
|
50
|
+
export function buildOAuthAuthEnv(providers) {
|
|
51
|
+
const env = {};
|
|
52
|
+
const pending = [];
|
|
53
|
+
const configs = providers.map(({ catalog, clientId, clientSecret }) => {
|
|
54
|
+
const envName = secretEnvName(catalog.id);
|
|
55
|
+
const ready = clientId.length > 0 && clientSecret.length > 0;
|
|
56
|
+
if (!ready)
|
|
57
|
+
pending.push(catalog.label);
|
|
58
|
+
env[envName] = clientSecret;
|
|
59
|
+
return {
|
|
60
|
+
id: catalog.id,
|
|
61
|
+
name: catalog.label,
|
|
62
|
+
enabled: ready,
|
|
63
|
+
clientId: clientId || `REPLACE_WITH_${catalog.id.toUpperCase()}_CLIENT_ID`,
|
|
64
|
+
clientSecretEnv: envName,
|
|
65
|
+
authorizationUrl: catalog.authorizationUrl,
|
|
66
|
+
tokenUrl: catalog.tokenUrl,
|
|
67
|
+
userInfoUrl: catalog.userInfoUrl,
|
|
68
|
+
scopes: catalog.scopes,
|
|
69
|
+
redirectUri: REDIRECT_URI,
|
|
70
|
+
redirectUris: [REDIRECT_URI],
|
|
71
|
+
...(catalog.pkce ? { pkce: true } : {}),
|
|
72
|
+
...(catalog.extra ?? {}),
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
env.OAUTH_PROVIDERS = JSON.stringify(configs);
|
|
76
|
+
env.OAUTH_STATE_SECRET = generateSecret(32);
|
|
77
|
+
return { env, pending };
|
|
78
|
+
}
|
|
79
|
+
// Ensures a login method is present in a comma-separated LOGIN_METHODS value.
|
|
80
|
+
export function withLoginMethod(current, method) {
|
|
81
|
+
const methods = (current ?? "passkey,magic_link")
|
|
82
|
+
.split(",")
|
|
83
|
+
.map((m) => m.trim())
|
|
84
|
+
.filter(Boolean);
|
|
85
|
+
if (!methods.includes(method))
|
|
86
|
+
methods.push(method);
|
|
87
|
+
return methods.join(",");
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=oauthProviders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthProviders.js","sourceRoot":"","sources":["../../src/core/oauthProviders.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import AdmZip from "adm-zip";
|
|
4
|
+
import { VERSION } from "../index.js";
|
|
5
|
+
import { parseEnvString, writeEnv } from "./env.js";
|
|
6
|
+
import { generateSecret } from "./secrets.js";
|
|
7
|
+
import { SEAMLESS_TEMPLATES_REF, SEAMLESS_TEMPLATES_REPO } from "./images.js";
|
|
8
|
+
// Build artifacts and local-only files that must never be copied into a scaffold,
|
|
9
|
+
// even if a local template checkout has them lying around.
|
|
10
|
+
const IGNORED_NAMES = new Set([
|
|
11
|
+
"node_modules",
|
|
12
|
+
".git",
|
|
13
|
+
"dist",
|
|
14
|
+
"build",
|
|
15
|
+
".next",
|
|
16
|
+
"out",
|
|
17
|
+
"coverage",
|
|
18
|
+
".DS_Store",
|
|
19
|
+
".env",
|
|
20
|
+
".env.local",
|
|
21
|
+
]);
|
|
22
|
+
export async function openTemplateSource() {
|
|
23
|
+
const localDir = process.env.SEAMLESS_TEMPLATES_DIR;
|
|
24
|
+
if (localDir) {
|
|
25
|
+
return openLocalSource(path.resolve(localDir));
|
|
26
|
+
}
|
|
27
|
+
return openRemoteSource(SEAMLESS_TEMPLATES_REPO, process.env.SEAMLESS_TEMPLATES_REF ?? SEAMLESS_TEMPLATES_REF);
|
|
28
|
+
}
|
|
29
|
+
function readRegistry(raw) {
|
|
30
|
+
const registry = JSON.parse(raw);
|
|
31
|
+
if (!registry || !Array.isArray(registry.templates)) {
|
|
32
|
+
throw new Error("Template registry is malformed (missing templates array).");
|
|
33
|
+
}
|
|
34
|
+
return registry;
|
|
35
|
+
}
|
|
36
|
+
function openLocalSource(dir) {
|
|
37
|
+
const registryPath = path.join(dir, "registry.json");
|
|
38
|
+
if (!fs.existsSync(registryPath)) {
|
|
39
|
+
throw new Error(`SEAMLESS_TEMPLATES_DIR is set to ${dir}, but no registry.json was found there.`);
|
|
40
|
+
}
|
|
41
|
+
const registry = readRegistry(fs.readFileSync(registryPath, "utf-8"));
|
|
42
|
+
return {
|
|
43
|
+
registry,
|
|
44
|
+
async readManifest(entry) {
|
|
45
|
+
const manifestPath = path.join(dir, entry.path, "template.json");
|
|
46
|
+
return JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
47
|
+
},
|
|
48
|
+
async copyInto(entry, destDir) {
|
|
49
|
+
copyDir(path.join(dir, entry.path), destDir);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async function openRemoteSource(repo, ref) {
|
|
54
|
+
const registryUrl = `https://raw.githubusercontent.com/${repo}/${ref}/registry.json`;
|
|
55
|
+
const res = await fetch(registryUrl);
|
|
56
|
+
if (!res.ok) {
|
|
57
|
+
throw new Error(`Failed to fetch the template registry (${res.status}) from ${registryUrl}.`);
|
|
58
|
+
}
|
|
59
|
+
const registry = readRegistry(await res.text());
|
|
60
|
+
// The whole monorepo is downloaded once, lazily, and shared across every template
|
|
61
|
+
// a single scaffold pulls in.
|
|
62
|
+
let archive = null;
|
|
63
|
+
const ensureArchive = async () => {
|
|
64
|
+
if (archive)
|
|
65
|
+
return archive;
|
|
66
|
+
const url = `https://github.com/${repo}/archive/${ref}.zip`;
|
|
67
|
+
const zipRes = await fetch(url);
|
|
68
|
+
if (!zipRes.ok) {
|
|
69
|
+
throw new Error(`Failed to download templates (${zipRes.status}) from ${url}.`);
|
|
70
|
+
}
|
|
71
|
+
const zip = new AdmZip(Buffer.from(await zipRes.arrayBuffer()));
|
|
72
|
+
const first = zip.getEntries()[0];
|
|
73
|
+
if (!first) {
|
|
74
|
+
throw new Error("Downloaded templates archive was empty.");
|
|
75
|
+
}
|
|
76
|
+
// GitHub archives nest everything under a single top-level directory.
|
|
77
|
+
const root = first.entryName.split("/")[0];
|
|
78
|
+
archive = { zip, root };
|
|
79
|
+
return archive;
|
|
80
|
+
};
|
|
81
|
+
return {
|
|
82
|
+
registry,
|
|
83
|
+
async readManifest(entry) {
|
|
84
|
+
const { zip, root } = await ensureArchive();
|
|
85
|
+
const name = `${root}/${entry.path}/template.json`;
|
|
86
|
+
const found = zip.getEntry(name);
|
|
87
|
+
if (!found) {
|
|
88
|
+
throw new Error(`Template "${entry.id}" is missing template.json in the registry.`);
|
|
89
|
+
}
|
|
90
|
+
return JSON.parse(found.getData().toString("utf-8"));
|
|
91
|
+
},
|
|
92
|
+
async copyInto(entry, destDir) {
|
|
93
|
+
const { zip, root } = await ensureArchive();
|
|
94
|
+
const prefix = `${root}/${entry.path}/`;
|
|
95
|
+
for (const e of zip.getEntries()) {
|
|
96
|
+
if (e.isDirectory || !e.entryName.startsWith(prefix))
|
|
97
|
+
continue;
|
|
98
|
+
const rel = e.entryName.slice(prefix.length);
|
|
99
|
+
if (rel.split("/").some((seg) => IGNORED_NAMES.has(seg)))
|
|
100
|
+
continue;
|
|
101
|
+
const out = path.join(destDir, rel);
|
|
102
|
+
fs.mkdirSync(path.dirname(out), { recursive: true });
|
|
103
|
+
fs.writeFileSync(out, e.getData());
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function copyDir(src, dest) {
|
|
109
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
110
|
+
for (const name of fs.readdirSync(src)) {
|
|
111
|
+
if (IGNORED_NAMES.has(name))
|
|
112
|
+
continue;
|
|
113
|
+
const from = path.join(src, name);
|
|
114
|
+
const to = path.join(dest, name);
|
|
115
|
+
const stat = fs.statSync(from);
|
|
116
|
+
if (stat.isDirectory()) {
|
|
117
|
+
copyDir(from, to);
|
|
118
|
+
}
|
|
119
|
+
else if (stat.isFile()) {
|
|
120
|
+
fs.copyFileSync(from, to);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export function assertCliSupports(manifest, label) {
|
|
125
|
+
const min = manifest.requires?.cliMin;
|
|
126
|
+
if (min && compareSemver(VERSION, min) < 0) {
|
|
127
|
+
throw new Error(`Template "${label}" requires seamless-cli >= ${min}, but this is ${VERSION}. Please upgrade.`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Copies the template's example env to .env (if declared), then applies the
|
|
131
|
+
// manifest's env.set, resolving {{placeholders}} against the scaffold context.
|
|
132
|
+
// This replaces the per-framework configure step.
|
|
133
|
+
export function applyTemplateEnv(destDir, manifest, ctx) {
|
|
134
|
+
const env = manifest.env ?? {};
|
|
135
|
+
const envPath = path.join(destDir, ".env");
|
|
136
|
+
let values = {};
|
|
137
|
+
if (env.fromExample) {
|
|
138
|
+
const examplePath = path.join(destDir, env.fromExample);
|
|
139
|
+
if (fs.existsSync(examplePath)) {
|
|
140
|
+
values = parseEnvString(fs.readFileSync(examplePath, "utf-8"));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else if (fs.existsSync(envPath)) {
|
|
144
|
+
values = parseEnvString(fs.readFileSync(envPath, "utf-8"));
|
|
145
|
+
}
|
|
146
|
+
for (const [key, raw] of Object.entries(env.set ?? {})) {
|
|
147
|
+
values[key] = resolvePlaceholders(raw, ctx);
|
|
148
|
+
}
|
|
149
|
+
writeEnv(envPath, values);
|
|
150
|
+
}
|
|
151
|
+
function resolvePlaceholders(value, ctx) {
|
|
152
|
+
return value.replace(/\{\{\s*([\w:]+)\s*\}\}/g, (_match, token) => resolveToken(token, ctx));
|
|
153
|
+
}
|
|
154
|
+
function resolveToken(token, ctx) {
|
|
155
|
+
const secret = /^secret:(\d+)$/.exec(token);
|
|
156
|
+
if (secret) {
|
|
157
|
+
return generateSecret(Number(secret[1]));
|
|
158
|
+
}
|
|
159
|
+
const known = {
|
|
160
|
+
authServerUrl: ctx.authServerUrl,
|
|
161
|
+
apiUrl: ctx.apiUrl,
|
|
162
|
+
apiToken: ctx.apiToken,
|
|
163
|
+
jwksKid: ctx.jwksKid,
|
|
164
|
+
};
|
|
165
|
+
if (token in known) {
|
|
166
|
+
const resolved = known[token];
|
|
167
|
+
if (resolved == null) {
|
|
168
|
+
throw new Error(`Template placeholder {{${token}}} has no value in this configuration.`);
|
|
169
|
+
}
|
|
170
|
+
return resolved;
|
|
171
|
+
}
|
|
172
|
+
throw new Error(`Unknown template placeholder {{${token}}}.`);
|
|
173
|
+
}
|
|
174
|
+
function compareSemver(a, b) {
|
|
175
|
+
const norm = (v) => v.replace(/^v/, "").split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
|
|
176
|
+
const pa = norm(a);
|
|
177
|
+
const pb = norm(b);
|
|
178
|
+
for (let i = 0; i < 3; i++) {
|
|
179
|
+
const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
180
|
+
if (diff !== 0)
|
|
181
|
+
return diff < 0 ? -1 : 1;
|
|
182
|
+
}
|
|
183
|
+
return 0;
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/core/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,MAAM,MAAM,SAAS,CAAC;AAE7B,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAmD9E,kFAAkF;AAClF,2DAA2D;AAC3D,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,cAAc;IACd,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,KAAK;IACL,UAAU;IACV,WAAW;IACX,MAAM;IACN,YAAY;CACb,CAAC,CAAC;AAUH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;IACpD,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,gBAAgB,CACrB,uBAAuB,EACvB,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,sBAAsB,CAC7D,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAa,CAAC;IAC7C,IAAI,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,eAAe,CAAC,GAAW;IAClC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IACrD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,oCAAoC,GAAG,yCAAyC,CACjF,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IAEtE,OAAO;QACL,QAAQ;QACR,KAAK,CAAC,YAAY,CAAC,KAAK;YACtB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;YACjE,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAqB,CAAC;QAChF,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO;YAC3B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;QAC/C,CAAC;KACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,IAAY,EAAE,GAAW;IACvD,MAAM,WAAW,GAAG,qCAAqC,IAAI,IAAI,GAAG,gBAAgB,CAAC;IACrF,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,0CAA0C,GAAG,CAAC,MAAM,UAAU,WAAW,GAAG,CAC7E,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAEhD,kFAAkF;IAClF,8BAA8B;IAC9B,IAAI,OAAO,GAAyC,IAAI,CAAC;IACzD,MAAM,aAAa,GAAG,KAAK,IAAI,EAAE;QAC/B,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;QAC5B,MAAM,GAAG,GAAG,sBAAsB,IAAI,YAAY,GAAG,MAAM,CAAC;QAC5D,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,iCAAiC,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,CAAC,CAAC;QAClF,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAChE,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QACD,sEAAsE;QACtE,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,OAAO,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;IAEF,OAAO;QACL,QAAQ;QACR,KAAK,CAAC,YAAY,CAAC,KAAK;YACtB,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,MAAM,aAAa,EAAE,CAAC;YAC5C,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,gBAAgB,CAAC;YACnD,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACjC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,IAAI,KAAK,CAAC,aAAa,KAAK,CAAC,EAAE,6CAA6C,CAAC,CAAC;YACtF,CAAC;YACD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAqB,CAAC;QAC3E,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO;YAC3B,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,MAAM,aAAa,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;YACxC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE,EAAE,CAAC;gBACjC,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC;oBAAE,SAAS;gBAC/D,MAAM,GAAG,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC7C,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBAAE,SAAS;gBACnE,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;gBACpC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACrD,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,GAAW,EAAE,IAAY;IACxC,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAClC,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACpB,CAAC;aAAM,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YACzB,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAA0B,EAAE,KAAa;IACzE,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IACtC,IAAI,GAAG,IAAI,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CACb,aAAa,KAAK,8BAA8B,GAAG,iBAAiB,OAAO,mBAAmB,CAC/F,CAAC;IACJ,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,+EAA+E;AAC/E,kDAAkD;AAClD,MAAM,UAAU,gBAAgB,CAC9B,OAAe,EACf,QAA0B,EAC1B,GAAoB;IAEpB,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,IAAI,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAE3C,IAAI,MAAM,GAA2B,EAAE,CAAC;IACxC,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACpB,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;QACxD,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/B,MAAM,GAAG,cAAc,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;SAAM,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAClC,MAAM,GAAG,cAAc,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,GAAG,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa,EAAE,GAAoB;IAC9D,OAAO,KAAK,CAAC,OAAO,CAAC,yBAAyB,EAAE,CAAC,MAAM,EAAE,KAAa,EAAE,EAAE,CACxE,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CACzB,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,KAAa,EAAE,GAAoB;IACvD,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,KAAK,GAAuC;QAChD,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,OAAO,EAAE,GAAG,CAAC,OAAO;KACrB,CAAC;IAEF,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;QACnB,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CACb,0BAA0B,KAAK,wCAAwC,CACxE,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,kCAAkC,KAAK,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,aAAa,CAAC,CAAS,EAAE,CAAS;IACzC,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CACzB,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAChF,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACnB,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACzC,IAAI,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -1,47 +1,68 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
+
import { parseEnvString } from "../../core/env.js";
|
|
3
4
|
import { runCommand } from "../../core/exec.js";
|
|
4
|
-
import {
|
|
5
|
+
import { fetchEnvExample } from "../../core/fetch.js";
|
|
6
|
+
import { POSTGRES_IMAGE, SEAMLESS_AUTH_API_IMAGE } from "../../core/images.js";
|
|
7
|
+
import { buildAuthEnv, configureAuthLocalEnv, envToDockerBlock, } from "../docker/docker.js";
|
|
5
8
|
const AUTH_REPO = "https://github.com/fells-code/seamless-auth-api";
|
|
6
|
-
|
|
7
|
-
export async function generateAuthServer(context, mode) {
|
|
9
|
+
export async function generateAuthServer(context, mode, oauth = []) {
|
|
8
10
|
const { root } = context;
|
|
9
11
|
if (mode === "local") {
|
|
10
|
-
await setupLocalAuth(root);
|
|
11
|
-
}
|
|
12
|
-
else {
|
|
13
|
-
await setupDockerAuth(root);
|
|
12
|
+
return await setupLocalAuth(root, oauth);
|
|
14
13
|
}
|
|
14
|
+
return await setupDockerAuth(root);
|
|
15
15
|
}
|
|
16
|
-
async function setupLocalAuth(root) {
|
|
16
|
+
async function setupLocalAuth(root, oauth = []) {
|
|
17
17
|
const authDir = path.join(root, "auth");
|
|
18
18
|
console.log("Cloning SeamlessAuth server...");
|
|
19
19
|
await runCommand("git", ["clone", AUTH_REPO, "auth"], root);
|
|
20
20
|
console.log("Writing auth environment...");
|
|
21
|
-
|
|
22
|
-
PORT: AUTH_PORT,
|
|
23
|
-
NODE_ENV: "development",
|
|
24
|
-
AUTH_MODE: "server",
|
|
25
|
-
ISSUER: `http://localhost:${AUTH_PORT}`,
|
|
26
|
-
});
|
|
21
|
+
const shared = await configureAuthLocalEnv(root, oauth);
|
|
27
22
|
console.log("Auth server ready in /auth");
|
|
23
|
+
return shared;
|
|
28
24
|
}
|
|
29
25
|
async function setupDockerAuth(root) {
|
|
30
26
|
console.log("Creating docker-compose for SeamlessAuth...");
|
|
27
|
+
const raw = await fetchEnvExample();
|
|
28
|
+
const parsed = parseEnvString(raw);
|
|
29
|
+
const { env, shared } = buildAuthEnv(parsed, "docker");
|
|
30
|
+
const envBlock = envToDockerBlock(env);
|
|
31
31
|
const dockerCompose = `
|
|
32
32
|
services:
|
|
33
|
+
db:
|
|
34
|
+
image: ${POSTGRES_IMAGE}
|
|
35
|
+
container_name: seamless-db
|
|
36
|
+
ports:
|
|
37
|
+
- "5432:5432"
|
|
38
|
+
environment:
|
|
39
|
+
POSTGRES_USER: myuser
|
|
40
|
+
POSTGRES_PASSWORD: mypassword
|
|
41
|
+
POSTGRES_DB: postgres
|
|
42
|
+
volumes:
|
|
43
|
+
- pgdata:/var/lib/postgresql/data
|
|
44
|
+
healthcheck:
|
|
45
|
+
test: ["CMD-SHELL", "pg_isready -U myuser -d postgres"]
|
|
46
|
+
interval: 5s
|
|
47
|
+
timeout: 5s
|
|
48
|
+
retries: 5
|
|
49
|
+
|
|
33
50
|
auth:
|
|
34
|
-
image:
|
|
51
|
+
image: ${SEAMLESS_AUTH_API_IMAGE}
|
|
35
52
|
container_name: seamless-auth
|
|
36
53
|
ports:
|
|
37
54
|
- "5312:5312"
|
|
38
55
|
environment:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
56
|
+
${envBlock}
|
|
57
|
+
depends_on:
|
|
58
|
+
db:
|
|
59
|
+
condition: service_healthy
|
|
60
|
+
|
|
61
|
+
volumes:
|
|
62
|
+
pgdata:
|
|
43
63
|
`;
|
|
44
64
|
fs.writeFileSync(path.join(root, "docker-compose.yml"), dockerCompose.trim() + "\n");
|
|
45
65
|
console.log("Docker setup ready.");
|
|
66
|
+
return shared;
|
|
46
67
|
}
|
|
47
68
|
//# sourceMappingURL=auth.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/generators/auth/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/generators/auth/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAG7B,MAAM,SAAS,GAAG,iDAAiD,CAAC;AAEpE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAY,EACZ,IAAiC,EACjC,QAAkC,EAAE;IAEpC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IAEzB,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,OAAO,MAAM,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,IAAY,EAAE,QAAkC,EAAE;IAC9E,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAExC,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAE9C,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;IAE5D,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;IAE3C,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAExD,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAC1C,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,IAAY;IACzC,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;IAE3D,MAAM,GAAG,GAAG,MAAM,eAAe,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAEvC,MAAM,aAAa,GAAG;;;aAGX,cAAc;;;;;;;;;;;;;;;;;aAiBd,uBAAuB;;;;;EAKlC,QAAQ;;;;;;;CAOT,CAAC;IAEA,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC,EACrC,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAC5B,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACnC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { VERSION } from "../../index.js";
|
|
4
|
+
import { SEAMLESS_AUTH_ADMIN_DASHBOARD_IMAGE, SEAMLESS_AUTH_API_IMAGE, } from "../../core/images.js";
|
|
4
5
|
export function generateSeamlessConfig(root, options) {
|
|
5
6
|
const config = {
|
|
6
7
|
version: VERSION,
|
|
@@ -17,15 +18,13 @@ export function generateSeamlessConfig(root, options) {
|
|
|
17
18
|
},
|
|
18
19
|
auth: {
|
|
19
20
|
mode: options.authMode,
|
|
20
|
-
image: options.authMode === "docker"
|
|
21
|
-
? "ghcr.io/fells-code/seamless-auth-api:latest"
|
|
22
|
-
: null,
|
|
21
|
+
image: options.authMode === "docker" ? SEAMLESS_AUTH_API_IMAGE : null,
|
|
23
22
|
path: options.authMode === "local" ? "./auth" : null,
|
|
24
23
|
},
|
|
25
24
|
admin: {
|
|
26
25
|
mode: options.adminMode,
|
|
27
26
|
image: options.adminMode === "image"
|
|
28
|
-
?
|
|
27
|
+
? SEAMLESS_AUTH_ADMIN_DASHBOARD_IMAGE
|
|
29
28
|
: null,
|
|
30
29
|
path: options.adminMode === "source" ? "./admin" : null,
|
|
31
30
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/generators/config/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/generators/config/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EACL,mCAAmC,EACnC,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,UAAU,sBAAsB,CACpC,IAAY,EACZ,OAMC;IAED,MAAM,MAAM,GAAG;QACb,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QACvD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAEnC,QAAQ,EAAE;YACR,GAAG,EAAE;gBACH,SAAS,EAAE,OAAO,CAAC,YAAY;gBAC/B,IAAI,EAAE,OAAO;aACd;YACD,GAAG,EAAE;gBACH,SAAS,EAAE,OAAO,CAAC,YAAY;gBAC/B,IAAI,EAAE,OAAO;aACd;YACD,IAAI,EAAE;gBACJ,IAAI,EAAE,OAAO,CAAC,QAAQ;gBACtB,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI;gBACrE,IAAI,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI;aACrD;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,OAAO,CAAC,SAAS;gBACvB,KAAK,EACH,OAAO,CAAC,SAAS,KAAK,OAAO;oBAC3B,CAAC,CAAC,mCAAmC;oBACrC,CAAC,CAAC,IAAI;gBACV,IAAI,EAAE,OAAO,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;aACxD;YACD,QAAQ,EAAE;gBACR,IAAI,EAAE,UAAU;aACjB;SACF;QAED,MAAM,EAAE;YACN,WAAW,EAAE,oBAAoB;SAClC;KACF,CAAC;IAEF,EAAE,CAAC,aAAa,CACd,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,sBAAsB,CAAC,EACvC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAChC,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;AAC1C,CAAC"}
|
|
@@ -4,6 +4,8 @@ import { fetchEnvExample } from "../../core/fetch.js";
|
|
|
4
4
|
import { parseEnv, parseEnvString } from "../../core/env.js";
|
|
5
5
|
import { generateSecret } from "../../core/secrets.js";
|
|
6
6
|
import { generateJWKS } from "../../core/jwks.js";
|
|
7
|
+
import { buildOAuthAuthEnv, withLoginMethod, } from "../../core/oauthProviders.js";
|
|
8
|
+
import { POSTGRES_IMAGE, SEAMLESS_AUTH_ADMIN_DASHBOARD_IMAGE, SEAMLESS_AUTH_API_IMAGE, } from "../../core/images.js";
|
|
7
9
|
export async function generateDockerCompose(root, options) {
|
|
8
10
|
const { compose, shared } = await buildCompose(options, root);
|
|
9
11
|
fs.writeFileSync(path.join(root, "docker-compose.yml"), compose.trim() + "\n");
|
|
@@ -11,13 +13,13 @@ export async function generateDockerCompose(root, options) {
|
|
|
11
13
|
return shared;
|
|
12
14
|
}
|
|
13
15
|
async function buildCompose(options, root) {
|
|
14
|
-
const { authMode, adminMode, includeAdmin } = options;
|
|
15
|
-
const { service: authBlock, shared } = await authService(authMode, root);
|
|
16
|
+
const { authMode, adminMode, includeAdmin, oauth } = options;
|
|
17
|
+
const { service: authBlock, shared } = await authService(authMode, root, oauth);
|
|
16
18
|
return {
|
|
17
19
|
compose: `
|
|
18
20
|
services:
|
|
19
21
|
db:
|
|
20
|
-
image:
|
|
22
|
+
image: ${POSTGRES_IMAGE}
|
|
21
23
|
container_name: seamless-db
|
|
22
24
|
ports:
|
|
23
25
|
- "5432:5432"
|
|
@@ -27,6 +29,11 @@ services:
|
|
|
27
29
|
POSTGRES_DB: postgres
|
|
28
30
|
volumes:
|
|
29
31
|
- pgdata:/var/lib/postgresql/data
|
|
32
|
+
healthcheck:
|
|
33
|
+
test: ["CMD-SHELL", "pg_isready -U myuser -d postgres"]
|
|
34
|
+
interval: 5s
|
|
35
|
+
timeout: 5s
|
|
36
|
+
retries: 5
|
|
30
37
|
|
|
31
38
|
${authBlock}
|
|
32
39
|
|
|
@@ -42,9 +49,9 @@ volumes:
|
|
|
42
49
|
shared,
|
|
43
50
|
};
|
|
44
51
|
}
|
|
45
|
-
async function authService(mode, root) {
|
|
52
|
+
async function authService(mode, root, oauth = []) {
|
|
46
53
|
if (mode === "local") {
|
|
47
|
-
const shared = await configureAuthLocalEnv(root);
|
|
54
|
+
const shared = await configureAuthLocalEnv(root, oauth);
|
|
48
55
|
return {
|
|
49
56
|
service: `
|
|
50
57
|
auth:
|
|
@@ -63,12 +70,13 @@ async function authService(mode, root) {
|
|
|
63
70
|
- ./auth:/app
|
|
64
71
|
- /app/node_modules
|
|
65
72
|
depends_on:
|
|
66
|
-
|
|
73
|
+
db:
|
|
74
|
+
condition: service_healthy
|
|
67
75
|
`,
|
|
68
76
|
shared,
|
|
69
77
|
};
|
|
70
78
|
}
|
|
71
|
-
return await authServiceDocker();
|
|
79
|
+
return await authServiceDocker(oauth);
|
|
72
80
|
}
|
|
73
81
|
function apiService(shared) {
|
|
74
82
|
return `
|
|
@@ -89,8 +97,10 @@ function apiService(shared) {
|
|
|
89
97
|
- ./api:/app
|
|
90
98
|
- /app/node_modules
|
|
91
99
|
depends_on:
|
|
92
|
-
|
|
93
|
-
|
|
100
|
+
db:
|
|
101
|
+
condition: service_healthy
|
|
102
|
+
auth:
|
|
103
|
+
condition: service_started
|
|
94
104
|
`;
|
|
95
105
|
}
|
|
96
106
|
function webService() {
|
|
@@ -107,24 +117,30 @@ function webService() {
|
|
|
107
117
|
- /app/node_modules
|
|
108
118
|
depends_on:
|
|
109
119
|
- api
|
|
120
|
+
healthcheck:
|
|
121
|
+
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost/health"]
|
|
122
|
+
interval: 5s
|
|
123
|
+
timeout: 5s
|
|
124
|
+
retries: 10
|
|
110
125
|
`;
|
|
111
126
|
}
|
|
112
|
-
async function authServiceDocker() {
|
|
127
|
+
async function authServiceDocker(oauth = []) {
|
|
113
128
|
const raw = await fetchEnvExample();
|
|
114
129
|
const parsed = parseEnvString(raw);
|
|
115
|
-
const { env, shared } = buildAuthEnv(parsed, "docker");
|
|
130
|
+
const { env, shared } = buildAuthEnv(parsed, "docker", oauth);
|
|
116
131
|
const envBlock = envToDockerBlock(env);
|
|
117
132
|
return {
|
|
118
133
|
service: `
|
|
119
134
|
auth:
|
|
120
|
-
image:
|
|
135
|
+
image: ${SEAMLESS_AUTH_API_IMAGE}
|
|
121
136
|
container_name: seamless-auth
|
|
122
137
|
ports:
|
|
123
138
|
- "5312:5312"
|
|
124
139
|
environment:
|
|
125
140
|
${envBlock}
|
|
126
141
|
depends_on:
|
|
127
|
-
|
|
142
|
+
db:
|
|
143
|
+
condition: service_healthy
|
|
128
144
|
`,
|
|
129
145
|
shared,
|
|
130
146
|
};
|
|
@@ -149,7 +165,7 @@ function adminService(mode) {
|
|
|
149
165
|
}
|
|
150
166
|
return `
|
|
151
167
|
admin:
|
|
152
|
-
image:
|
|
168
|
+
image: ${SEAMLESS_AUTH_ADMIN_DASHBOARD_IMAGE}
|
|
153
169
|
container_name: admin
|
|
154
170
|
ports:
|
|
155
171
|
- "5174:80"
|
|
@@ -159,30 +175,34 @@ function adminService(mode) {
|
|
|
159
175
|
- api
|
|
160
176
|
`;
|
|
161
177
|
}
|
|
162
|
-
function buildAuthEnv(env, mode) {
|
|
178
|
+
export function buildAuthEnv(env, mode, oauth = []) {
|
|
163
179
|
const apiToken = generateSecret(32);
|
|
164
180
|
const bootstrapSecret = generateSecret(32);
|
|
181
|
+
const kid = "dev-main";
|
|
165
182
|
env.SEAMLESS_BOOTSTRAP_ENABLED = "true";
|
|
166
183
|
env.SEAMLESS_BOOTSTRAP_SECRET = bootstrapSecret;
|
|
167
184
|
env.PORT = "5312";
|
|
168
185
|
env.NODE_ENV = "development";
|
|
169
186
|
env.AUTH_MODE = "server";
|
|
170
|
-
env.ISSUER =
|
|
187
|
+
env.ISSUER =
|
|
188
|
+
mode === "docker" ? "http://auth:5312" : "http://localhost:5312";
|
|
171
189
|
env.DB_HOST = mode === "docker" ? "db" : "localhost";
|
|
172
190
|
env.DB_PORT = "5432";
|
|
173
191
|
env.API_SERVICE_TOKEN = apiToken;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
kid = jwks.kid;
|
|
179
|
-
env.SEAMLESS_JWKS_ACTIVE_KID = jwks.kid;
|
|
180
|
-
env.JWKS_ACTIVE_KID = jwks.kid;
|
|
181
|
-
env[`SEAMLESS_JWKS_KEY_${jwks.kid}_PRIVATE`] = jwks.privateKey;
|
|
182
|
-
env.JWKS_PUBLIC_KEYS = jwks.publicJwksJson;
|
|
183
|
-
}
|
|
192
|
+
// Dedicated secrets the auth server otherwise leaves empty (falling back to the
|
|
193
|
+
// service token). Generate real ones so a scaffolded stack is production-shaped.
|
|
194
|
+
env.REFRESH_TOKEN_LOOKUP_SECRET = generateSecret(32);
|
|
195
|
+
env.TOTP_SECRET_ENCRYPTION_KEY = generateSecret(32);
|
|
184
196
|
env.APP_ORIGINS = "http://localhost:3000";
|
|
185
|
-
env.ORIGINS = "http://localhost:5173";
|
|
197
|
+
env.ORIGINS = "http://localhost:5173,http://localhost:5174";
|
|
198
|
+
// When the OAuth template collected providers, wire them into the auth server
|
|
199
|
+
// (OAUTH_PROVIDERS, per-provider secret env vars, OAUTH_STATE_SECRET) and enable
|
|
200
|
+
// the oauth login method.
|
|
201
|
+
if (oauth.length > 0) {
|
|
202
|
+
const { env: oauthEnv } = buildOAuthAuthEnv(oauth);
|
|
203
|
+
Object.assign(env, oauthEnv);
|
|
204
|
+
env.LOGIN_METHODS = withLoginMethod(env.LOGIN_METHODS, "oauth");
|
|
205
|
+
}
|
|
186
206
|
return {
|
|
187
207
|
env,
|
|
188
208
|
shared: {
|
|
@@ -198,7 +218,7 @@ export function envToDockerBlock(env) {
|
|
|
198
218
|
if (v.includes("\n")) {
|
|
199
219
|
return ` ${k}: |\n${indentMultiline(v, 8)}`;
|
|
200
220
|
}
|
|
201
|
-
return ` ${k}: ${v}`;
|
|
221
|
+
return ` ${k}: ${JSON.stringify(v)}`;
|
|
202
222
|
})
|
|
203
223
|
.join("\n");
|
|
204
224
|
}
|
|
@@ -226,7 +246,7 @@ export function buildJWKSConfig() {
|
|
|
226
246
|
}, null, 2),
|
|
227
247
|
};
|
|
228
248
|
}
|
|
229
|
-
export async function configureAuthLocalEnv(root) {
|
|
249
|
+
export async function configureAuthLocalEnv(root, oauth = []) {
|
|
230
250
|
const authDir = path.join(root, "auth");
|
|
231
251
|
const envExamplePath = path.join(authDir, ".env.example");
|
|
232
252
|
const envPath = path.join(authDir, ".env");
|
|
@@ -235,7 +255,7 @@ export async function configureAuthLocalEnv(root) {
|
|
|
235
255
|
}
|
|
236
256
|
const raw = fs.readFileSync(envExamplePath, "utf-8");
|
|
237
257
|
const parsed = parseEnvString(raw);
|
|
238
|
-
const { env, shared } = buildAuthEnv(parsed, "local");
|
|
258
|
+
const { env, shared } = buildAuthEnv(parsed, "local", oauth);
|
|
239
259
|
writeEnvFile(envPath, env);
|
|
240
260
|
return shared;
|
|
241
261
|
}
|
|
@@ -257,7 +277,7 @@ export function extractSharedFromExistingEnv(root) {
|
|
|
257
277
|
const env = parseEnv(path.join(root, "auth", ".env"));
|
|
258
278
|
return {
|
|
259
279
|
apiToken: env.API_SERVICE_TOKEN,
|
|
260
|
-
kid: env.JWKS_ACTIVE_KID || "main",
|
|
280
|
+
kid: env.SEAMLESS_JWKS_ACTIVE_KID || env.JWKS_ACTIVE_KID || "dev-main",
|
|
261
281
|
};
|
|
262
282
|
}
|
|
263
283
|
//# sourceMappingURL=docker.js.map
|