@stackwright-pro/mcp 0.2.0-alpha.61 → 0.2.0-alpha.66
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/integrity.js +7 -7
- package/dist/integrity.js.map +1 -1
- package/dist/integrity.mjs +7 -7
- package/dist/integrity.mjs.map +1 -1
- package/dist/server.js +437 -37
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +445 -45
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -1702,6 +1702,14 @@ function handleSavePhaseAnswers(input) {
|
|
|
1702
1702
|
let answers;
|
|
1703
1703
|
if (input.questions && input.questions.length > 0) {
|
|
1704
1704
|
answers = answersToManifestFormat(input.rawAnswers, input.questions);
|
|
1705
|
+
if (Object.keys(answers).length === 0 && input.rawAnswers.length > 0) {
|
|
1706
|
+
answers = Object.fromEntries(
|
|
1707
|
+
input.rawAnswers.map((a) => [
|
|
1708
|
+
a.question_header,
|
|
1709
|
+
a.selected_options.length > 1 ? a.selected_options : a.selected_options[0] ?? ""
|
|
1710
|
+
])
|
|
1711
|
+
);
|
|
1712
|
+
}
|
|
1705
1713
|
} else {
|
|
1706
1714
|
answers = Object.fromEntries(
|
|
1707
1715
|
input.rawAnswers.map((a) => [a.question_header, a.selected_options[0] ?? ""])
|
|
@@ -2285,12 +2293,13 @@ var PHASE_DEPENDENCIES = {
|
|
|
2285
2293
|
// workflow states as trigger sources. Produces OpenAPI specs consumed
|
|
2286
2294
|
// by pages and dashboard for typed data wiring.
|
|
2287
2295
|
services: ["api", "workflow"],
|
|
2288
|
-
// pages/dashboard:
|
|
2289
|
-
//
|
|
2290
|
-
//
|
|
2291
|
-
//
|
|
2292
|
-
|
|
2293
|
-
|
|
2296
|
+
// pages/dashboard: depend on services for typed endpoint wiring (OpenAPI
|
|
2297
|
+
// specs) and on geo so the specialist prompt includes geo-manifest.json
|
|
2298
|
+
// — page/dashboard otters see which page slugs are already claimed and
|
|
2299
|
+
// won't attempt to overwrite them (swp-73c). 'api' is still transitive
|
|
2300
|
+
// through 'data'; auth removed — page-otter has graceful fallback.
|
|
2301
|
+
pages: ["designer", "theme", "data", "services", "geo"],
|
|
2302
|
+
dashboard: ["designer", "theme", "data", "services", "geo"],
|
|
2294
2303
|
// auth is the penultimate phase — runs after all content-producing phases
|
|
2295
2304
|
// so it can read pages, dashboard, workflow, and geo artifacts for route
|
|
2296
2305
|
// protection and RBAC wiring. Skipped upstream phases still satisfy deps
|
|
@@ -3347,6 +3356,16 @@ var OTTER_WRITE_ALLOWLISTS = {
|
|
|
3347
3356
|
prefix: ".env",
|
|
3348
3357
|
suffix: "",
|
|
3349
3358
|
description: "Dotenv files (.env, .env.local, .env.production, etc.)"
|
|
3359
|
+
},
|
|
3360
|
+
{
|
|
3361
|
+
prefix: "lib/mock-auth",
|
|
3362
|
+
suffix: ".ts",
|
|
3363
|
+
description: "Mock auth module (DEV_ONLY_MODE role updates)"
|
|
3364
|
+
},
|
|
3365
|
+
{
|
|
3366
|
+
prefix: "package.json",
|
|
3367
|
+
suffix: ".json",
|
|
3368
|
+
description: "Project package.json (DEV_ONLY_MODE script cleanup)"
|
|
3350
3369
|
}
|
|
3351
3370
|
],
|
|
3352
3371
|
"stackwright-pro-data-otter": [
|
|
@@ -3404,7 +3423,9 @@ var PROTECTED_PATH_PREFIXES = [
|
|
|
3404
3423
|
".stackwright/artifacts/signatures.json",
|
|
3405
3424
|
// artifact signature manifest
|
|
3406
3425
|
".stackwright/questions/",
|
|
3407
|
-
".stackwright/answers/"
|
|
3426
|
+
".stackwright/answers/",
|
|
3427
|
+
".stackwright/page-registry.json"
|
|
3428
|
+
// page ownership — managed by safe_write internally
|
|
3408
3429
|
];
|
|
3409
3430
|
var MAX_SAFE_WRITE_BYTES_JSON = 512 * 1024;
|
|
3410
3431
|
var MAX_SAFE_WRITE_BYTES_YAML = 256 * 1024;
|
|
@@ -3418,6 +3439,58 @@ function getMaxBytesForPath(filePath) {
|
|
|
3418
3439
|
return { limit: MAX_SAFE_WRITE_BYTES_ENV, label: "env" };
|
|
3419
3440
|
return { limit: MAX_SAFE_WRITE_BYTES_DEFAULT, label: "default" };
|
|
3420
3441
|
}
|
|
3442
|
+
var PAGE_REGISTRY_FILE = ".stackwright/page-registry.json";
|
|
3443
|
+
function extractPageSlug(filePath) {
|
|
3444
|
+
const match = (0, import_path6.normalize)(filePath).match(/^pages\/(.+?)\/content\.ya?ml$/);
|
|
3445
|
+
return match?.[1] ?? null;
|
|
3446
|
+
}
|
|
3447
|
+
function extractContentTypes(yamlContent) {
|
|
3448
|
+
const typePattern = /^\s*-?\s*type:\s*(\S+)/gm;
|
|
3449
|
+
const types = [];
|
|
3450
|
+
let m;
|
|
3451
|
+
while ((m = typePattern.exec(yamlContent)) !== null) {
|
|
3452
|
+
const typeName = m[1];
|
|
3453
|
+
if (typeName && !types.includes(typeName)) {
|
|
3454
|
+
types.push(typeName);
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
return types.length > 0 ? types : ["unknown"];
|
|
3458
|
+
}
|
|
3459
|
+
function readPageRegistry(cwd) {
|
|
3460
|
+
const regPath = (0, import_path6.join)(cwd, PAGE_REGISTRY_FILE);
|
|
3461
|
+
if (!(0, import_fs6.existsSync)(regPath)) return {};
|
|
3462
|
+
try {
|
|
3463
|
+
const stat = (0, import_fs6.lstatSync)(regPath);
|
|
3464
|
+
if (stat.isSymbolicLink()) return {};
|
|
3465
|
+
return JSON.parse((0, import_fs6.readFileSync)(regPath, "utf-8"));
|
|
3466
|
+
} catch {
|
|
3467
|
+
return {};
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3470
|
+
function writePageRegistry(cwd, registry) {
|
|
3471
|
+
const dir = (0, import_path6.join)(cwd, ".stackwright");
|
|
3472
|
+
(0, import_fs6.mkdirSync)(dir, { recursive: true });
|
|
3473
|
+
const regPath = (0, import_path6.join)(cwd, PAGE_REGISTRY_FILE);
|
|
3474
|
+
if ((0, import_fs6.existsSync)(regPath)) {
|
|
3475
|
+
const stat = (0, import_fs6.lstatSync)(regPath);
|
|
3476
|
+
if (stat.isSymbolicLink()) {
|
|
3477
|
+
throw new Error("Refusing to write page registry through symlink");
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
(0, import_fs6.writeFileSync)(regPath, JSON.stringify(registry, null, 2) + "\n", { encoding: "utf-8" });
|
|
3481
|
+
}
|
|
3482
|
+
function checkPageOwnership(cwd, slug, callerOtter) {
|
|
3483
|
+
const registry = readPageRegistry(cwd);
|
|
3484
|
+
const existing = registry[slug];
|
|
3485
|
+
if (!existing || existing.claimedBy === callerOtter) {
|
|
3486
|
+
return { allowed: true };
|
|
3487
|
+
}
|
|
3488
|
+
return {
|
|
3489
|
+
allowed: false,
|
|
3490
|
+
owner: existing.claimedBy,
|
|
3491
|
+
contentTypes: existing.contentTypes
|
|
3492
|
+
};
|
|
3493
|
+
}
|
|
3421
3494
|
function checkPathAllowed(callerOtter, filePath) {
|
|
3422
3495
|
const normalized = (0, import_path6.normalize)(filePath);
|
|
3423
3496
|
if (normalized.includes("..")) {
|
|
@@ -3459,6 +3532,16 @@ function checkPathAllowed(callerOtter, filePath) {
|
|
|
3459
3532
|
continue;
|
|
3460
3533
|
}
|
|
3461
3534
|
}
|
|
3535
|
+
if (rule.prefix === "lib/mock-auth" && rule.suffix === ".ts") {
|
|
3536
|
+
if (normalized !== "lib/mock-auth.ts") {
|
|
3537
|
+
continue;
|
|
3538
|
+
}
|
|
3539
|
+
}
|
|
3540
|
+
if (rule.prefix === "package.json" && rule.suffix === ".json") {
|
|
3541
|
+
if (normalized !== "package.json") {
|
|
3542
|
+
continue;
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3462
3545
|
return { allowed: true, rule: rule.description };
|
|
3463
3546
|
}
|
|
3464
3547
|
}
|
|
@@ -3584,11 +3667,38 @@ function handleSafeWrite(input) {
|
|
|
3584
3667
|
};
|
|
3585
3668
|
return { text: JSON.stringify(result), isError: true };
|
|
3586
3669
|
}
|
|
3670
|
+
const pageSlug = extractPageSlug(normalized);
|
|
3671
|
+
if (pageSlug) {
|
|
3672
|
+
const ownership = checkPageOwnership(cwd, pageSlug, callerOtter);
|
|
3673
|
+
if (!ownership.allowed) {
|
|
3674
|
+
const result = {
|
|
3675
|
+
success: false,
|
|
3676
|
+
error: `Page slug "${pageSlug}" is already claimed by ${ownership.owner} (content types: ${ownership.contentTypes.join(", ")}). Use a different slug or coordinate with the owning otter.`,
|
|
3677
|
+
callerOtter,
|
|
3678
|
+
attemptedPath: filePath,
|
|
3679
|
+
allowedPaths: []
|
|
3680
|
+
};
|
|
3681
|
+
return { text: JSON.stringify(result), isError: true };
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3587
3684
|
try {
|
|
3588
3685
|
if (createDirectories) {
|
|
3589
3686
|
(0, import_fs6.mkdirSync)((0, import_path6.dirname)(fullPath), { recursive: true });
|
|
3590
3687
|
}
|
|
3591
3688
|
(0, import_fs6.writeFileSync)(fullPath, content, { encoding: "utf-8" });
|
|
3689
|
+
if (pageSlug) {
|
|
3690
|
+
try {
|
|
3691
|
+
const registry = readPageRegistry(cwd);
|
|
3692
|
+
registry[pageSlug] = {
|
|
3693
|
+
slug: pageSlug,
|
|
3694
|
+
claimedBy: callerOtter,
|
|
3695
|
+
contentTypes: extractContentTypes(content),
|
|
3696
|
+
writtenAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3697
|
+
};
|
|
3698
|
+
writePageRegistry(cwd, registry);
|
|
3699
|
+
} catch {
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
3592
3702
|
const result = {
|
|
3593
3703
|
success: true,
|
|
3594
3704
|
path: normalized,
|
|
@@ -3855,10 +3965,232 @@ ${routeLines}
|
|
|
3855
3965
|
${auditSection}
|
|
3856
3966
|
`;
|
|
3857
3967
|
}
|
|
3968
|
+
function generateDevOnlyMiddlewareContent(method, params, roles, defaultRole, hierarchy, auditEnabled, auditRetentionDays, protectedRoutes) {
|
|
3969
|
+
const rbacBlock = ` rbac: {
|
|
3970
|
+
roles: ${JSON.stringify(roles)},
|
|
3971
|
+
defaultRole: '${defaultRole}',
|
|
3972
|
+
hierarchy: ${JSON.stringify(hierarchy, null, 4)},
|
|
3973
|
+
},`;
|
|
3974
|
+
const auditBlock = ` audit: {
|
|
3975
|
+
enabled: ${auditEnabled},
|
|
3976
|
+
retentionDays: ${auditRetentionDays},
|
|
3977
|
+
},`;
|
|
3978
|
+
const routesBlock = ` protectedRoutes: ${JSON.stringify(protectedRoutes)},`;
|
|
3979
|
+
const configBlock = `export const config = {
|
|
3980
|
+
matcher: ${JSON.stringify(protectedRoutes)},
|
|
3981
|
+
};`;
|
|
3982
|
+
const devHeader = [
|
|
3983
|
+
"// middleware.ts \u2014 generated by @stackwright-pro/auth-nextjs (dev-only mock)",
|
|
3984
|
+
"// DEV ONLY \u2014 uses mock authentication from lib/mock-auth.ts",
|
|
3985
|
+
"// Do NOT deploy to production.",
|
|
3986
|
+
"import { createProMiddleware } from '@stackwright-pro/auth-nextjs';",
|
|
3987
|
+
"import { mockAuthProvider } from './lib/mock-auth';"
|
|
3988
|
+
].join("\n");
|
|
3989
|
+
if (method === "cac") {
|
|
3990
|
+
const caBundle = params.cacCaBundle ?? "./certs/dod-ca-bundle.pem";
|
|
3991
|
+
const edipiLookup = params.cacEdipiLookup ?? "./config/edipi-lookup.json";
|
|
3992
|
+
const ocspEndpoint = params.cacOcspEndpoint ?? "https://ocsp.disa.mil";
|
|
3993
|
+
const certHeader = params.cacCertHeader ?? "X-SSL-Client-Cert";
|
|
3994
|
+
return `${devHeader}
|
|
3995
|
+
|
|
3996
|
+
export const middleware = createProMiddleware({
|
|
3997
|
+
method: 'cac',
|
|
3998
|
+
cac: {
|
|
3999
|
+
caBundle: '${caBundle}',
|
|
4000
|
+
edipiLookup: '${edipiLookup}',
|
|
4001
|
+
ocspEndpoint: '${ocspEndpoint}',
|
|
4002
|
+
certHeader: '${certHeader}',
|
|
4003
|
+
provider: mockAuthProvider,
|
|
4004
|
+
},
|
|
4005
|
+
${rbacBlock}
|
|
4006
|
+
${auditBlock}
|
|
4007
|
+
${routesBlock}
|
|
4008
|
+
});
|
|
4009
|
+
|
|
4010
|
+
${configBlock}
|
|
4011
|
+
`;
|
|
4012
|
+
}
|
|
4013
|
+
if (method === "oidc") {
|
|
4014
|
+
const scopes2 = params.oidcScopes ?? "openid profile email";
|
|
4015
|
+
const roleClaim = params.oidcRoleClaim ?? "roles";
|
|
4016
|
+
return `${devHeader}
|
|
4017
|
+
|
|
4018
|
+
export const middleware = createProMiddleware({
|
|
4019
|
+
method: 'oidc',
|
|
4020
|
+
oidc: {
|
|
4021
|
+
discoveryUrl: 'https://dev-mock-oidc/.well-known/openid-configuration',
|
|
4022
|
+
clientId: 'dev-mock-client',
|
|
4023
|
+
clientSecret: 'dev-mock-secret',
|
|
4024
|
+
scopes: '${scopes2}',
|
|
4025
|
+
roleClaim: '${roleClaim}',
|
|
4026
|
+
provider: mockAuthProvider,
|
|
4027
|
+
},
|
|
4028
|
+
${rbacBlock}
|
|
4029
|
+
${auditBlock}
|
|
4030
|
+
${routesBlock}
|
|
4031
|
+
});
|
|
4032
|
+
|
|
4033
|
+
${configBlock}
|
|
4034
|
+
`;
|
|
4035
|
+
}
|
|
4036
|
+
const scopes = params.oauth2Scopes ?? "read write";
|
|
4037
|
+
return `${devHeader}
|
|
4038
|
+
|
|
4039
|
+
export const middleware = createProMiddleware({
|
|
4040
|
+
method: 'oauth2',
|
|
4041
|
+
oauth2: {
|
|
4042
|
+
authorizationUrl: 'https://dev-mock-oauth2/authorize',
|
|
4043
|
+
tokenUrl: 'https://dev-mock-oauth2/token',
|
|
4044
|
+
clientId: 'dev-mock-client',
|
|
4045
|
+
clientSecret: 'dev-mock-secret',
|
|
4046
|
+
scopes: '${scopes}',
|
|
4047
|
+
provider: mockAuthProvider,
|
|
4048
|
+
},
|
|
4049
|
+
${rbacBlock}
|
|
4050
|
+
${auditBlock}
|
|
4051
|
+
${routesBlock}
|
|
4052
|
+
});
|
|
4053
|
+
|
|
4054
|
+
${configBlock}
|
|
4055
|
+
`;
|
|
4056
|
+
}
|
|
4057
|
+
function generateDevOnlyYamlBlock(method, params, roles, defaultRole, hierarchy, auditEnabled, auditRetentionDays, protectedRoutes) {
|
|
4058
|
+
const rbacSection = ` rbac:
|
|
4059
|
+
roles:
|
|
4060
|
+
${rolesToYaml(roles, " ")}
|
|
4061
|
+
defaultRole: ${defaultRole}
|
|
4062
|
+
hierarchy:
|
|
4063
|
+
${hierarchyToYaml(hierarchy, " ")}`;
|
|
4064
|
+
const auditSection = ` audit:
|
|
4065
|
+
enabled: ${auditEnabled}
|
|
4066
|
+
retentionDays: ${auditRetentionDays}`;
|
|
4067
|
+
const routeLines = protectedRoutes.map((r) => ` - pattern: ${r}
|
|
4068
|
+
requiredRole: ${defaultRole}`).join("\n");
|
|
4069
|
+
const providerLine = params.provider ? ` provider: ${params.provider}
|
|
4070
|
+
` : "";
|
|
4071
|
+
if (method === "cac") {
|
|
4072
|
+
const caBundle = params.cacCaBundle ?? "./certs/dod-ca-bundle.pem";
|
|
4073
|
+
const edipiLookup = params.cacEdipiLookup ?? "./config/edipi-lookup.json";
|
|
4074
|
+
const ocspEndpoint = params.cacOcspEndpoint ?? "https://ocsp.disa.mil";
|
|
4075
|
+
const certHeader = params.cacCertHeader ?? "X-SSL-Client-Cert";
|
|
4076
|
+
return `auth:
|
|
4077
|
+
method: cac
|
|
4078
|
+
devOnly: true
|
|
4079
|
+
${providerLine} middleware: ./middleware.ts
|
|
4080
|
+
cac:
|
|
4081
|
+
caBundle: ${caBundle}
|
|
4082
|
+
edipiLookup: ${edipiLookup}
|
|
4083
|
+
ocspEndpoint: ${ocspEndpoint}
|
|
4084
|
+
certHeader: ${certHeader}
|
|
4085
|
+
${rbacSection}
|
|
4086
|
+
protectedRoutes:
|
|
4087
|
+
${routeLines}
|
|
4088
|
+
${auditSection}
|
|
4089
|
+
`;
|
|
4090
|
+
}
|
|
4091
|
+
if (method === "oidc") {
|
|
4092
|
+
const scopes2 = params.oidcScopes ?? "openid profile email";
|
|
4093
|
+
const roleClaim = params.oidcRoleClaim ?? "roles";
|
|
4094
|
+
return `auth:
|
|
4095
|
+
method: oidc
|
|
4096
|
+
devOnly: true
|
|
4097
|
+
${providerLine} middleware: ./middleware.ts
|
|
4098
|
+
oidc:
|
|
4099
|
+
discoveryUrl: https://dev-mock-oidc/.well-known/openid-configuration
|
|
4100
|
+
clientId: dev-mock-client
|
|
4101
|
+
clientSecret: dev-mock-secret
|
|
4102
|
+
scopes: ${scopes2}
|
|
4103
|
+
roleClaim: ${roleClaim}
|
|
4104
|
+
${rbacSection}
|
|
4105
|
+
protectedRoutes:
|
|
4106
|
+
${routeLines}
|
|
4107
|
+
${auditSection}
|
|
4108
|
+
`;
|
|
4109
|
+
}
|
|
4110
|
+
const scopes = params.oauth2Scopes ?? "read write";
|
|
4111
|
+
return `auth:
|
|
4112
|
+
method: oauth2
|
|
4113
|
+
devOnly: true
|
|
4114
|
+
${providerLine} middleware: ./middleware.ts
|
|
4115
|
+
oauth2:
|
|
4116
|
+
authorizationUrl: https://dev-mock-oauth2/authorize
|
|
4117
|
+
tokenUrl: https://dev-mock-oauth2/token
|
|
4118
|
+
clientId: dev-mock-client
|
|
4119
|
+
clientSecret: dev-mock-secret
|
|
4120
|
+
scopes: ${scopes}
|
|
4121
|
+
${rbacSection}
|
|
4122
|
+
protectedRoutes:
|
|
4123
|
+
${routeLines}
|
|
4124
|
+
${auditSection}
|
|
4125
|
+
`;
|
|
4126
|
+
}
|
|
4127
|
+
function deriveDevKey(roleName) {
|
|
4128
|
+
const segment = roleName.split("_")[0];
|
|
4129
|
+
return (segment ?? roleName).toLowerCase();
|
|
4130
|
+
}
|
|
4131
|
+
function generateMockAuthContent(roles, mockUsers) {
|
|
4132
|
+
const entries = [];
|
|
4133
|
+
const scriptLines = [];
|
|
4134
|
+
for (let i = 0; i < roles.length; i++) {
|
|
4135
|
+
const role = roles[i];
|
|
4136
|
+
const devKey = deriveDevKey(role);
|
|
4137
|
+
const persona = mockUsers?.[i];
|
|
4138
|
+
const name = persona?.name ?? `Dev ${role}`;
|
|
4139
|
+
const email = persona?.email ?? `dev-${devKey}@example.mil`;
|
|
4140
|
+
const edipi = String(i + 1).padStart(10, "0");
|
|
4141
|
+
entries.push(` ${devKey}: {
|
|
4142
|
+
id: 'mock-${devKey}-${String(i + 1).padStart(3, "0")}',
|
|
4143
|
+
name: '${name}',
|
|
4144
|
+
email: '${email}',
|
|
4145
|
+
roles: ['${role}'],
|
|
4146
|
+
edipi: '${edipi}',
|
|
4147
|
+
}`);
|
|
4148
|
+
scriptLines.push(` * pnpm dev:${devKey} \u2014 ${name}`);
|
|
4149
|
+
}
|
|
4150
|
+
return `/**
|
|
4151
|
+
* Mock authentication for development mode.
|
|
4152
|
+
*
|
|
4153
|
+
* DEV_ONLY_MODE \u2014 no real auth provider. Select a persona via MOCK_USER env var
|
|
4154
|
+
* or use the convenience scripts in package.json:
|
|
4155
|
+
${scriptLines.join("\n")}
|
|
4156
|
+
*/
|
|
4157
|
+
|
|
4158
|
+
export const MOCK_USERS = {
|
|
4159
|
+
${entries.join(",\n")}
|
|
4160
|
+
} as const;
|
|
4161
|
+
|
|
4162
|
+
export type MockRole = keyof typeof MOCK_USERS;
|
|
4163
|
+
|
|
4164
|
+
export function getMockUser(role?: string) {
|
|
4165
|
+
const key = (role ?? process.env.MOCK_USER) as MockRole | undefined;
|
|
4166
|
+
if (!key) return null;
|
|
4167
|
+
return MOCK_USERS[key] ?? null;
|
|
4168
|
+
}
|
|
4169
|
+
|
|
4170
|
+
export function mockAuthProvider() {
|
|
4171
|
+
return getMockUser();
|
|
4172
|
+
}
|
|
4173
|
+
`;
|
|
4174
|
+
}
|
|
4175
|
+
function updatePackageJsonScripts(existingJson, roles, mockUsers) {
|
|
4176
|
+
const pkg = JSON.parse(existingJson);
|
|
4177
|
+
const scripts = pkg.scripts ?? {};
|
|
4178
|
+
delete scripts["dev:admin"];
|
|
4179
|
+
delete scripts["dev:analyst"];
|
|
4180
|
+
delete scripts["dev:viewer"];
|
|
4181
|
+
for (let i = 0; i < roles.length; i++) {
|
|
4182
|
+
const devKey = deriveDevKey(roles[i]);
|
|
4183
|
+
scripts[`dev:${devKey}`] = `MOCK_USER=${devKey} next dev`;
|
|
4184
|
+
}
|
|
4185
|
+
pkg.scripts = scripts;
|
|
4186
|
+
return JSON.stringify(pkg, null, 2) + "\n";
|
|
4187
|
+
}
|
|
3858
4188
|
async function configureAuthHandler(params, cwd) {
|
|
3859
4189
|
const {
|
|
3860
4190
|
method,
|
|
3861
4191
|
provider,
|
|
4192
|
+
devOnly = false,
|
|
4193
|
+
mockUsers,
|
|
3862
4194
|
rbacRoles = ["SUPER_ADMIN", "ADMIN", "ANALYST"],
|
|
3863
4195
|
auditEnabled = true,
|
|
3864
4196
|
auditRetentionDays = 90,
|
|
@@ -3888,7 +4220,16 @@ async function configureAuthHandler(params, cwd) {
|
|
|
3888
4220
|
}
|
|
3889
4221
|
const filesWritten = [];
|
|
3890
4222
|
try {
|
|
3891
|
-
const middlewareContent =
|
|
4223
|
+
const middlewareContent = devOnly ? generateDevOnlyMiddlewareContent(
|
|
4224
|
+
method,
|
|
4225
|
+
params,
|
|
4226
|
+
roles,
|
|
4227
|
+
defaultRole,
|
|
4228
|
+
hierarchy,
|
|
4229
|
+
auditEnabled,
|
|
4230
|
+
auditRetentionDays,
|
|
4231
|
+
protectedRoutes
|
|
4232
|
+
) : generateMiddlewareContent(
|
|
3892
4233
|
method,
|
|
3893
4234
|
params,
|
|
3894
4235
|
roles,
|
|
@@ -3912,30 +4253,87 @@ async function configureAuthHandler(params, cwd) {
|
|
|
3912
4253
|
isError: true
|
|
3913
4254
|
};
|
|
3914
4255
|
}
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
4256
|
+
if (!devOnly) {
|
|
4257
|
+
try {
|
|
4258
|
+
const envBlock = generateEnvBlock(method, params);
|
|
4259
|
+
const envPath = (0, import_path7.join)(cwd, ".env.example");
|
|
4260
|
+
if ((0, import_fs7.existsSync)(envPath)) {
|
|
4261
|
+
const existing = (0, import_fs7.readFileSync)(envPath, "utf8");
|
|
4262
|
+
(0, import_fs7.writeFileSync)(envPath, existing.trimEnd() + "\n\n" + envBlock, "utf8");
|
|
4263
|
+
} else {
|
|
4264
|
+
(0, import_fs7.writeFileSync)(envPath, envBlock, "utf8");
|
|
4265
|
+
}
|
|
4266
|
+
filesWritten.push(".env.example");
|
|
4267
|
+
} catch (err) {
|
|
4268
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4269
|
+
return {
|
|
4270
|
+
content: [
|
|
4271
|
+
{
|
|
4272
|
+
type: "text",
|
|
4273
|
+
text: JSON.stringify({ success: false, error: `Failed writing .env.example: ${msg}` })
|
|
4274
|
+
}
|
|
4275
|
+
],
|
|
4276
|
+
isError: true
|
|
4277
|
+
};
|
|
4278
|
+
}
|
|
4279
|
+
}
|
|
4280
|
+
if (devOnly) {
|
|
4281
|
+
try {
|
|
4282
|
+
const mockAuthDir = (0, import_path7.join)(cwd, "lib");
|
|
4283
|
+
(0, import_fs7.mkdirSync)(mockAuthDir, { recursive: true });
|
|
4284
|
+
const mockAuthContent = generateMockAuthContent(roles, mockUsers);
|
|
4285
|
+
(0, import_fs7.writeFileSync)((0, import_path7.join)(mockAuthDir, "mock-auth.ts"), mockAuthContent, "utf8");
|
|
4286
|
+
filesWritten.push("lib/mock-auth.ts");
|
|
4287
|
+
} catch (err) {
|
|
4288
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4289
|
+
return {
|
|
4290
|
+
content: [
|
|
4291
|
+
{
|
|
4292
|
+
type: "text",
|
|
4293
|
+
text: JSON.stringify({
|
|
4294
|
+
success: false,
|
|
4295
|
+
error: `Failed writing lib/mock-auth.ts: ${msg}`
|
|
4296
|
+
})
|
|
4297
|
+
}
|
|
4298
|
+
],
|
|
4299
|
+
isError: true
|
|
4300
|
+
};
|
|
4301
|
+
}
|
|
4302
|
+
try {
|
|
4303
|
+
const pkgPath = (0, import_path7.join)(cwd, "package.json");
|
|
4304
|
+
if ((0, import_fs7.existsSync)(pkgPath)) {
|
|
4305
|
+
const existingPkg = (0, import_fs7.readFileSync)(pkgPath, "utf8");
|
|
4306
|
+
const updatedPkg = updatePackageJsonScripts(existingPkg, roles, mockUsers);
|
|
4307
|
+
(0, import_fs7.writeFileSync)(pkgPath, updatedPkg, "utf8");
|
|
4308
|
+
filesWritten.push("package.json");
|
|
4309
|
+
}
|
|
4310
|
+
} catch (err) {
|
|
4311
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4312
|
+
return {
|
|
4313
|
+
content: [
|
|
4314
|
+
{
|
|
4315
|
+
type: "text",
|
|
4316
|
+
text: JSON.stringify({
|
|
4317
|
+
success: false,
|
|
4318
|
+
error: `Failed updating package.json: ${msg}`
|
|
4319
|
+
})
|
|
4320
|
+
}
|
|
4321
|
+
],
|
|
4322
|
+
isError: true
|
|
4323
|
+
};
|
|
3923
4324
|
}
|
|
3924
|
-
filesWritten.push(".env.example");
|
|
3925
|
-
} catch (err) {
|
|
3926
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
3927
|
-
return {
|
|
3928
|
-
content: [
|
|
3929
|
-
{
|
|
3930
|
-
type: "text",
|
|
3931
|
-
text: JSON.stringify({ success: false, error: `Failed writing .env.example: ${msg}` })
|
|
3932
|
-
}
|
|
3933
|
-
],
|
|
3934
|
-
isError: true
|
|
3935
|
-
};
|
|
3936
4325
|
}
|
|
3937
4326
|
try {
|
|
3938
|
-
const authYaml =
|
|
4327
|
+
const authYaml = devOnly ? generateDevOnlyYamlBlock(
|
|
4328
|
+
method,
|
|
4329
|
+
params,
|
|
4330
|
+
roles,
|
|
4331
|
+
defaultRole,
|
|
4332
|
+
hierarchy,
|
|
4333
|
+
auditEnabled,
|
|
4334
|
+
auditRetentionDays,
|
|
4335
|
+
protectedRoutes
|
|
4336
|
+
) : generateYamlBlock(
|
|
3939
4337
|
method,
|
|
3940
4338
|
params,
|
|
3941
4339
|
roles,
|
|
@@ -4017,7 +4415,9 @@ function registerAuthTools(server2) {
|
|
|
4017
4415
|
// Routes
|
|
4018
4416
|
protectedRoutes: jsonCoerce(import_zod13.z.array(import_zod13.z.string()).optional()),
|
|
4019
4417
|
// Injection for tests
|
|
4020
|
-
_cwd: import_zod13.z.string().optional()
|
|
4418
|
+
_cwd: import_zod13.z.string().optional(),
|
|
4419
|
+
devOnly: boolCoerce(import_zod13.z.boolean().optional()),
|
|
4420
|
+
mockUsers: jsonCoerce(import_zod13.z.array(import_zod13.z.object({ name: import_zod13.z.string(), email: import_zod13.z.string() })).optional())
|
|
4021
4421
|
},
|
|
4022
4422
|
async (params) => {
|
|
4023
4423
|
const cwd = params._cwd ?? process.cwd();
|
|
@@ -4037,15 +4437,15 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
4037
4437
|
],
|
|
4038
4438
|
[
|
|
4039
4439
|
"stackwright-pro-auth-otter.json",
|
|
4040
|
-
"
|
|
4440
|
+
"4bf6beba7150d08c74c5f6fbbeb20e988aba52a2029ff2892615e71f6ab12ed1"
|
|
4041
4441
|
],
|
|
4042
4442
|
[
|
|
4043
4443
|
"stackwright-pro-dashboard-otter.json",
|
|
4044
|
-
"
|
|
4444
|
+
"9c319d311801730e8dc9bc142eebb8fc5a7f48da48fa0b8d8c3b7431652447be"
|
|
4045
4445
|
],
|
|
4046
4446
|
[
|
|
4047
4447
|
"stackwright-pro-data-otter.json",
|
|
4048
|
-
"
|
|
4448
|
+
"4d9369277685a4acc484116920c9622ad8a1838012a493fcfe42a6ae5abe53cf"
|
|
4049
4449
|
],
|
|
4050
4450
|
[
|
|
4051
4451
|
"stackwright-pro-designer-otter.json",
|
|
@@ -4053,7 +4453,7 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
4053
4453
|
],
|
|
4054
4454
|
[
|
|
4055
4455
|
"stackwright-pro-domain-expert-otter.json",
|
|
4056
|
-
"
|
|
4456
|
+
"6055a2efc78f54a8393f628839e2a2563bf0c6de3ad32de00c82779a53381efd"
|
|
4057
4457
|
],
|
|
4058
4458
|
[
|
|
4059
4459
|
"stackwright-pro-foreman-otter.json",
|
|
@@ -4061,15 +4461,15 @@ var _checksums = /* @__PURE__ */ new Map([
|
|
|
4061
4461
|
],
|
|
4062
4462
|
[
|
|
4063
4463
|
"stackwright-pro-geo-otter.json",
|
|
4064
|
-
"
|
|
4464
|
+
"9e09aaf2bb10197c6d1c05d0fd5f5f9380acc0cb697a410fcae839ffba648561"
|
|
4065
4465
|
],
|
|
4066
4466
|
[
|
|
4067
4467
|
"stackwright-pro-page-otter.json",
|
|
4068
|
-
"
|
|
4468
|
+
"532bb7e9a25a5c832edd1ff1ea0886dd4453905d86e6f9331eb957ae5e121833"
|
|
4069
4469
|
],
|
|
4070
4470
|
[
|
|
4071
4471
|
"stackwright-pro-polish-otter.json",
|
|
4072
|
-
"
|
|
4472
|
+
"8f284d4d6a204137cd786824fc584d5bddac1bc757204769b99ca5412cf2cea2"
|
|
4073
4473
|
],
|
|
4074
4474
|
[
|
|
4075
4475
|
"stackwright-pro-theme-otter.json",
|