swallowkit 1.0.0-beta.55 → 1.0.0-beta.57
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/cli/commands/add-auth.d.ts.map +1 -1
- package/dist/cli/commands/add-auth.js +154 -157
- package/dist/cli/commands/add-auth.js.map +1 -1
- package/dist/cli/commands/init.d.ts +5 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +178 -25
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/scaffold.d.ts +7 -2
- package/dist/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +113 -123
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +127 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +8 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/operations/auth-operations.d.ts +57 -0
- package/dist/core/operations/auth-operations.d.ts.map +1 -0
- package/dist/core/operations/auth-operations.js +269 -0
- package/dist/core/operations/auth-operations.js.map +1 -0
- package/dist/core/operations/create-model.d.ts.map +1 -1
- package/dist/core/operations/create-model.js +23 -13
- package/dist/core/operations/create-model.js.map +1 -1
- package/dist/core/operations/file-session.d.ts +56 -0
- package/dist/core/operations/file-session.d.ts.map +1 -0
- package/dist/core/operations/file-session.js +203 -0
- package/dist/core/operations/file-session.js.map +1 -0
- package/dist/core/operations/provision-operations.d.ts +52 -0
- package/dist/core/operations/provision-operations.d.ts.map +1 -0
- package/dist/core/operations/provision-operations.js +211 -0
- package/dist/core/operations/provision-operations.js.map +1 -0
- package/dist/core/operations/runtime.d.ts +5 -0
- package/dist/core/operations/runtime.d.ts.map +1 -1
- package/dist/core/operations/runtime.js +23 -0
- package/dist/core/operations/runtime.js.map +1 -1
- package/dist/core/operations/scaffold-apply.d.ts +21 -0
- package/dist/core/operations/scaffold-apply.d.ts.map +1 -0
- package/dist/core/operations/scaffold-apply.js +57 -0
- package/dist/core/operations/scaffold-apply.js.map +1 -0
- package/dist/core/operations/scaffold-machine.d.ts.map +1 -1
- package/dist/core/operations/scaffold-machine.js +1 -13
- package/dist/core/operations/scaffold-machine.js.map +1 -1
- package/dist/core/operations/scaffold-plan.d.ts +43 -0
- package/dist/core/operations/scaffold-plan.d.ts.map +1 -0
- package/dist/core/operations/scaffold-plan.js +187 -0
- package/dist/core/operations/scaffold-plan.js.map +1 -0
- package/dist/core/project/artifacts.d.ts +58 -0
- package/dist/core/project/artifacts.d.ts.map +1 -0
- package/dist/core/project/artifacts.js +179 -0
- package/dist/core/project/artifacts.js.map +1 -0
- package/dist/core/project/boundaries.d.ts +50 -0
- package/dist/core/project/boundaries.d.ts.map +1 -0
- package/dist/core/project/boundaries.js +117 -0
- package/dist/core/project/boundaries.js.map +1 -0
- package/dist/core/project/drift.d.ts +29 -0
- package/dist/core/project/drift.d.ts.map +1 -0
- package/dist/core/project/drift.js +188 -0
- package/dist/core/project/drift.js.map +1 -0
- package/dist/core/project/infra.d.ts +49 -0
- package/dist/core/project/infra.d.ts.map +1 -0
- package/dist/core/project/infra.js +167 -0
- package/dist/core/project/infra.js.map +1 -0
- package/dist/core/project/state.d.ts +15 -0
- package/dist/core/project/state.d.ts.map +1 -0
- package/dist/core/project/state.js +106 -0
- package/dist/core/project/state.js.map +1 -0
- package/dist/core/project/workflows.d.ts +43 -0
- package/dist/core/project/workflows.d.ts.map +1 -0
- package/dist/core/project/workflows.js +255 -0
- package/dist/core/project/workflows.js.map +1 -0
- package/dist/core/scaffold/auth-generator.d.ts.map +1 -1
- package/dist/core/scaffold/auth-generator.js +24 -27
- package/dist/core/scaffold/auth-generator.js.map +1 -1
- package/dist/core/scaffold/functions-generator.js +9 -9
- package/dist/core/scaffold/native-schema-generator.d.ts +7 -1
- package/dist/core/scaffold/native-schema-generator.d.ts.map +1 -1
- package/dist/core/scaffold/native-schema-generator.js +104 -47
- package/dist/core/scaffold/native-schema-generator.js.map +1 -1
- package/dist/core/scaffold/nextjs-generator.js +6 -6
- package/dist/core/scaffold/ui-generator.js +19 -19
- package/dist/core/scaffold/ui-generator.js.map +1 -1
- package/dist/core/verify/index.d.ts +62 -0
- package/dist/core/verify/index.d.ts.map +1 -0
- package/dist/core/verify/index.js +343 -0
- package/dist/core/verify/index.js.map +1 -0
- package/dist/machine/contracts.d.ts +8 -0
- package/dist/machine/contracts.d.ts.map +1 -1
- package/dist/machine/errors.d.ts +4 -1
- package/dist/machine/errors.d.ts.map +1 -1
- package/dist/machine/errors.js +9 -1
- package/dist/machine/errors.js.map +1 -1
- package/dist/machine/index.d.ts.map +1 -1
- package/dist/machine/index.js +350 -16
- package/dist/machine/index.js.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +202 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/functions-generator.test.ts.snap +17 -17
- package/src/__tests__/__snapshots__/nextjs-generator.test.ts.snap +6 -6
- package/src/__tests__/__snapshots__/ui-generator.test.ts.snap +11 -11
- package/src/__tests__/agent-loop-phase34.test.ts +449 -0
- package/src/__tests__/file-session.test.ts +98 -0
- package/src/__tests__/init.test.ts +50 -0
- package/src/__tests__/mcp.test.ts +113 -5
- package/src/__tests__/plan-apply.test.ts +461 -0
- package/src/__tests__/scaffold.test.ts +2 -2
- package/src/cli/commands/add-auth.ts +164 -164
- package/src/cli/commands/init.ts +186 -24
- package/src/cli/commands/scaffold.ts +136 -130
- package/src/cli/index.ts +148 -2
- package/src/core/config.ts +5 -4
- package/src/core/operations/auth-operations.ts +353 -0
- package/src/core/operations/create-model.ts +25 -13
- package/src/core/operations/file-session.ts +222 -0
- package/src/core/operations/provision-operations.ts +297 -0
- package/src/core/operations/runtime.ts +23 -0
- package/src/core/operations/scaffold-apply.ts +106 -0
- package/src/core/operations/scaffold-machine.ts +2 -16
- package/src/core/operations/scaffold-plan.ts +215 -0
- package/src/core/project/artifacts.ts +205 -0
- package/src/core/project/boundaries.ts +170 -0
- package/src/core/project/drift.ts +202 -0
- package/src/core/project/infra.ts +196 -0
- package/src/core/project/state.ts +77 -0
- package/src/core/project/workflows.ts +249 -0
- package/src/core/scaffold/auth-generator.ts +24 -27
- package/src/core/scaffold/functions-generator.ts +9 -9
- package/src/core/scaffold/native-schema-generator.ts +152 -70
- package/src/core/scaffold/nextjs-generator.ts +6 -6
- package/src/core/scaffold/ui-generator.ts +19 -19
- package/src/core/verify/index.ts +392 -0
- package/src/machine/contracts.ts +16 -0
- package/src/machine/errors.ts +12 -1
- package/src/machine/index.ts +444 -15
- package/src/mcp/index.ts +198 -2
- package/src/types/index.ts +17 -0
|
@@ -44,6 +44,8 @@ import {
|
|
|
44
44
|
generateNamedExternalTokenVerifierPython,
|
|
45
45
|
} from "../../core/scaffold/auth-generator";
|
|
46
46
|
import { syncProjectManifest } from "../../core/project/manifest";
|
|
47
|
+
import { FileOperationSession, getActiveFileSession } from "../../core/operations/file-session";
|
|
48
|
+
import { recordSessionOperations } from "../../core/project/artifacts";
|
|
47
49
|
import { buildSharedTsConfig } from "./init";
|
|
48
50
|
|
|
49
51
|
interface AddAuthOptions {
|
|
@@ -51,10 +53,14 @@ interface AddAuthOptions {
|
|
|
51
53
|
scheme?: string;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
const AUTH_GENERATOR = "add-auth";
|
|
57
|
+
const managedMeta = { ownership: "managed" as const, generator: AUTH_GENERATOR };
|
|
58
|
+
const extensionMeta = { ownership: "extension-point" as const, generator: AUTH_GENERATOR };
|
|
59
|
+
const onceMeta = { ownership: "generated-once" as const, generator: AUTH_GENERATOR };
|
|
60
|
+
|
|
61
|
+
function writeIfMissing(session: FileOperationSession, filePath: string, content: string): void {
|
|
62
|
+
if (session.fileExists(filePath)) return;
|
|
63
|
+
session.writeFile(filePath, content, onceMeta);
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
function defaultCustomJwtConfig(): CustomJwtConfig {
|
|
@@ -69,79 +75,72 @@ function defaultCustomJwtConfig(): CustomJwtConfig {
|
|
|
69
75
|
};
|
|
70
76
|
}
|
|
71
77
|
|
|
72
|
-
function setupSwaAuth(cwd: string, backendLanguage: BackendLanguage): void {
|
|
78
|
+
function setupSwaAuth(cwd: string, backendLanguage: BackendLanguage, session: FileOperationSession): void {
|
|
73
79
|
const helperPath = backendLanguage === "typescript"
|
|
74
80
|
? path.join(cwd, "functions", "src", "auth", "jwt-helper.ts")
|
|
75
81
|
: backendLanguage === "csharp"
|
|
76
82
|
? path.join(cwd, "functions", "Auth", "JwtHelper.cs")
|
|
77
83
|
: path.join(cwd, "functions", "auth", "jwt_helper.py");
|
|
78
|
-
fs.mkdirSync(path.dirname(helperPath), { recursive: true });
|
|
79
84
|
const helper = backendLanguage === "typescript"
|
|
80
85
|
? generateSwaAuthHelperTS()
|
|
81
86
|
: backendLanguage === "csharp"
|
|
82
87
|
? generateSwaAuthHelperCSharp()
|
|
83
88
|
: generateSwaAuthHelperPython();
|
|
84
|
-
|
|
89
|
+
session.writeFile(helperPath, helper, managedMeta);
|
|
85
90
|
|
|
86
91
|
const callFnPath = path.join(cwd, "lib", "api", "call-function.ts");
|
|
87
|
-
|
|
88
|
-
fs.writeFileSync(callFnPath, generateBFFCallFunctionWithSwaAuth(), "utf-8");
|
|
92
|
+
session.writeFile(callFnPath, generateBFFCallFunctionWithSwaAuth(), managedMeta);
|
|
89
93
|
|
|
90
94
|
const authDir = path.join(cwd, "lib", "auth");
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
updateRootLayoutWithAuthProvider(cwd);
|
|
95
|
+
session.writeFile(path.join(authDir, "auth-context.tsx"), generateSwaAuthContext(), managedMeta);
|
|
96
|
+
updateRootLayoutWithAuthProvider(cwd, session);
|
|
94
97
|
const loginDir = path.join(cwd, "app", "login");
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
updateSwaRouteConfig(cwd);
|
|
98
|
+
session.writeFile(path.join(loginDir, "page.tsx"), generateSwaLoginPage(), managedMeta);
|
|
99
|
+
updateSwaRouteConfig(cwd, session);
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
function setupExternalTokenAuth(cwd: string, backendLanguage: BackendLanguage): void {
|
|
102
|
+
function setupExternalTokenAuth(cwd: string, backendLanguage: BackendLanguage, session: FileOperationSession): void {
|
|
101
103
|
const authDir = path.join(cwd, "lib", "auth");
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
fs.writeFileSync(path.join(cwd, "lib", "api", "call-function.ts"), generateBFFCallFunctionWithAuth(), "utf-8");
|
|
104
|
+
writeIfMissing(session, path.join(authDir, "external-token-adapter.ts"), generateExternalTokenAdapter());
|
|
105
|
+
session.writeFile(path.join(authDir, "authenticated-fetch.ts"), generateAuthenticatedFetch(), managedMeta);
|
|
106
|
+
session.writeFile(path.join(authDir, "auth-context.tsx"), generateExternalTokenAuthContext(), managedMeta);
|
|
107
|
+
session.writeFile(path.join(cwd, "lib", "api", "call-function.ts"), generateBFFCallFunctionWithAuth(), managedMeta);
|
|
107
108
|
const meDir = path.join(cwd, "app", "api", "auth", "me");
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
updateRootLayoutWithAuthProvider(cwd);
|
|
109
|
+
session.writeFile(path.join(meDir, "route.ts"), generateExternalTokenBFFMeRoute(), managedMeta);
|
|
110
|
+
updateRootLayoutWithAuthProvider(cwd, session);
|
|
111
111
|
|
|
112
112
|
if (backendLanguage === "typescript") {
|
|
113
113
|
const verifier = path.join(cwd, "functions", "src", "auth", "external-token-verifier.ts");
|
|
114
|
-
writeIfMissing(verifier, generateExternalTokenVerifierTS());
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
writeIfMissing(session, verifier, generateExternalTokenVerifierTS());
|
|
115
|
+
session.writeFile(path.join(cwd, "functions", "src", "auth", "jwt-helper.ts"), generateExternalTokenHelperTS(), managedMeta);
|
|
116
|
+
session.writeFile(path.join(cwd, "functions", "src", "auth-me.ts"), generateExternalAuthMeTS(), managedMeta);
|
|
117
117
|
} else if (backendLanguage === "csharp") {
|
|
118
118
|
const verifier = path.join(cwd, "functions", "Auth", "ExternalTokenVerifier.cs");
|
|
119
|
-
writeIfMissing(verifier, generateExternalTokenVerifierCSharp());
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
writeIfMissing(session, verifier, generateExternalTokenVerifierCSharp());
|
|
120
|
+
session.writeFile(path.join(cwd, "functions", "Auth", "JwtHelper.cs"), generateExternalTokenHelperCSharp(), managedMeta);
|
|
121
|
+
session.writeFile(path.join(cwd, "functions", "Auth", "ExternalAuthMe.cs"), generateExternalAuthMeCSharp(), managedMeta);
|
|
122
122
|
} else {
|
|
123
123
|
const verifier = path.join(cwd, "functions", "auth", "external_token_verifier.py");
|
|
124
|
-
writeIfMissing(verifier, generateExternalTokenVerifierPython());
|
|
125
|
-
|
|
124
|
+
writeIfMissing(session, verifier, generateExternalTokenVerifierPython());
|
|
125
|
+
session.writeFile(path.join(cwd, "functions", "auth", "jwt_helper.py"), generateExternalTokenHelperPython(), managedMeta);
|
|
126
126
|
const authMePath = path.join(cwd, "functions", "blueprints", "auth_me.py");
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
updatePythonAuthMeRegistration(cwd);
|
|
127
|
+
session.writeFile(authMePath, generateExternalAuthMePython(), managedMeta);
|
|
128
|
+
updatePythonAuthMeRegistration(cwd, session);
|
|
130
129
|
}
|
|
131
130
|
}
|
|
132
131
|
|
|
133
|
-
function updatePythonAuthMeRegistration(cwd: string): void {
|
|
132
|
+
function updatePythonAuthMeRegistration(cwd: string, session: FileOperationSession): void {
|
|
134
133
|
const appPath = path.join(cwd, "functions", "function_app.py");
|
|
135
|
-
if (!
|
|
134
|
+
if (!session.fileExists(appPath)) return;
|
|
136
135
|
const importLine = "from blueprints.auth_me import bp as external_auth_me_bp";
|
|
137
136
|
const registerLine = "app.register_blueprint(external_auth_me_bp)";
|
|
138
|
-
let content =
|
|
137
|
+
let content = session.readFile(appPath);
|
|
139
138
|
if (content.includes(importLine)) return;
|
|
140
139
|
const marker = "# SwallowKit scaffold registrations";
|
|
141
140
|
content = content.includes(marker)
|
|
142
141
|
? content.replace(marker, `${importLine}\n${registerLine}\n${marker}`)
|
|
143
142
|
: `${content.trimEnd()}\n${importLine}\n${registerLine}\n`;
|
|
144
|
-
|
|
143
|
+
session.writeFile(appPath, content, extensionMeta);
|
|
145
144
|
}
|
|
146
145
|
|
|
147
146
|
function generateSwaLoginPage(): string {
|
|
@@ -210,25 +209,25 @@ export function addAuthProviderToRootLayout(layout: string): string {
|
|
|
210
209
|
return updated;
|
|
211
210
|
}
|
|
212
211
|
|
|
213
|
-
function updateRootLayoutWithAuthProvider(cwd: string): void {
|
|
212
|
+
function updateRootLayoutWithAuthProvider(cwd: string, session: FileOperationSession): void {
|
|
214
213
|
const layoutPath = path.join(cwd, "app", "layout.tsx");
|
|
215
|
-
if (!
|
|
214
|
+
if (!session.fileExists(layoutPath)) {
|
|
216
215
|
throw new Error("app/layout.tsx was not found; cannot install AuthProvider");
|
|
217
216
|
}
|
|
218
|
-
const layout =
|
|
217
|
+
const layout = session.readFile(layoutPath);
|
|
219
218
|
const updated = addAuthProviderToRootLayout(layout);
|
|
220
|
-
if (updated !== layout)
|
|
219
|
+
if (updated !== layout) session.writeFile(layoutPath, updated, extensionMeta);
|
|
221
220
|
}
|
|
222
221
|
|
|
223
|
-
function updateSwaRouteConfig(cwd: string): void {
|
|
222
|
+
function updateSwaRouteConfig(cwd: string, session: FileOperationSession): void {
|
|
224
223
|
const configPath = path.join(cwd, "staticwebapp.config.json");
|
|
225
|
-
const config =
|
|
224
|
+
const config = session.fileExists(configPath) ? JSON.parse(session.readFile(configPath)) : {};
|
|
226
225
|
config.routes = Array.isArray(config.routes)
|
|
227
226
|
? config.routes.filter((route: { route?: string }) => route.route !== "/api/*")
|
|
228
227
|
: [];
|
|
229
228
|
config.routes.unshift({ route: "/api/*", allowedRoles: ["authenticated"] });
|
|
230
229
|
config.responseOverrides = { ...(config.responseOverrides || {}), "401": { statusCode: 302, redirect: "/.auth/login/aad?post_login_redirect_uri=.referrer" } };
|
|
231
|
-
|
|
230
|
+
session.writeFile(configPath, JSON.stringify(config, null, 2), extensionMeta);
|
|
232
231
|
}
|
|
233
232
|
|
|
234
233
|
export async function addAuthCommand(options: AddAuthOptions) {
|
|
@@ -246,11 +245,20 @@ export async function addAuthCommand(options: AddAuthOptions) {
|
|
|
246
245
|
const config = getValidatedFullConfig();
|
|
247
246
|
const cwd = process.cwd();
|
|
248
247
|
|
|
248
|
+
// Plan(dry-run) や Apply からセッションが供給される。単体実行時は commit セッションを生成。
|
|
249
|
+
const session = getActiveFileSession() ?? new FileOperationSession("commit");
|
|
250
|
+
const finalize = async () => {
|
|
251
|
+
if (session.mode === "commit") {
|
|
252
|
+
recordSessionOperations(session.operations);
|
|
253
|
+
await syncProjectManifest();
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
249
257
|
if (options.scheme) {
|
|
250
258
|
if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(options.scheme)) throw new Error("--scheme must start with a letter and contain only letters, digits, '_' or '-'");
|
|
251
259
|
if (provider === "none" || provider === "swa-custom") throw new Error(`Provider '${provider}' cannot be added as a named scheme`);
|
|
252
|
-
addNamedScheme(cwd, options.scheme, provider, backendLanguage);
|
|
253
|
-
await
|
|
260
|
+
addNamedScheme(cwd, options.scheme, provider, backendLanguage, session);
|
|
261
|
+
await finalize();
|
|
254
262
|
console.log(`\n Named authentication scheme '${options.scheme}' added.`);
|
|
255
263
|
return;
|
|
256
264
|
}
|
|
@@ -259,22 +267,22 @@ export async function addAuthCommand(options: AddAuthOptions) {
|
|
|
259
267
|
throw new Error("The swa-custom provider is not implemented. Use --provider swa or --provider custom-jwt.");
|
|
260
268
|
}
|
|
261
269
|
if (provider === "none") {
|
|
262
|
-
updateConfigWithAuth(cwd, provider, config.auth?.customJwt || defaultCustomJwtConfig());
|
|
263
|
-
await
|
|
270
|
+
updateConfigWithAuth(cwd, provider, config.auth?.customJwt || defaultCustomJwtConfig(), session);
|
|
271
|
+
await finalize();
|
|
264
272
|
console.log(" Authentication disabled in swallowkit.config.js");
|
|
265
273
|
return;
|
|
266
274
|
}
|
|
267
275
|
if (provider === "swa") {
|
|
268
|
-
setupSwaAuth(cwd, backendLanguage);
|
|
269
|
-
updateConfigWithAuth(cwd, provider, config.auth?.customJwt || defaultCustomJwtConfig());
|
|
270
|
-
await
|
|
276
|
+
setupSwaAuth(cwd, backendLanguage, session);
|
|
277
|
+
updateConfigWithAuth(cwd, provider, config.auth?.customJwt || defaultCustomJwtConfig(), session);
|
|
278
|
+
await finalize();
|
|
271
279
|
console.log("\n SWA built-in authentication setup complete!");
|
|
272
280
|
return;
|
|
273
281
|
}
|
|
274
282
|
if (provider === "external-token") {
|
|
275
|
-
setupExternalTokenAuth(cwd, backendLanguage);
|
|
276
|
-
updateConfigWithAuth(cwd, provider, config.auth?.customJwt || defaultCustomJwtConfig());
|
|
277
|
-
await
|
|
283
|
+
setupExternalTokenAuth(cwd, backendLanguage, session);
|
|
284
|
+
updateConfigWithAuth(cwd, provider, config.auth?.customJwt || defaultCustomJwtConfig(), session);
|
|
285
|
+
await finalize();
|
|
278
286
|
console.log("\n External token authentication setup complete!");
|
|
279
287
|
console.log(" Implement the generated frontend adapter and backend verifier before use.");
|
|
280
288
|
return;
|
|
@@ -301,16 +309,15 @@ export async function addAuthCommand(options: AddAuthOptions) {
|
|
|
301
309
|
// 1. Generate shared/models/auth.ts
|
|
302
310
|
console.log(" Generating auth models...");
|
|
303
311
|
const modelsDir = path.join(cwd, "shared", "models");
|
|
304
|
-
fs.mkdirSync(modelsDir, { recursive: true });
|
|
305
312
|
const authModelPath = path.join(modelsDir, "auth.ts");
|
|
306
|
-
|
|
313
|
+
session.writeFile(authModelPath, generateAuthModels(), managedMeta);
|
|
307
314
|
console.log(` Created: shared/models/auth.ts`);
|
|
308
315
|
|
|
309
316
|
// Ensure shared package has build infrastructure (tsconfig, build script)
|
|
310
|
-
ensureSharedBuildInfrastructure(cwd);
|
|
317
|
+
ensureSharedBuildInfrastructure(cwd, session);
|
|
311
318
|
|
|
312
319
|
// Update shared/index.ts to re-export auth
|
|
313
|
-
updateSharedIndex(cwd);
|
|
320
|
+
updateSharedIndex(cwd, session);
|
|
314
321
|
|
|
315
322
|
// Resolve RDB provider for dependency installation
|
|
316
323
|
const connDef = getConnectorDefinition(customJwtConfig.userConnector);
|
|
@@ -318,52 +325,48 @@ export async function addAuthCommand(options: AddAuthOptions) {
|
|
|
318
325
|
|
|
319
326
|
// 2. Generate Functions auth code
|
|
320
327
|
console.log("\n Generating auth functions...");
|
|
321
|
-
generateFunctionsAuth(cwd, backendLanguage, sharedPackageName, customJwtConfig);
|
|
328
|
+
generateFunctionsAuth(cwd, backendLanguage, sharedPackageName, customJwtConfig, session);
|
|
322
329
|
|
|
323
330
|
// 3. Generate BFF auth routes
|
|
324
331
|
console.log("\n Generating BFF auth routes...");
|
|
325
|
-
generateBFFAuth(cwd, projectName, sharedPackageName);
|
|
332
|
+
generateBFFAuth(cwd, projectName, sharedPackageName, session);
|
|
326
333
|
|
|
327
334
|
// 4. Generate proxy
|
|
328
335
|
console.log("\n Generating proxy...");
|
|
329
336
|
const proxyPath = path.join(cwd, "proxy.ts");
|
|
330
|
-
|
|
337
|
+
session.writeFile(proxyPath, generateProxy(projectName), managedMeta);
|
|
331
338
|
console.log(` Created: proxy.ts`);
|
|
332
339
|
|
|
333
340
|
// 5. Generate login page
|
|
334
341
|
console.log("\n Generating login page...");
|
|
335
342
|
const loginDir = path.join(cwd, "app", "login");
|
|
336
|
-
|
|
337
|
-
fs.writeFileSync(path.join(loginDir, "page.tsx"), generateLoginPage(), "utf-8");
|
|
343
|
+
session.writeFile(path.join(loginDir, "page.tsx"), generateLoginPage(), managedMeta);
|
|
338
344
|
console.log(` Created: app/login/page.tsx`);
|
|
339
345
|
|
|
340
346
|
// 6. Generate auth context
|
|
341
347
|
console.log("\n Generating auth context...");
|
|
342
348
|
const authLibDir = path.join(cwd, "lib", "auth");
|
|
343
|
-
|
|
344
|
-
fs.writeFileSync(path.join(authLibDir, "auth-context.tsx"), generateAuthContext(), "utf-8");
|
|
349
|
+
session.writeFile(path.join(authLibDir, "auth-context.tsx"), generateAuthContext(), managedMeta);
|
|
345
350
|
console.log(`✅ Created: lib/auth/auth-context.tsx`);
|
|
346
351
|
|
|
347
352
|
// 7. Update callFunction with auth support
|
|
348
353
|
console.log("\n Updating callFunction with auth support...");
|
|
349
354
|
const callFnPath = path.join(cwd, "lib", "api", "call-function.ts");
|
|
350
|
-
|
|
351
|
-
fs.mkdirSync(callFnDir, { recursive: true });
|
|
352
|
-
fs.writeFileSync(callFnPath, generateBFFCallFunctionWithAuth(), "utf-8");
|
|
355
|
+
session.writeFile(callFnPath, generateBFFCallFunctionWithAuth(), managedMeta);
|
|
353
356
|
console.log(` Updated: lib/api/call-function.ts`);
|
|
354
357
|
|
|
355
358
|
// 8. Update swallowkit.config.js
|
|
356
359
|
console.log("\n Updating configuration...");
|
|
357
|
-
updateConfigWithAuth(cwd, provider, customJwtConfig);
|
|
360
|
+
updateConfigWithAuth(cwd, provider, customJwtConfig, session);
|
|
358
361
|
|
|
359
362
|
// 9. Update environment files
|
|
360
363
|
console.log("\n Updating environment files...");
|
|
361
|
-
updateEnvironmentFiles(cwd);
|
|
364
|
+
updateEnvironmentFiles(cwd, session);
|
|
362
365
|
|
|
363
366
|
// 10. Install dependencies
|
|
364
367
|
console.log("\n Installing auth dependencies...");
|
|
365
|
-
await installAuthDependencies(cwd, backendLanguage, rdbProvider);
|
|
366
|
-
await
|
|
368
|
+
await installAuthDependencies(cwd, backendLanguage, rdbProvider, session);
|
|
369
|
+
await finalize();
|
|
367
370
|
|
|
368
371
|
console.log("\n Authentication setup complete!");
|
|
369
372
|
console.log("\n Next steps:");
|
|
@@ -389,22 +392,22 @@ function findObjectEnd(content: string, open: number): number {
|
|
|
389
392
|
return -1;
|
|
390
393
|
}
|
|
391
394
|
|
|
392
|
-
function updateConfigWithNamedScheme(cwd: string, scheme: string, provider: AuthProvider): void {
|
|
395
|
+
function updateConfigWithNamedScheme(cwd: string, scheme: string, provider: AuthProvider, session: FileOperationSession): void {
|
|
393
396
|
const jsPath = path.join(cwd, "swallowkit.config.js");
|
|
394
397
|
const jsonPath = path.join(cwd, "swallowkit.config.json");
|
|
395
|
-
const configPath =
|
|
396
|
-
if (!
|
|
398
|
+
const configPath = session.fileExists(jsPath) ? jsPath : jsonPath;
|
|
399
|
+
if (!session.fileExists(configPath)) throw new Error("swallowkit.config.js or swallowkit.config.json is required");
|
|
397
400
|
if (configPath.endsWith(".json")) {
|
|
398
|
-
const value = JSON.parse(
|
|
401
|
+
const value = JSON.parse(session.readFile(configPath));
|
|
399
402
|
value.auth ??= {};
|
|
400
403
|
value.auth.schemes ??= {};
|
|
401
404
|
if (value.auth.schemes[scheme]) throw new Error(`auth.schemes.${scheme} already exists; no files were changed`);
|
|
402
405
|
value.auth.schemes[scheme] = provider === "custom-jwt" ? { provider, customJwt: defaultCustomJwtConfig() } : { provider };
|
|
403
406
|
value.auth.authorization ??= { defaultPolicy: "anonymous", policies: {} };
|
|
404
|
-
|
|
407
|
+
session.writeFile(configPath, JSON.stringify(value, null, 2) + "\n", extensionMeta);
|
|
405
408
|
return;
|
|
406
409
|
}
|
|
407
|
-
let content =
|
|
410
|
+
let content = session.readFile(configPath);
|
|
408
411
|
const authMatch = /\bauth\s*:\s*\{/.exec(content);
|
|
409
412
|
const customJwt = defaultCustomJwtConfig();
|
|
410
413
|
const entry = provider === "custom-jwt"
|
|
@@ -430,45 +433,45 @@ function updateConfigWithNamedScheme(cwd: string, scheme: string, provider: Auth
|
|
|
430
433
|
content = content.slice(0, authOpen + 1) + `\n schemes: {${entry}\n },` + content.slice(authOpen + 1);
|
|
431
434
|
}
|
|
432
435
|
}
|
|
433
|
-
|
|
436
|
+
session.writeFile(configPath, content, extensionMeta);
|
|
434
437
|
}
|
|
435
438
|
|
|
436
|
-
function addNamedScheme(cwd: string, scheme: string, provider: AuthProvider, language: BackendLanguage): void {
|
|
439
|
+
function addNamedScheme(cwd: string, scheme: string, provider: AuthProvider, language: BackendLanguage, session: FileOperationSession): void {
|
|
437
440
|
// Validate/update config before creating files, so duplicate names stop safely.
|
|
438
|
-
updateConfigWithNamedScheme(cwd, scheme, provider);
|
|
441
|
+
updateConfigWithNamedScheme(cwd, scheme, provider, session);
|
|
439
442
|
const slug = scheme.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
|
|
440
443
|
if (language === "typescript") {
|
|
441
444
|
const dir = path.join(cwd, "functions", "src", "auth", "schemes", slug);
|
|
442
|
-
if (provider === "external-token") writeIfMissing(path.join(dir, "verifier.ts"), generateExternalTokenVerifierTS());
|
|
443
|
-
else if (provider === "swa") writeIfMissing(path.join(dir, "adapter.ts"), generateSwaAuthHelperTS());
|
|
444
|
-
else writeIfMissing(path.join(dir, "jwt-helper.ts"), generateJwtHelperTS());
|
|
445
|
+
if (provider === "external-token") writeIfMissing(session, path.join(dir, "verifier.ts"), generateExternalTokenVerifierTS());
|
|
446
|
+
else if (provider === "swa") writeIfMissing(session, path.join(dir, "adapter.ts"), generateSwaAuthHelperTS());
|
|
447
|
+
else writeIfMissing(session, path.join(dir, "jwt-helper.ts"), generateJwtHelperTS());
|
|
445
448
|
} else if (language === "csharp") {
|
|
446
449
|
const dir = path.join(cwd, "functions", "Auth", "Schemes", slug);
|
|
447
|
-
if (provider === "external-token") writeIfMissing(path.join(dir, "ExternalTokenVerifier.cs"), generateNamedExternalTokenVerifierCSharp(scheme));
|
|
448
|
-
else if (provider === "swa") writeIfMissing(path.join(dir, "SwaAdapter.cs"), generateSwaAuthHelperCSharp());
|
|
449
|
-
else writeIfMissing(path.join(dir, "JwtHelper.cs"), generateJwtHelperCSharp());
|
|
450
|
+
if (provider === "external-token") writeIfMissing(session, path.join(dir, "ExternalTokenVerifier.cs"), generateNamedExternalTokenVerifierCSharp(scheme));
|
|
451
|
+
else if (provider === "swa") writeIfMissing(session, path.join(dir, "SwaAdapter.cs"), generateSwaAuthHelperCSharp());
|
|
452
|
+
else writeIfMissing(session, path.join(dir, "JwtHelper.cs"), generateJwtHelperCSharp());
|
|
450
453
|
} else {
|
|
451
454
|
const dir = path.join(cwd, "functions", "auth", "schemes", slug.replace(/-/g, "_"));
|
|
452
|
-
if (provider === "external-token") writeIfMissing(path.join(dir, "verifier.py"), generateNamedExternalTokenVerifierPython(scheme));
|
|
453
|
-
else if (provider === "swa") writeIfMissing(path.join(dir, "adapter.py"), generateSwaAuthHelperPython());
|
|
454
|
-
else writeIfMissing(path.join(dir, "jwt_helper.py"), generateJwtHelperPython());
|
|
455
|
+
if (provider === "external-token") writeIfMissing(session, path.join(dir, "verifier.py"), generateNamedExternalTokenVerifierPython(scheme));
|
|
456
|
+
else if (provider === "swa") writeIfMissing(session, path.join(dir, "adapter.py"), generateSwaAuthHelperPython());
|
|
457
|
+
else writeIfMissing(session, path.join(dir, "jwt_helper.py"), generateJwtHelperPython());
|
|
455
458
|
}
|
|
456
459
|
const clientDir = path.join(cwd, "lib", "auth", "schemes", slug);
|
|
457
460
|
if (provider === "external-token") {
|
|
458
|
-
writeIfMissing(path.join(clientDir, "token-adapter.ts"), generateExternalTokenAdapter());
|
|
459
|
-
writeIfMissing(path.join(clientDir, "authenticated-fetch.ts"), generateAuthenticatedFetch().replace("'./external-token-adapter'", "'./token-adapter'"));
|
|
460
|
-
writeIfMissing(path.join(clientDir, "auth-context.tsx"), generateExternalTokenAuthContext().replace(/external-token-adapter/g, "token-adapter"));
|
|
461
|
+
writeIfMissing(session, path.join(clientDir, "token-adapter.ts"), generateExternalTokenAdapter());
|
|
462
|
+
writeIfMissing(session, path.join(clientDir, "authenticated-fetch.ts"), generateAuthenticatedFetch().replace("'./external-token-adapter'", "'./token-adapter'"));
|
|
463
|
+
writeIfMissing(session, path.join(clientDir, "auth-context.tsx"), generateExternalTokenAuthContext().replace(/external-token-adapter/g, "token-adapter"));
|
|
461
464
|
} else if (provider === "swa") {
|
|
462
|
-
writeIfMissing(path.join(clientDir, "auth-context.tsx"), generateSwaAuthContext());
|
|
465
|
+
writeIfMissing(session, path.join(clientDir, "auth-context.tsx"), generateSwaAuthContext());
|
|
463
466
|
} else if (provider === "custom-jwt") {
|
|
464
|
-
writeIfMissing(path.join(clientDir, "auth-context.tsx"), generateAuthContext());
|
|
467
|
+
writeIfMissing(session, path.join(clientDir, "auth-context.tsx"), generateAuthContext());
|
|
465
468
|
}
|
|
466
469
|
const callFunctionPath = path.join(cwd, "lib", "api", "call-function.ts");
|
|
467
|
-
if (!
|
|
470
|
+
if (!session.fileExists(callFunctionPath)) writeIfMissing(session, callFunctionPath, generateBFFCallFunctionWithMultipleAuth());
|
|
468
471
|
else {
|
|
469
|
-
const current =
|
|
472
|
+
const current = session.readFile(callFunctionPath);
|
|
470
473
|
if (!current.includes("x-ms-client-principal") || !current.includes("fetchHeaders['Authorization']")) {
|
|
471
|
-
if (current.includes("SwallowKit BFF Call Function Helper"))
|
|
474
|
+
if (current.includes("SwallowKit BFF Call Function Helper")) session.writeFile(callFunctionPath, generateBFFCallFunctionWithMultipleAuth(), managedMeta);
|
|
472
475
|
else console.warn(" Existing customized lib/api/call-function.ts was preserved. Ensure it forwards Bearer and SWA credentials without logging them.");
|
|
473
476
|
}
|
|
474
477
|
}
|
|
@@ -479,12 +482,12 @@ function addNamedScheme(cwd: string, scheme: string, provider: AuthProvider, lan
|
|
|
479
482
|
* (tsconfig.json, build script, typescript devDependency).
|
|
480
483
|
* Required for `dev` command which runs `npm run --workspace=shared build`.
|
|
481
484
|
*/
|
|
482
|
-
function ensureSharedBuildInfrastructure(cwd: string): void {
|
|
485
|
+
function ensureSharedBuildInfrastructure(cwd: string, session: FileOperationSession): void {
|
|
483
486
|
const sharedDir = path.join(cwd, "shared");
|
|
484
487
|
const pkgPath = path.join(sharedDir, "package.json");
|
|
485
|
-
if (!
|
|
488
|
+
if (!session.fileExists(pkgPath)) return;
|
|
486
489
|
|
|
487
|
-
const pkg = JSON.parse(
|
|
490
|
+
const pkg = JSON.parse(session.readFile(pkgPath));
|
|
488
491
|
let updated = false;
|
|
489
492
|
|
|
490
493
|
// Ensure scripts.build exists
|
|
@@ -510,29 +513,29 @@ function ensureSharedBuildInfrastructure(cwd: string): void {
|
|
|
510
513
|
}
|
|
511
514
|
|
|
512
515
|
if (updated) {
|
|
513
|
-
|
|
516
|
+
session.writeFile(pkgPath, JSON.stringify(pkg, null, 2), extensionMeta);
|
|
514
517
|
console.log(` Updated: shared/package.json (added build infrastructure)`);
|
|
515
518
|
}
|
|
516
519
|
|
|
517
520
|
// Ensure tsconfig.json exists
|
|
518
521
|
const tsconfigPath = path.join(sharedDir, "tsconfig.json");
|
|
519
|
-
if (!
|
|
520
|
-
|
|
522
|
+
if (!session.fileExists(tsconfigPath)) {
|
|
523
|
+
session.writeFile(tsconfigPath, JSON.stringify(buildSharedTsConfig(), null, 2), onceMeta);
|
|
521
524
|
console.log(` Created: shared/tsconfig.json`);
|
|
522
525
|
}
|
|
523
526
|
}
|
|
524
527
|
|
|
525
|
-
function updateSharedIndex(cwd: string): void {
|
|
528
|
+
function updateSharedIndex(cwd: string, session: FileOperationSession): void {
|
|
526
529
|
const indexPath = path.join(cwd, "shared", "index.ts");
|
|
527
|
-
if (
|
|
528
|
-
let content =
|
|
530
|
+
if (session.fileExists(indexPath)) {
|
|
531
|
+
let content = session.readFile(indexPath);
|
|
529
532
|
if (!content.includes("./models/auth")) {
|
|
530
533
|
content += `\nexport { LoginRequest, AuthUser, LoginResponse } from './models/auth';\n`;
|
|
531
|
-
|
|
534
|
+
session.writeFile(indexPath, content, extensionMeta);
|
|
532
535
|
console.log(` Updated: shared/index.ts`);
|
|
533
536
|
}
|
|
534
537
|
} else {
|
|
535
|
-
|
|
538
|
+
session.writeFile(indexPath, `export { LoginRequest, AuthUser, LoginResponse } from './models/auth';\n`, extensionMeta);
|
|
536
539
|
console.log(` Created: shared/index.ts`);
|
|
537
540
|
}
|
|
538
541
|
}
|
|
@@ -542,6 +545,7 @@ function generateFunctionsAuth(
|
|
|
542
545
|
backendLanguage: BackendLanguage,
|
|
543
546
|
sharedPackageName: string,
|
|
544
547
|
config: CustomJwtConfig,
|
|
548
|
+
session: FileOperationSession,
|
|
545
549
|
): void {
|
|
546
550
|
const functionsDir = path.join(cwd, "functions");
|
|
547
551
|
|
|
@@ -552,64 +556,61 @@ function generateFunctionsAuth(
|
|
|
552
556
|
if (backendLanguage === "typescript") {
|
|
553
557
|
// Auth functions
|
|
554
558
|
const srcDir = path.join(functionsDir, "src");
|
|
555
|
-
|
|
556
|
-
fs.writeFileSync(
|
|
559
|
+
session.writeFile(
|
|
557
560
|
path.join(srcDir, "auth.ts"),
|
|
558
561
|
generateAuthFunctionsTS(sharedPackageName, config, provider),
|
|
559
|
-
|
|
562
|
+
managedMeta
|
|
560
563
|
);
|
|
561
564
|
console.log(` Created: functions/src/auth.ts`);
|
|
562
565
|
|
|
563
566
|
// JWT helper
|
|
564
567
|
const authDir = path.join(srcDir, "auth");
|
|
565
|
-
|
|
566
|
-
fs.writeFileSync(
|
|
568
|
+
session.writeFile(
|
|
567
569
|
path.join(authDir, "jwt-helper.ts"),
|
|
568
570
|
generateJwtHelperTS(),
|
|
569
|
-
|
|
571
|
+
managedMeta
|
|
570
572
|
);
|
|
571
573
|
console.log(` Created: functions/src/auth/jwt-helper.ts`);
|
|
572
574
|
} else if (backendLanguage === "csharp") {
|
|
573
575
|
const authDir = path.join(functionsDir, "Auth");
|
|
574
|
-
|
|
575
|
-
fs.writeFileSync(
|
|
576
|
+
session.writeFile(
|
|
576
577
|
path.join(authDir, "AuthFunctions.cs"),
|
|
577
578
|
generateAuthFunctionsCSharp(config, provider),
|
|
578
|
-
|
|
579
|
+
managedMeta
|
|
579
580
|
);
|
|
580
581
|
console.log(` Created: functions/Auth/AuthFunctions.cs`);
|
|
581
|
-
|
|
582
|
+
session.writeFile(
|
|
582
583
|
path.join(authDir, "JwtHelper.cs"),
|
|
583
584
|
generateJwtHelperCSharp(),
|
|
584
|
-
|
|
585
|
+
managedMeta
|
|
585
586
|
);
|
|
586
587
|
console.log(` Created: functions/Auth/JwtHelper.cs`);
|
|
587
588
|
} else if (backendLanguage === "python") {
|
|
588
589
|
const blueprintsDir = path.join(functionsDir, "blueprints");
|
|
589
|
-
|
|
590
|
-
fs.writeFileSync(
|
|
590
|
+
session.writeFile(
|
|
591
591
|
path.join(blueprintsDir, "auth.py"),
|
|
592
592
|
generateAuthFunctionsPython(config, provider),
|
|
593
|
-
|
|
593
|
+
managedMeta
|
|
594
594
|
);
|
|
595
595
|
console.log(` Created: functions/blueprints/auth.py`);
|
|
596
596
|
|
|
597
597
|
const authDir = path.join(functionsDir, "auth");
|
|
598
|
-
|
|
599
|
-
fs.writeFileSync(
|
|
598
|
+
session.writeFile(
|
|
600
599
|
path.join(authDir, "jwt_helper.py"),
|
|
601
600
|
generateJwtHelperPython(),
|
|
602
|
-
|
|
601
|
+
managedMeta
|
|
603
602
|
);
|
|
604
603
|
console.log(` Created: functions/auth/jwt_helper.py`);
|
|
605
604
|
|
|
606
605
|
// __init__.py
|
|
607
|
-
|
|
606
|
+
if (!session.fileExists(path.join(authDir, "__init__.py"))) {
|
|
607
|
+
session.writeFile(path.join(authDir, "__init__.py"), "", onceMeta);
|
|
608
|
+
}
|
|
608
609
|
|
|
609
610
|
// Register auth blueprint in function_app.py
|
|
610
611
|
const functionAppPath = path.join(functionsDir, "function_app.py");
|
|
611
|
-
if (
|
|
612
|
-
const content =
|
|
612
|
+
if (session.fileExists(functionAppPath)) {
|
|
613
|
+
const content = session.readFile(functionAppPath);
|
|
613
614
|
const authImport = "from blueprints.auth import bp as auth_bp";
|
|
614
615
|
const authRegister = "app.register_blueprint(auth_bp)";
|
|
615
616
|
if (!content.includes(authImport)) {
|
|
@@ -619,7 +620,7 @@ function generateFunctionsAuth(
|
|
|
619
620
|
marker,
|
|
620
621
|
`${authImport}\n${authRegister}\n${marker}`
|
|
621
622
|
);
|
|
622
|
-
|
|
623
|
+
session.writeFile(functionAppPath, updated, extensionMeta);
|
|
623
624
|
console.log(` Updated: functions/function_app.py (registered auth blueprint)`);
|
|
624
625
|
}
|
|
625
626
|
}
|
|
@@ -627,48 +628,45 @@ function generateFunctionsAuth(
|
|
|
627
628
|
}
|
|
628
629
|
}
|
|
629
630
|
|
|
630
|
-
function generateBFFAuth(cwd: string, projectName: string, sharedPackageName: string): void {
|
|
631
|
+
function generateBFFAuth(cwd: string, projectName: string, sharedPackageName: string, session: FileOperationSession): void {
|
|
631
632
|
const authApiDir = path.join(cwd, "app", "api", "auth");
|
|
632
633
|
|
|
633
634
|
// Login route
|
|
634
635
|
const loginDir = path.join(authApiDir, "login");
|
|
635
|
-
|
|
636
|
-
fs.writeFileSync(
|
|
636
|
+
session.writeFile(
|
|
637
637
|
path.join(loginDir, "route.ts"),
|
|
638
638
|
generateBFFAuthLoginRoute(projectName, sharedPackageName),
|
|
639
|
-
|
|
639
|
+
managedMeta
|
|
640
640
|
);
|
|
641
641
|
console.log(` Created: app/api/auth/login/route.ts`);
|
|
642
642
|
|
|
643
643
|
// Logout route
|
|
644
644
|
const logoutDir = path.join(authApiDir, "logout");
|
|
645
|
-
|
|
646
|
-
fs.writeFileSync(
|
|
645
|
+
session.writeFile(
|
|
647
646
|
path.join(logoutDir, "route.ts"),
|
|
648
647
|
generateBFFAuthLogoutRoute(projectName),
|
|
649
|
-
|
|
648
|
+
managedMeta
|
|
650
649
|
);
|
|
651
650
|
console.log(` Created: app/api/auth/logout/route.ts`);
|
|
652
651
|
|
|
653
652
|
// Me route
|
|
654
653
|
const meDir = path.join(authApiDir, "me");
|
|
655
|
-
|
|
656
|
-
fs.writeFileSync(
|
|
654
|
+
session.writeFile(
|
|
657
655
|
path.join(meDir, "route.ts"),
|
|
658
656
|
generateBFFAuthMeRoute(),
|
|
659
|
-
|
|
657
|
+
managedMeta
|
|
660
658
|
);
|
|
661
659
|
console.log(` Created: app/api/auth/me/route.ts`);
|
|
662
660
|
}
|
|
663
661
|
|
|
664
|
-
function updateConfigWithAuth(cwd: string, provider: AuthProvider, config: CustomJwtConfig): void {
|
|
662
|
+
function updateConfigWithAuth(cwd: string, provider: AuthProvider, config: CustomJwtConfig, session: FileOperationSession): void {
|
|
665
663
|
const configPath = path.join(cwd, "swallowkit.config.js");
|
|
666
|
-
if (!
|
|
664
|
+
if (!session.fileExists(configPath)) {
|
|
667
665
|
console.warn(" swallowkit.config.js not found. Please add auth config manually.");
|
|
668
666
|
return;
|
|
669
667
|
}
|
|
670
668
|
|
|
671
|
-
const content =
|
|
669
|
+
const content = session.readFile(configPath);
|
|
672
670
|
|
|
673
671
|
if (content.includes("auth:") || content.includes("auth :")) {
|
|
674
672
|
console.log(" 'auth' section already exists in swallowkit.config.js");
|
|
@@ -712,40 +710,40 @@ ${providerSettings}
|
|
|
712
710
|
`;
|
|
713
711
|
|
|
714
712
|
const newContent = content.substring(0, closingBraceIdx) + authBlock + content.substring(closingBraceIdx);
|
|
715
|
-
|
|
713
|
+
session.writeFile(configPath, newContent, extensionMeta);
|
|
716
714
|
console.log(` Updated: swallowkit.config.js`);
|
|
717
715
|
}
|
|
718
716
|
|
|
719
|
-
function updateEnvironmentFiles(cwd: string): void {
|
|
717
|
+
function updateEnvironmentFiles(cwd: string, session: FileOperationSession): void {
|
|
720
718
|
// Update functions/local.settings.json
|
|
721
719
|
const localSettingsPath = path.join(cwd, "functions", "local.settings.json");
|
|
722
|
-
if (
|
|
723
|
-
const settings = JSON.parse(
|
|
720
|
+
if (session.fileExists(localSettingsPath)) {
|
|
721
|
+
const settings = JSON.parse(session.readFile(localSettingsPath));
|
|
724
722
|
if (!settings.Values) settings.Values = {};
|
|
725
723
|
if (!settings.Values.JWT_SECRET) {
|
|
726
724
|
settings.Values.JWT_SECRET = "dev-jwt-secret-change-in-production-min-32-chars!!";
|
|
727
725
|
}
|
|
728
|
-
|
|
726
|
+
session.writeFile(localSettingsPath, JSON.stringify(settings, null, 2), extensionMeta);
|
|
729
727
|
console.log(` Updated: functions/local.settings.json`);
|
|
730
728
|
}
|
|
731
729
|
|
|
732
730
|
// Update .env.example
|
|
733
731
|
const envExamplePath = path.join(cwd, ".env.example");
|
|
734
|
-
if (
|
|
735
|
-
let content =
|
|
732
|
+
if (session.fileExists(envExamplePath)) {
|
|
733
|
+
let content = session.readFile(envExamplePath);
|
|
736
734
|
if (!content.includes("JWT_SECRET")) {
|
|
737
735
|
content += "\n# Authentication\nJWT_SECRET=your-jwt-secret-key-at-least-32-chars\n";
|
|
738
|
-
|
|
736
|
+
session.writeFile(envExamplePath, content, extensionMeta);
|
|
739
737
|
console.log(` Updated: .env.example`);
|
|
740
738
|
}
|
|
741
739
|
}
|
|
742
740
|
}
|
|
743
741
|
|
|
744
|
-
async function installAuthDependencies(cwd: string, backendLanguage: BackendLanguage, provider: "mysql" | "postgres" | "sqlserver" = "mysql"): Promise<void> {
|
|
742
|
+
async function installAuthDependencies(cwd: string, backendLanguage: BackendLanguage, provider: "mysql" | "postgres" | "sqlserver" = "mysql", session: FileOperationSession): Promise<void> {
|
|
745
743
|
if (backendLanguage === "typescript") {
|
|
746
744
|
const funcPkgPath = path.join(cwd, "functions", "package.json");
|
|
747
|
-
if (
|
|
748
|
-
const funcPkg = JSON.parse(
|
|
745
|
+
if (session.fileExists(funcPkgPath)) {
|
|
746
|
+
const funcPkg = JSON.parse(session.readFile(funcPkgPath));
|
|
749
747
|
if (!funcPkg.dependencies) funcPkg.dependencies = {};
|
|
750
748
|
funcPkg.dependencies["jsonwebtoken"] = "^9.0.0";
|
|
751
749
|
funcPkg.dependencies["bcryptjs"] = "^2.4.3";
|
|
@@ -757,16 +755,18 @@ async function installAuthDependencies(cwd: string, backendLanguage: BackendLang
|
|
|
757
755
|
funcPkg.devDependencies["@types/jsonwebtoken"] = "^9.0.0";
|
|
758
756
|
funcPkg.devDependencies["@types/bcryptjs"] = "^2.4.0";
|
|
759
757
|
if (provider === "postgres") funcPkg.devDependencies["@types/pg"] = "^8.11.0";
|
|
760
|
-
|
|
758
|
+
session.writeFile(funcPkgPath, JSON.stringify(funcPkg, null, 2), extensionMeta);
|
|
761
759
|
console.log(` Updated: functions/package.json with auth dependencies (${provider})`);
|
|
762
760
|
}
|
|
763
761
|
} else if (backendLanguage === "csharp") {
|
|
764
762
|
// Add NuGet package references to .csproj
|
|
765
763
|
const functionsDir = path.join(cwd, "functions");
|
|
766
|
-
const csprojFiles = fs.
|
|
764
|
+
const csprojFiles = fs.existsSync(functionsDir)
|
|
765
|
+
? fs.readdirSync(functionsDir).filter((f: string) => f.endsWith(".csproj"))
|
|
766
|
+
: [];
|
|
767
767
|
if (csprojFiles.length > 0) {
|
|
768
768
|
const csprojPath = path.join(functionsDir, csprojFiles[0]);
|
|
769
|
-
let csprojContent =
|
|
769
|
+
let csprojContent = session.readFile(csprojPath);
|
|
770
770
|
const nugetPackages: { name: string; version: string }[] = [
|
|
771
771
|
{ name: "System.IdentityModel.Tokens.Jwt", version: "7.0.0" },
|
|
772
772
|
{ name: "Microsoft.IdentityModel.Tokens", version: "7.0.0" },
|
|
@@ -787,7 +787,7 @@ async function installAuthDependencies(cwd: string, backendLanguage: BackendLang
|
|
|
787
787
|
}
|
|
788
788
|
}
|
|
789
789
|
}
|
|
790
|
-
|
|
790
|
+
session.writeFile(csprojPath, csprojContent, extensionMeta);
|
|
791
791
|
console.log(` Updated: ${csprojFiles[0]} with auth NuGet packages (${provider})`);
|
|
792
792
|
}
|
|
793
793
|
} else if (backendLanguage === "python") {
|
|
@@ -798,17 +798,17 @@ async function installAuthDependencies(cwd: string, backendLanguage: BackendLang
|
|
|
798
798
|
if (provider === "mysql") baseDeps.push("mysql-connector-python>=8.3.0");
|
|
799
799
|
else if (provider === "postgres") baseDeps.push("psycopg2-binary>=2.9.0");
|
|
800
800
|
else baseDeps.push("pymssql>=2.2.0");
|
|
801
|
-
if (
|
|
802
|
-
let content =
|
|
801
|
+
if (session.fileExists(requirementsPath)) {
|
|
802
|
+
let content = session.readFile(requirementsPath);
|
|
803
803
|
for (const dep of baseDeps) {
|
|
804
804
|
const pkgName = dep.split(">=")[0].split("==")[0];
|
|
805
805
|
if (!content.includes(pkgName)) {
|
|
806
806
|
content += `${dep}\n`;
|
|
807
807
|
}
|
|
808
808
|
}
|
|
809
|
-
|
|
809
|
+
session.writeFile(requirementsPath, content, extensionMeta);
|
|
810
810
|
} else {
|
|
811
|
-
|
|
811
|
+
session.writeFile(requirementsPath, baseDeps.join("\n") + "\n", extensionMeta);
|
|
812
812
|
}
|
|
813
813
|
console.log(` Updated: functions/requirements.txt with auth dependencies`);
|
|
814
814
|
}
|