minutework 0.1.31 → 0.1.33
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/EXTERNAL_ALPHA.md +33 -33
- package/README.md +34 -34
- package/assets/claude-local/CLAUDE.md.template +12 -12
- package/assets/claude-local/skills/README.md +3 -1
- package/assets/claude-local/skills/app-pack-authoring/SKILL.md +17 -4
- package/assets/claude-local/skills/capability-gap-reporting/SKILL.md +3 -3
- package/assets/claude-local/skills/contract-first-public-intake/SKILL.md +11 -3
- package/assets/claude-local/skills/generated-workspace-architecture/SKILL.md +12 -5
- package/assets/claude-local/skills/layering-and-import-modes/SKILL.md +2 -2
- package/assets/claude-local/skills/openclaw-skill-importer/SKILL.md +2 -2
- package/assets/claude-local/skills/project-overview-and-strategy/SKILL.md +8 -8
- package/assets/claude-local/skills/published-web-and-mw-core-site/SKILL.md +11 -8
- package/assets/claude-local/skills/standalone-mobile-client/SKILL.md +6 -5
- package/assets/claude-local/skills/vuilder-discovery-output-contract/SKILL.md +6 -6
- package/assets/claude-local/skills/workspace-guidance-refresh/SKILL.md +4 -4
- package/assets/templates/fastapi-sidecar/pyproject.toml +1 -1
- package/assets/templates/fastapi-sidecar/src/fastapi_sidecar/main.py +1 -1
- package/assets/templates/mobile-app/.env.example +4 -4
- package/assets/templates/mobile-app/AGENTS.md +3 -3
- package/assets/templates/mobile-app/README.md +10 -10
- package/assets/templates/mobile-app/app/(app)/_layout.tsx +2 -2
- package/assets/templates/mobile-app/app/(app)/index.tsx +2 -2
- package/assets/templates/mobile-app/app/(auth)/login.tsx +3 -3
- package/assets/templates/mobile-app/app/_layout.tsx +1 -1
- package/assets/templates/mobile-app/babel.config.js +1 -1
- package/assets/templates/mobile-app/eas.json +1 -1
- package/assets/templates/mobile-app/expo-env.d.ts +1 -1
- package/assets/templates/mobile-app/metro.config.js +2 -2
- package/assets/templates/mobile-app/package.json +1 -1
- package/assets/templates/mobile-app/src/mw/client.ts +3 -3
- package/assets/templates/mobile-app/src/mw/contracts.ts +2 -2
- package/assets/templates/mobile-app/src/mw/endpoints.ts +2 -2
- package/assets/templates/mobile-app/src/mw/env.ts +4 -4
- package/assets/templates/mobile-app/src/mw/session.ts +1 -1
- package/assets/templates/mobile-app/template.json +1 -1
- package/assets/templates/mobile-app/tools/template/validate-template.mjs +2 -2
- package/assets/templates/mobile-app/tsconfig.json +1 -1
- package/assets/templates/next-tenant-app/.env.example +1 -1
- package/assets/templates/next-tenant-app/README.md +26 -138
- package/assets/templates/next-tenant-app/package.json +1 -0
- package/assets/templates/next-tenant-app/src/app/app/demo/page.tsx +15 -0
- package/assets/templates/next-tenant-app/src/app/app/layout.tsx +1 -4
- package/assets/templates/next-tenant-app/src/app/app/page.tsx +2 -17
- package/assets/templates/next-tenant-app/src/app/blog/[slug]/page.tsx +9 -67
- package/assets/templates/next-tenant-app/src/app/blog/page.tsx +10 -46
- package/assets/templates/next-tenant-app/src/app/docs/[...slug]/page.tsx +9 -65
- package/assets/templates/next-tenant-app/src/app/docs/page.tsx +10 -46
- package/assets/templates/next-tenant-app/src/app/layout.tsx +8 -10
- package/assets/templates/next-tenant-app/src/app/login/page.tsx +3 -23
- package/assets/templates/next-tenant-app/src/app/page.tsx +11 -44
- package/assets/templates/next-tenant-app/src/app/pricing/page.tsx +10 -44
- package/assets/templates/next-tenant-app/src/app/providers.tsx +2 -1
- package/assets/templates/next-tenant-app/src/app/robots.ts +7 -18
- package/assets/templates/next-tenant-app/src/app/sitemap.ts +4 -39
- package/assets/templates/next-tenant-app/src/features/auth/components/login-screen.tsx +97 -98
- package/assets/templates/next-tenant-app/src/features/dashboard/components/tenant-dashboard.tsx +43 -78
- package/assets/templates/next-tenant-app/src/features/demo/components/manifest-demo.tsx +89 -0
- package/assets/templates/next-tenant-app/src/features/public-shell/components/static-public-page.tsx +58 -0
- package/assets/templates/next-tenant-app/src/features/shell/components/private-app-shell.tsx +48 -552
- package/assets/templates/next-tenant-app/src/lib/app-routes.ts +2 -2
- package/assets/templates/next-tenant-app/src/lib/public-site.test.ts +1 -1
- package/assets/templates/next-tenant-app/src/lib/public-site.ts +5 -30
- package/assets/templates/next-tenant-app/src/mw/client.ts +18 -0
- package/assets/templates/next-tenant-app/src/mw/mock.test.ts +21 -0
- package/assets/templates/next-tenant-app/src/mw/mock.ts +35 -0
- package/assets/templates/next-tenant-app/src/mw/provider.tsx +17 -0
- package/assets/templates/next-tenant-app/template.json +3 -3
- package/assets/templates/next-tenant-app/template.schema.json +1 -0
- package/assets/templates/next-tenant-app/tools/template/validate-route-contract.mjs +4 -5
- package/assets/templates/next-tenant-app/tools/template/with-public-site-fixture.mjs +2 -2
- package/bin/minutework.js +1 -1
- package/dist/agent.js +7 -7
- package/dist/agent.js.map +1 -1
- package/dist/auth.js +7 -7
- package/dist/auth.js.map +1 -1
- package/dist/compile.js +5 -5
- package/dist/config.js +6 -6
- package/dist/config.js.map +1 -1
- package/dist/deploy.js +7 -7
- package/dist/deploy.js.map +1 -1
- package/dist/developer-client.js +2 -2
- package/dist/developer-client.js.map +1 -1
- package/dist/index.js +30 -30
- package/dist/index.js.map +1 -1
- package/dist/init.js +10 -10
- package/dist/init.js.map +1 -1
- package/dist/launcher.js +1 -1
- package/dist/launcher.js.map +1 -1
- package/dist/managed-engine.js +6 -6
- package/dist/managed-engine.js.map +1 -1
- package/dist/orchestrator-context.js +1 -1
- package/dist/orchestrator-context.js.map +1 -1
- package/dist/orchestrator.js +15 -15
- package/dist/orchestrator.js.map +1 -1
- package/dist/paths.js +1 -1
- package/dist/paths.js.map +1 -1
- package/dist/publish.js +3 -3
- package/dist/publish.js.map +1 -1
- package/dist/reporting.js +8 -8
- package/dist/reporting.js.map +1 -1
- package/dist/sandbox.js +5 -5
- package/dist/sandbox.js.map +1 -1
- package/dist/state.js +1 -1
- package/dist/state.js.map +1 -1
- package/dist/tokens.js +9 -9
- package/dist/tokens.js.map +1 -1
- package/dist/workspace-assets.js +6 -6
- package/dist/workspace-assets.js.map +1 -1
- package/dist/workspace.js +3 -3
- package/dist/workspace.js.map +1 -1
- package/package.json +3 -3
- package/vendor/workspace-mcp/context.d.ts +6 -6
- package/vendor/workspace-mcp/context.js +56 -56
- package/vendor/workspace-mcp/context.js.map +1 -1
- package/vendor/workspace-mcp/types.d.ts +4 -0
- package/assets/templates/next-tenant-app/src/app/(cms)/[...path]/page.tsx +0 -89
- package/assets/templates/next-tenant-app/src/app/api/auth/context/route.test.ts +0 -90
- package/assets/templates/next-tenant-app/src/app/api/auth/context/route.ts +0 -78
- package/assets/templates/next-tenant-app/src/app/api/auth/login/route.ts +0 -31
- package/assets/templates/next-tenant-app/src/app/api/auth/logout/route.ts +0 -16
- package/assets/templates/next-tenant-app/src/app/api/auth/password-change/route.test.ts +0 -79
- package/assets/templates/next-tenant-app/src/app/api/auth/password-change/route.ts +0 -40
- package/assets/templates/next-tenant-app/src/app/api/auth/password-status/route.test.ts +0 -42
- package/assets/templates/next-tenant-app/src/app/api/auth/password-status/route.ts +0 -29
- package/assets/templates/next-tenant-app/src/app/api/auth/session/route.ts +0 -26
- package/assets/templates/next-tenant-app/src/app/api/gateway/commands/[runId]/route.test.ts +0 -40
- package/assets/templates/next-tenant-app/src/app/api/gateway/commands/[runId]/route.ts +0 -47
- package/assets/templates/next-tenant-app/src/app/api/gateway/commands/route.test.ts +0 -43
- package/assets/templates/next-tenant-app/src/app/api/gateway/commands/route.ts +0 -45
- package/assets/templates/next-tenant-app/src/app/app/examples/runtime-commands/page.test.ts +0 -83
- package/assets/templates/next-tenant-app/src/app/app/examples/runtime-commands/page.tsx +0 -30
- package/assets/templates/next-tenant-app/src/app/app/page.test.ts +0 -62
- package/assets/templates/next-tenant-app/src/app/app/private-content-source.test.ts +0 -88
- package/assets/templates/next-tenant-app/src/app/blog/[slug]/page.test.ts +0 -70
- package/assets/templates/next-tenant-app/src/app/blog/page.test.ts +0 -46
- package/assets/templates/next-tenant-app/src/app/docs/[...slug]/page.test.ts +0 -70
- package/assets/templates/next-tenant-app/src/app/docs/page.test.ts +0 -46
- package/assets/templates/next-tenant-app/src/app/login/page.test.ts +0 -55
- package/assets/templates/next-tenant-app/src/app/page.test.ts +0 -90
- package/assets/templates/next-tenant-app/src/app/pricing/page.test.ts +0 -59
- package/assets/templates/next-tenant-app/src/app/robots.test.ts +0 -40
- package/assets/templates/next-tenant-app/src/app/sitemap.test.ts +0 -63
- package/assets/templates/next-tenant-app/src/features/examples/runtime-command-demo/components/runtime-command-demo.tsx +0 -342
- package/assets/templates/next-tenant-app/src/features/public-shell/components/content-article.tsx +0 -66
- package/assets/templates/next-tenant-app/src/features/public-shell/components/content-collection.tsx +0 -108
- package/assets/templates/next-tenant-app/src/features/public-shell/components/marketing-page-canvas.tsx +0 -111
- package/assets/templates/next-tenant-app/src/features/public-shell/components/public-site-shell.tsx +0 -111
- package/assets/templates/next-tenant-app/src/features/public-shell/components/section-renderer.test.ts +0 -38
- package/assets/templates/next-tenant-app/src/features/public-shell/components/section-renderer.tsx +0 -145
- package/assets/templates/next-tenant-app/src/lib/content/__fixtures__/public-site-snapshot.ts +0 -189
- package/assets/templates/next-tenant-app/src/lib/content/adapter.server.test.ts +0 -444
- package/assets/templates/next-tenant-app/src/lib/content/adapter.server.ts +0 -383
- package/assets/templates/next-tenant-app/src/lib/content/contracts.test.ts +0 -138
- package/assets/templates/next-tenant-app/src/lib/content/contracts.ts +0 -399
- package/assets/templates/next-tenant-app/src/lib/content/custom-adapter.ts +0 -5
- package/assets/templates/next-tenant-app/src/lib/content/empty-state.ts +0 -96
- package/assets/templates/next-tenant-app/src/lib/content/release-manifest.test.ts +0 -93
- package/assets/templates/next-tenant-app/src/lib/content/release-manifest.ts +0 -123
- package/assets/templates/next-tenant-app/src/lib/platform/auth.server.test.ts +0 -75
- package/assets/templates/next-tenant-app/src/lib/platform/auth.server.ts +0 -25
- package/assets/templates/next-tenant-app/src/lib/platform/client.server.test.ts +0 -170
- package/assets/templates/next-tenant-app/src/lib/platform/client.server.ts +0 -661
- package/assets/templates/next-tenant-app/src/lib/platform/contracts.ts +0 -131
- package/assets/templates/next-tenant-app/src/lib/platform/endpoints.server.ts +0 -34
- package/assets/templates/next-tenant-app/src/lib/platform/env.server.test.ts +0 -211
- package/assets/templates/next-tenant-app/src/lib/platform/env.server.ts +0 -151
- package/assets/templates/next-tenant-app/src/lib/platform/route-response.ts +0 -33
- package/assets/templates/next-tenant-app/src/lib/platform/session.server.ts +0 -108
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const changePassword = vi.fn();
|
|
4
|
-
const readPlatformAuthState = vi.fn();
|
|
5
|
-
const syncPlatformAuthStateToResponse = vi.fn();
|
|
6
|
-
|
|
7
|
-
vi.mock("@/lib/platform/client.server", () => ({
|
|
8
|
-
changePassword,
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
vi.mock("@/lib/platform/session.server", () => ({
|
|
12
|
-
readPlatformAuthState,
|
|
13
|
-
syncPlatformAuthStateToResponse,
|
|
14
|
-
}));
|
|
15
|
-
|
|
16
|
-
describe("password change route", () => {
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
vi.clearAllMocks();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("rejects invalid password payloads before proxying upstream", async () => {
|
|
22
|
-
readPlatformAuthState.mockResolvedValue({
|
|
23
|
-
sessionId: "session-1",
|
|
24
|
-
csrfToken: "csrf-1",
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const route = await import("./route");
|
|
28
|
-
const response = await route.POST(
|
|
29
|
-
new Request("http://localhost/api/auth/password-change", {
|
|
30
|
-
method: "POST",
|
|
31
|
-
headers: { "content-type": "application/json" },
|
|
32
|
-
body: JSON.stringify({
|
|
33
|
-
current_password: "old",
|
|
34
|
-
new_password: "new-password",
|
|
35
|
-
confirm_password: "different-password",
|
|
36
|
-
}),
|
|
37
|
-
}),
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
expect(changePassword).not.toHaveBeenCalled();
|
|
41
|
-
expect(response.status).toBe(400);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it("proxies valid password changes through the BFF", async () => {
|
|
45
|
-
const authState = { sessionId: "session-1", csrfToken: "csrf-1" };
|
|
46
|
-
|
|
47
|
-
readPlatformAuthState.mockResolvedValue(authState);
|
|
48
|
-
changePassword.mockResolvedValue({
|
|
49
|
-
data: { has_password: true },
|
|
50
|
-
authState,
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const route = await import("./route");
|
|
54
|
-
const response = await route.POST(
|
|
55
|
-
new Request("http://localhost/api/auth/password-change", {
|
|
56
|
-
method: "POST",
|
|
57
|
-
headers: { "content-type": "application/json" },
|
|
58
|
-
body: JSON.stringify({
|
|
59
|
-
current_password: "old-password",
|
|
60
|
-
new_password: "new-password",
|
|
61
|
-
confirm_password: "new-password",
|
|
62
|
-
}),
|
|
63
|
-
}),
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
expect(changePassword).toHaveBeenCalledWith(authState, {
|
|
67
|
-
current_password: "old-password",
|
|
68
|
-
new_password: "new-password",
|
|
69
|
-
confirm_password: "new-password",
|
|
70
|
-
});
|
|
71
|
-
expect(syncPlatformAuthStateToResponse).toHaveBeenCalledWith(
|
|
72
|
-
response,
|
|
73
|
-
authState,
|
|
74
|
-
authState,
|
|
75
|
-
);
|
|
76
|
-
expect(response.status).toBe(200);
|
|
77
|
-
await expect(response.json()).resolves.toEqual({ has_password: true });
|
|
78
|
-
});
|
|
79
|
-
});
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
|
|
3
|
-
import { changePassword } from "@/lib/platform/client.server";
|
|
4
|
-
import { passwordChangeRequestSchema } from "@/lib/platform/contracts";
|
|
5
|
-
import { toPlatformErrorResponse } from "@/lib/platform/route-response";
|
|
6
|
-
import {
|
|
7
|
-
readPlatformAuthState,
|
|
8
|
-
syncPlatformAuthStateToResponse,
|
|
9
|
-
} from "@/lib/platform/session.server";
|
|
10
|
-
|
|
11
|
-
export async function POST(request: Request) {
|
|
12
|
-
const authState = await readPlatformAuthState();
|
|
13
|
-
|
|
14
|
-
if (!authState.sessionId) {
|
|
15
|
-
return NextResponse.json({ detail: "Authentication required." }, { status: 401 });
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const body = await request.json().catch(() => null);
|
|
19
|
-
const parsed = passwordChangeRequestSchema.safeParse(body);
|
|
20
|
-
|
|
21
|
-
if (!parsed.success) {
|
|
22
|
-
return NextResponse.json(
|
|
23
|
-
{ detail: "Invalid password change payload." },
|
|
24
|
-
{ status: 400 },
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
const result = await changePassword(authState, parsed.data);
|
|
30
|
-
const response = NextResponse.json(result.data, { status: 200 });
|
|
31
|
-
syncPlatformAuthStateToResponse(response, authState, result.authState);
|
|
32
|
-
return response;
|
|
33
|
-
} catch (error) {
|
|
34
|
-
return toPlatformErrorResponse(
|
|
35
|
-
error,
|
|
36
|
-
"Unable to change password.",
|
|
37
|
-
authState,
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const fetchPasswordStatus = vi.fn();
|
|
4
|
-
const readPlatformAuthState = vi.fn();
|
|
5
|
-
const syncPlatformAuthStateToResponse = vi.fn();
|
|
6
|
-
|
|
7
|
-
vi.mock("@/lib/platform/client.server", () => ({
|
|
8
|
-
fetchPasswordStatus,
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
vi.mock("@/lib/platform/session.server", () => ({
|
|
12
|
-
readPlatformAuthState,
|
|
13
|
-
syncPlatformAuthStateToResponse,
|
|
14
|
-
}));
|
|
15
|
-
|
|
16
|
-
describe("password status route", () => {
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
vi.clearAllMocks();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("returns the proxied password status for authenticated sessions", async () => {
|
|
22
|
-
const authState = { sessionId: "session-1", csrfToken: "csrf-1" };
|
|
23
|
-
|
|
24
|
-
readPlatformAuthState.mockResolvedValue(authState);
|
|
25
|
-
fetchPasswordStatus.mockResolvedValue({
|
|
26
|
-
data: { has_password: true },
|
|
27
|
-
authState,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
const route = await import("./route");
|
|
31
|
-
const response = await route.GET();
|
|
32
|
-
|
|
33
|
-
expect(fetchPasswordStatus).toHaveBeenCalledWith(authState);
|
|
34
|
-
expect(syncPlatformAuthStateToResponse).toHaveBeenCalledWith(
|
|
35
|
-
response,
|
|
36
|
-
authState,
|
|
37
|
-
authState,
|
|
38
|
-
);
|
|
39
|
-
expect(response.status).toBe(200);
|
|
40
|
-
await expect(response.json()).resolves.toEqual({ has_password: true });
|
|
41
|
-
});
|
|
42
|
-
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
|
|
3
|
-
import { fetchPasswordStatus } from "@/lib/platform/client.server";
|
|
4
|
-
import { toPlatformErrorResponse } from "@/lib/platform/route-response";
|
|
5
|
-
import {
|
|
6
|
-
readPlatformAuthState,
|
|
7
|
-
syncPlatformAuthStateToResponse,
|
|
8
|
-
} from "@/lib/platform/session.server";
|
|
9
|
-
|
|
10
|
-
export async function GET() {
|
|
11
|
-
const authState = await readPlatformAuthState();
|
|
12
|
-
|
|
13
|
-
if (!authState.sessionId) {
|
|
14
|
-
return NextResponse.json({ detail: "Authentication required." }, { status: 401 });
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
const result = await fetchPasswordStatus(authState);
|
|
19
|
-
const response = NextResponse.json(result.data, { status: 200 });
|
|
20
|
-
syncPlatformAuthStateToResponse(response, authState, result.authState);
|
|
21
|
-
return response;
|
|
22
|
-
} catch (error) {
|
|
23
|
-
return toPlatformErrorResponse(
|
|
24
|
-
error,
|
|
25
|
-
"Unable to load password status.",
|
|
26
|
-
authState,
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
loadCurrentSession,
|
|
5
|
-
} from "@/lib/platform/client.server";
|
|
6
|
-
import { toPlatformErrorResponse } from "@/lib/platform/route-response";
|
|
7
|
-
import {
|
|
8
|
-
readPlatformAuthState,
|
|
9
|
-
syncPlatformAuthStateToResponse,
|
|
10
|
-
} from "@/lib/platform/session.server";
|
|
11
|
-
|
|
12
|
-
export async function GET() {
|
|
13
|
-
const authState = await readPlatformAuthState();
|
|
14
|
-
try {
|
|
15
|
-
const result = await loadCurrentSession(authState);
|
|
16
|
-
const response = NextResponse.json(result.data, { status: 200 });
|
|
17
|
-
syncPlatformAuthStateToResponse(response, authState, result.authState);
|
|
18
|
-
return response;
|
|
19
|
-
} catch (error) {
|
|
20
|
-
return toPlatformErrorResponse(
|
|
21
|
-
error,
|
|
22
|
-
"Unable to load the current platform session.",
|
|
23
|
-
authState,
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const fetchTenantCommandRun = vi.fn();
|
|
4
|
-
const readPlatformAuthState = vi.fn();
|
|
5
|
-
const syncPlatformAuthStateToResponse = vi.fn();
|
|
6
|
-
|
|
7
|
-
vi.mock("@/lib/platform/client.server", () => ({
|
|
8
|
-
fetchTenantCommandRun,
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
vi.mock("@/lib/platform/env.server", () => ({
|
|
12
|
-
env: {
|
|
13
|
-
MW_ENABLE_RUNTIME_COMMAND_EXAMPLE: false,
|
|
14
|
-
},
|
|
15
|
-
}));
|
|
16
|
-
|
|
17
|
-
vi.mock("@/lib/platform/session.server", () => ({
|
|
18
|
-
readPlatformAuthState,
|
|
19
|
-
syncPlatformAuthStateToResponse,
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
describe("runtime command run route", () => {
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
vi.clearAllMocks();
|
|
25
|
-
vi.resetModules();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("returns 404 when the example feature is disabled", async () => {
|
|
29
|
-
const route = await import("./route");
|
|
30
|
-
const response = await route.GET(
|
|
31
|
-
new Request("http://localhost/api/gateway/commands/run-1?tenant_id=tenant-1"),
|
|
32
|
-
{ params: Promise.resolve({ runId: "run-1" }) },
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
expect(response.status).toBe(404);
|
|
36
|
-
expect(readPlatformAuthState).not.toHaveBeenCalled();
|
|
37
|
-
expect(fetchTenantCommandRun).not.toHaveBeenCalled();
|
|
38
|
-
expect(syncPlatformAuthStateToResponse).not.toHaveBeenCalled();
|
|
39
|
-
});
|
|
40
|
-
});
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
|
|
3
|
-
import { fetchTenantCommandRun } from "@/lib/platform/client.server";
|
|
4
|
-
import { env } from "@/lib/platform/env.server";
|
|
5
|
-
import { toPlatformErrorResponse } from "@/lib/platform/route-response";
|
|
6
|
-
import {
|
|
7
|
-
readPlatformAuthState,
|
|
8
|
-
syncPlatformAuthStateToResponse,
|
|
9
|
-
} from "@/lib/platform/session.server";
|
|
10
|
-
|
|
11
|
-
export async function GET(
|
|
12
|
-
request: Request,
|
|
13
|
-
{ params }: { params: Promise<{ runId: string }> },
|
|
14
|
-
) {
|
|
15
|
-
if (!env.MW_ENABLE_RUNTIME_COMMAND_EXAMPLE) {
|
|
16
|
-
return new NextResponse(null, { status: 404 });
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const authState = await readPlatformAuthState();
|
|
20
|
-
if (!authState.sessionId) {
|
|
21
|
-
return NextResponse.json({ detail: "Authentication required." }, { status: 401 });
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const { runId } = await params;
|
|
25
|
-
const url = new URL(request.url);
|
|
26
|
-
const tenantId = url.searchParams.get("tenant_id") || "";
|
|
27
|
-
|
|
28
|
-
if (!tenantId) {
|
|
29
|
-
return NextResponse.json(
|
|
30
|
-
{ detail: "Missing tenant_id query parameter." },
|
|
31
|
-
{ status: 400 },
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
const result = await fetchTenantCommandRun(authState, runId, tenantId);
|
|
37
|
-
const response = NextResponse.json(result.data, { status: 200 });
|
|
38
|
-
syncPlatformAuthStateToResponse(response, authState, result.authState);
|
|
39
|
-
return response;
|
|
40
|
-
} catch (error) {
|
|
41
|
-
return toPlatformErrorResponse(
|
|
42
|
-
error,
|
|
43
|
-
"Unable to load command status.",
|
|
44
|
-
authState,
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const dispatchTenantCommand = vi.fn();
|
|
4
|
-
const readPlatformAuthState = vi.fn();
|
|
5
|
-
const syncPlatformAuthStateToResponse = vi.fn();
|
|
6
|
-
|
|
7
|
-
vi.mock("@/lib/platform/client.server", () => ({
|
|
8
|
-
dispatchTenantCommand,
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
vi.mock("@/lib/platform/env.server", () => ({
|
|
12
|
-
env: {
|
|
13
|
-
MW_ENABLE_RUNTIME_COMMAND_EXAMPLE: false,
|
|
14
|
-
},
|
|
15
|
-
}));
|
|
16
|
-
|
|
17
|
-
vi.mock("@/lib/platform/session.server", () => ({
|
|
18
|
-
readPlatformAuthState,
|
|
19
|
-
syncPlatformAuthStateToResponse,
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
describe("runtime command route", () => {
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
vi.clearAllMocks();
|
|
25
|
-
vi.resetModules();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("returns 404 when the example feature is disabled", async () => {
|
|
29
|
-
const route = await import("./route");
|
|
30
|
-
const response = await route.POST(
|
|
31
|
-
new Request("http://localhost/api/gateway/commands", {
|
|
32
|
-
method: "POST",
|
|
33
|
-
headers: { "content-type": "application/json" },
|
|
34
|
-
body: JSON.stringify({ command: "deploy" }),
|
|
35
|
-
}),
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
expect(response.status).toBe(404);
|
|
39
|
-
expect(readPlatformAuthState).not.toHaveBeenCalled();
|
|
40
|
-
expect(dispatchTenantCommand).not.toHaveBeenCalled();
|
|
41
|
-
expect(syncPlatformAuthStateToResponse).not.toHaveBeenCalled();
|
|
42
|
-
});
|
|
43
|
-
});
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
|
|
3
|
-
import { dispatchTenantCommand } from "@/lib/platform/client.server";
|
|
4
|
-
import { commandDispatchRequestSchema } from "@/lib/platform/contracts";
|
|
5
|
-
import { env } from "@/lib/platform/env.server";
|
|
6
|
-
import { toPlatformErrorResponse } from "@/lib/platform/route-response";
|
|
7
|
-
import {
|
|
8
|
-
readPlatformAuthState,
|
|
9
|
-
syncPlatformAuthStateToResponse,
|
|
10
|
-
} from "@/lib/platform/session.server";
|
|
11
|
-
|
|
12
|
-
export async function POST(request: Request) {
|
|
13
|
-
if (!env.MW_ENABLE_RUNTIME_COMMAND_EXAMPLE) {
|
|
14
|
-
return new NextResponse(null, { status: 404 });
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const authState = await readPlatformAuthState();
|
|
18
|
-
|
|
19
|
-
if (!authState.sessionId) {
|
|
20
|
-
return NextResponse.json({ detail: "Authentication required." }, { status: 401 });
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const body = await request.json().catch(() => null);
|
|
24
|
-
const parsed = commandDispatchRequestSchema.safeParse(body);
|
|
25
|
-
|
|
26
|
-
if (!parsed.success) {
|
|
27
|
-
return NextResponse.json(
|
|
28
|
-
{ detail: "Invalid command payload." },
|
|
29
|
-
{ status: 400 },
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
const result = await dispatchTenantCommand(authState, parsed.data);
|
|
35
|
-
const response = NextResponse.json(result.data, { status: 200 });
|
|
36
|
-
syncPlatformAuthStateToResponse(response, authState, result.authState);
|
|
37
|
-
return response;
|
|
38
|
-
} catch (error) {
|
|
39
|
-
return toPlatformErrorResponse(
|
|
40
|
-
error,
|
|
41
|
-
"Unable to dispatch command.",
|
|
42
|
-
authState,
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const notFound = vi.fn(() => {
|
|
4
|
-
throw new Error("notFound");
|
|
5
|
-
});
|
|
6
|
-
const resolveAuthenticatedSession = vi.fn();
|
|
7
|
-
|
|
8
|
-
vi.mock("next/navigation", () => ({
|
|
9
|
-
notFound,
|
|
10
|
-
}));
|
|
11
|
-
|
|
12
|
-
vi.mock("@/features/shell/components/private-app-shell", () => ({
|
|
13
|
-
PrivateAppShell: () => null,
|
|
14
|
-
}));
|
|
15
|
-
|
|
16
|
-
vi.mock("@/lib/platform/auth.server", () => ({
|
|
17
|
-
resolveAuthenticatedSession,
|
|
18
|
-
}));
|
|
19
|
-
|
|
20
|
-
vi.mock("@/lib/platform/endpoints.server", () => ({
|
|
21
|
-
platformAuthEndpoints: {
|
|
22
|
-
operatorConsole: "http://127.0.0.1:8000/ops/login/",
|
|
23
|
-
},
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
vi.mock("@/lib/platform/env.server", () => ({
|
|
27
|
-
env: {
|
|
28
|
-
MW_TEMPLATE_APP_NAME: "PandaWork Combined Starter",
|
|
29
|
-
MW_ENABLE_RUNTIME_COMMAND_EXAMPLE: false,
|
|
30
|
-
},
|
|
31
|
-
}));
|
|
32
|
-
|
|
33
|
-
describe("runtime commands example page", () => {
|
|
34
|
-
beforeEach(() => {
|
|
35
|
-
vi.clearAllMocks();
|
|
36
|
-
vi.resetModules();
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it("returns notFound before loading auth when the example is disabled", async () => {
|
|
40
|
-
const page = await import("./page");
|
|
41
|
-
|
|
42
|
-
await expect(page.default()).rejects.toThrow("notFound");
|
|
43
|
-
expect(notFound).toHaveBeenCalledTimes(1);
|
|
44
|
-
expect(resolveAuthenticatedSession).not.toHaveBeenCalled();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it("loads the private shell when the example is enabled", async () => {
|
|
48
|
-
vi.doMock("@/lib/platform/env.server", () => ({
|
|
49
|
-
env: {
|
|
50
|
-
MW_TEMPLATE_APP_NAME: "PandaWork Combined Starter",
|
|
51
|
-
MW_ENABLE_RUNTIME_COMMAND_EXAMPLE: true,
|
|
52
|
-
},
|
|
53
|
-
}));
|
|
54
|
-
resolveAuthenticatedSession.mockResolvedValue({
|
|
55
|
-
authenticated: true,
|
|
56
|
-
user: {
|
|
57
|
-
id: "user-1",
|
|
58
|
-
username: "demo-user",
|
|
59
|
-
email: "demo@example.com",
|
|
60
|
-
},
|
|
61
|
-
active_tenant_id: "tenant-1",
|
|
62
|
-
active_tenant: {
|
|
63
|
-
tenant_id: "tenant-1",
|
|
64
|
-
tenant_slug: "alpha",
|
|
65
|
-
tenant_name: "Alpha",
|
|
66
|
-
role: "admin",
|
|
67
|
-
},
|
|
68
|
-
memberships: [
|
|
69
|
-
{
|
|
70
|
-
tenant_id: "tenant-1",
|
|
71
|
-
tenant_slug: "alpha",
|
|
72
|
-
tenant_name: "Alpha",
|
|
73
|
-
role: "admin",
|
|
74
|
-
},
|
|
75
|
-
],
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
const page = await import("./page");
|
|
79
|
-
|
|
80
|
-
await expect(page.default()).resolves.toBeDefined();
|
|
81
|
-
expect(resolveAuthenticatedSession).toHaveBeenCalledTimes(1);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { notFound } from "next/navigation";
|
|
2
|
-
|
|
3
|
-
import { PrivateAppShell } from "@/features/shell/components/private-app-shell";
|
|
4
|
-
import { resolveAuthenticatedSession } from "@/lib/platform/auth.server";
|
|
5
|
-
import { platformAuthEndpoints } from "@/lib/platform/endpoints.server";
|
|
6
|
-
import { env } from "@/lib/platform/env.server";
|
|
7
|
-
|
|
8
|
-
export const metadata = {
|
|
9
|
-
title: "Runtime Commands Example",
|
|
10
|
-
description:
|
|
11
|
-
"Optional runtime command example inside the authenticated /app surface.",
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export default async function RuntimeCommandsExamplePage() {
|
|
15
|
-
if (!env.MW_ENABLE_RUNTIME_COMMAND_EXAMPLE) {
|
|
16
|
-
notFound();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const session = await resolveAuthenticatedSession();
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<PrivateAppShell
|
|
23
|
-
initialSession={session}
|
|
24
|
-
appName={env.MW_TEMPLATE_APP_NAME}
|
|
25
|
-
operatorConsoleHref={platformAuthEndpoints.operatorConsole}
|
|
26
|
-
runtimeCommandExampleEnabled={env.MW_ENABLE_RUNTIME_COMMAND_EXAMPLE}
|
|
27
|
-
view="runtime-command-demo"
|
|
28
|
-
/>
|
|
29
|
-
);
|
|
30
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const resolveAuthenticatedSession = vi.fn();
|
|
4
|
-
|
|
5
|
-
vi.mock("@/features/shell/components/private-app-shell", () => ({
|
|
6
|
-
PrivateAppShell: () => null,
|
|
7
|
-
}));
|
|
8
|
-
|
|
9
|
-
vi.mock("@/lib/platform/auth.server", () => ({
|
|
10
|
-
resolveAuthenticatedSession,
|
|
11
|
-
}));
|
|
12
|
-
|
|
13
|
-
vi.mock("@/lib/platform/endpoints.server", () => ({
|
|
14
|
-
platformAuthEndpoints: {
|
|
15
|
-
operatorConsole: "http://127.0.0.1:8000/ops/login/",
|
|
16
|
-
},
|
|
17
|
-
}));
|
|
18
|
-
|
|
19
|
-
vi.mock("@/lib/platform/env.server", () => ({
|
|
20
|
-
env: {
|
|
21
|
-
MW_TEMPLATE_APP_NAME: "PandaWork Combined Starter",
|
|
22
|
-
MW_ENABLE_RUNTIME_COMMAND_EXAMPLE: false,
|
|
23
|
-
},
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
describe("authenticated app home page", () => {
|
|
27
|
-
beforeEach(() => {
|
|
28
|
-
vi.clearAllMocks();
|
|
29
|
-
vi.resetModules();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("renders the private shell after the auth guard resolves", async () => {
|
|
33
|
-
resolveAuthenticatedSession.mockResolvedValue({
|
|
34
|
-
authenticated: true,
|
|
35
|
-
user: {
|
|
36
|
-
id: "user-1",
|
|
37
|
-
username: "demo-user",
|
|
38
|
-
email: "demo@example.com",
|
|
39
|
-
},
|
|
40
|
-
active_tenant_id: "tenant-1",
|
|
41
|
-
active_tenant: {
|
|
42
|
-
tenant_id: "tenant-1",
|
|
43
|
-
tenant_slug: "alpha",
|
|
44
|
-
tenant_name: "Alpha",
|
|
45
|
-
role: "admin",
|
|
46
|
-
},
|
|
47
|
-
memberships: [
|
|
48
|
-
{
|
|
49
|
-
tenant_id: "tenant-1",
|
|
50
|
-
tenant_slug: "alpha",
|
|
51
|
-
tenant_name: "Alpha",
|
|
52
|
-
role: "admin",
|
|
53
|
-
},
|
|
54
|
-
],
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const page = await import("./page");
|
|
58
|
-
|
|
59
|
-
await expect(page.default()).resolves.toBeDefined();
|
|
60
|
-
expect(resolveAuthenticatedSession).toHaveBeenCalledTimes(1);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const originalEnv = { ...process.env };
|
|
4
|
-
const resolveAuthenticatedSession = vi.fn();
|
|
5
|
-
|
|
6
|
-
function restoreProcessEnv() {
|
|
7
|
-
for (const key of Object.keys(process.env)) {
|
|
8
|
-
if (!(key in originalEnv)) {
|
|
9
|
-
delete process.env[key];
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
Object.assign(process.env, originalEnv);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function applyPrivateOnlyServerEnv() {
|
|
17
|
-
restoreProcessEnv();
|
|
18
|
-
process.env.MW_PLATFORM_BASE_URL = "http://127.0.0.1:8000";
|
|
19
|
-
process.env.MW_PUBLIC_CONTENT_SOURCE = "none";
|
|
20
|
-
process.env.MW_TEMPLATE_APP_NAME = "Private Only Workspace";
|
|
21
|
-
process.env.MW_ENABLE_RUNTIME_COMMAND_EXAMPLE = "false";
|
|
22
|
-
delete process.env.MW_CONTENT_API_TOKEN;
|
|
23
|
-
delete process.env.MW_PUBLIC_BASE_URL;
|
|
24
|
-
delete process.env.MW_PUBLIC_SITE_PROPERTY_KEY;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
vi.mock("@/features/shell/components/private-app-shell", () => ({
|
|
28
|
-
PrivateAppShell: () => null,
|
|
29
|
-
}));
|
|
30
|
-
|
|
31
|
-
vi.mock("@/lib/platform/auth.server", () => ({
|
|
32
|
-
resolveAuthenticatedSession,
|
|
33
|
-
}));
|
|
34
|
-
|
|
35
|
-
vi.mock("@/lib/platform/endpoints.server", () => ({
|
|
36
|
-
platformAuthEndpoints: {
|
|
37
|
-
operatorConsole: "http://127.0.0.1:8000/ops/login/",
|
|
38
|
-
},
|
|
39
|
-
}));
|
|
40
|
-
|
|
41
|
-
describe("private app routes with disabled public content", () => {
|
|
42
|
-
beforeEach(() => {
|
|
43
|
-
vi.clearAllMocks();
|
|
44
|
-
vi.resetModules();
|
|
45
|
-
applyPrivateOnlyServerEnv();
|
|
46
|
-
resolveAuthenticatedSession.mockResolvedValue({
|
|
47
|
-
authenticated: true,
|
|
48
|
-
user: {
|
|
49
|
-
id: "user-1",
|
|
50
|
-
username: "demo-user",
|
|
51
|
-
email: "demo@example.com",
|
|
52
|
-
},
|
|
53
|
-
active_tenant_id: "tenant-1",
|
|
54
|
-
active_tenant: {
|
|
55
|
-
tenant_id: "tenant-1",
|
|
56
|
-
tenant_slug: "alpha",
|
|
57
|
-
tenant_name: "Alpha",
|
|
58
|
-
role: "admin",
|
|
59
|
-
},
|
|
60
|
-
memberships: [
|
|
61
|
-
{
|
|
62
|
-
tenant_id: "tenant-1",
|
|
63
|
-
tenant_slug: "alpha",
|
|
64
|
-
tenant_name: "Alpha",
|
|
65
|
-
role: "admin",
|
|
66
|
-
},
|
|
67
|
-
],
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
afterEach(() => {
|
|
72
|
-
restoreProcessEnv();
|
|
73
|
-
vi.resetModules();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it("imports /app entrypoints without CMS or public base environment", async () => {
|
|
77
|
-
const [layout, page] = await Promise.all([
|
|
78
|
-
import("./layout"),
|
|
79
|
-
import("./page"),
|
|
80
|
-
]);
|
|
81
|
-
|
|
82
|
-
await expect(layout.default({ children: "workspace" })).resolves.toBe(
|
|
83
|
-
"workspace",
|
|
84
|
-
);
|
|
85
|
-
await expect(page.default()).resolves.toBeDefined();
|
|
86
|
-
expect(resolveAuthenticatedSession).toHaveBeenCalledTimes(2);
|
|
87
|
-
});
|
|
88
|
-
});
|