@askrjs/cli 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -7
- package/dist/add.d.ts +16 -0
- package/dist/add.js +558 -1
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +43 -16
- package/dist/create.d.ts +5 -0
- package/dist/create.js +104 -26
- package/dist/directory-swap-DWoHtx7C.js +35 -0
- package/dist/discovery-Difb7Y4G.js +323 -0
- package/dist/generate.d.ts +5 -0
- package/dist/generate.js +461 -0
- package/dist/is-direct-execution-Cdlr-ZUl.js +0 -2
- package/dist/openapi.d.ts +25 -0
- package/dist/openapi.js +49 -16
- package/dist/planner-VAj7qlxr.js +285 -0
- package/dist/range-YUs9eimn.js +125 -0
- package/dist/registry-CyrRHRG5.js +209 -0
- package/dist/skills/askr-dashboard-charts/SKILL.md +61 -44
- package/dist/skills/askr-dashboard-charts/agents/openai.yaml +2 -2
- package/dist/skills/askr-ssr-ssg/SKILL.md +3 -1
- package/dist/{skills-Bh0mEhIx.js → skills-B7CbWur9.js} +89 -26
- package/dist/skills.d.ts +18 -0
- package/dist/skills.js +1 -1
- package/dist/specification-DXnDOC-0.js +49 -0
- package/dist/ssg-config.d.ts +41 -0
- package/dist/ssg-config.js +1 -0
- package/dist/ssg.d.ts +61 -0
- package/dist/ssg.js +360 -24
- package/dist/templates/full-stack/AGENTS.md +0 -1
- package/dist/templates/full-stack/README.md +0 -1
- package/dist/templates/full-stack/index.html +0 -1
- package/dist/templates/full-stack/package.json +5 -3
- package/dist/templates/full-stack/server.ts +5 -9
- package/dist/templates/full-stack/src/action-authorizations.ts +2 -2
- package/dist/templates/full-stack/src/actions/create-message.ts +5 -5
- package/dist/templates/full-stack/src/i18n.ts +4 -4
- package/dist/templates/full-stack/src/main.tsx +4 -5
- package/dist/templates/full-stack/src/pages/home.tsx +5 -5
- package/dist/templates/full-stack/src/pages/layout.tsx +15 -5
- package/dist/templates/full-stack/src/pages/not-found.tsx +5 -2
- package/dist/templates/full-stack/src/routes.tsx +11 -12
- package/dist/templates/full-stack/src/schemas.ts +1 -2
- package/dist/templates/full-stack/src/server/action-registry.ts +5 -10
- package/dist/templates/full-stack/src/server/actions/create-message.ts +4 -4
- package/dist/templates/full-stack/src/server/app.ts +67 -57
- package/dist/templates/full-stack/src/server/dependencies.ts +10 -10
- package/dist/templates/full-stack/src/server/entry-server.ts +3 -3
- package/dist/templates/full-stack/src/telemetry.ts +1 -2
- package/dist/templates/full-stack/tests/actions/create-message.test.ts +7 -8
- package/dist/templates/full-stack/tsconfig.json +1 -2
- package/dist/templates/full-stack/vite.config.ts +5 -6
- package/dist/templates/spa/AGENTS.md +1 -1
- package/dist/templates/spa/package.json +3 -4
- package/dist/templates/spa/src/adapters/operations-client.ts +7 -2
- package/dist/templates/spa/src/pages/app/_routes.tsx +2 -0
- package/dist/templates/spa/src/pages/app/admin-home.tsx +21 -3
- package/dist/templates/spa/src/pages/public/_routes.tsx +2 -0
- package/dist/templates/spa/src/styles.css +1 -1
- package/dist/templates/spa/tsconfig.json +2 -1
- package/dist/templates/spa/vitest.config.ts +0 -4
- package/dist/templates/ssg/README.md +1 -1
- package/dist/templates/ssg/package.json +1 -1
- package/dist/templates/ssg/ssg.config.ts +7 -0
- package/dist/templates/ssg/tests/ssg-config.test.ts +5 -3
- package/dist/templates/ssg/tsconfig.json +2 -1
- package/dist/templates/ssg/vitest.config.ts +0 -4
- package/dist/templates/ssr/package.json +2 -2
- package/dist/templates/ssr/server.ts +4 -10
- package/dist/templates/ssr/src/entry-server.tsx +6 -4
- package/dist/templates/startkit/package.json +2 -2
- package/dist/templates/startkit/src/lib/mock-data.ts +17 -39
- package/dist/templates/startkit/tsconfig.json +2 -1
- package/dist/update.d.ts +41 -0
- package/dist/update.js +282 -2
- package/dist/writer-D8qe_7ud.js +226 -0
- package/package.json +23 -22
- package/dist/add-DqhqRzBQ.js +0 -555
- package/dist/add-DqhqRzBQ.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/create.js.map +0 -1
- package/dist/is-direct-execution-Cdlr-ZUl.js.map +0 -1
- package/dist/openapi.js.map +0 -1
- package/dist/skills-Bh0mEhIx.js.map +0 -1
- package/dist/ssg.js.map +0 -1
- package/dist/templates/full-stack/src/vite-server.d.ts +0 -6
- package/dist/templates/spa/src/styles.d.ts +0 -1
- package/dist/templates/ssg/src/vite-env.d.ts +0 -5
- package/dist/templates/ssr/src/vite-server.d.ts +0 -7
- package/dist/templates/startkit/src/vite-env.d.ts +0 -5
- package/dist/update-DyW1na5V.js +0 -1140
- package/dist/update-DyW1na5V.js.map +0 -1
- package/skills/askr-accessibility/SKILL.md +0 -68
- package/skills/askr-accessibility/agents/openai.yaml +0 -4
- package/skills/askr-agent-execution/SKILL.md +0 -85
- package/skills/askr-agent-execution/agents/openai.yaml +0 -4
- package/skills/askr-agent-workflows/SKILL.md +0 -57
- package/skills/askr-agent-workflows/agents/openai.yaml +0 -4
- package/skills/askr-api-integration/SKILL.md +0 -79
- package/skills/askr-api-integration/agents/openai.yaml +0 -4
- package/skills/askr-app-builder/SKILL.md +0 -99
- package/skills/askr-app-builder/agents/openai.yaml +0 -4
- package/skills/askr-auth-access/SKILL.md +0 -74
- package/skills/askr-auth-access/agents/openai.yaml +0 -4
- package/skills/askr-cli-vite/SKILL.md +0 -76
- package/skills/askr-cli-vite/agents/openai.yaml +0 -4
- package/skills/askr-dashboard-charts/SKILL.md +0 -82
- package/skills/askr-dashboard-charts/agents/openai.yaml +0 -4
- package/skills/askr-design-system/SKILL.md +0 -86
- package/skills/askr-design-system/agents/openai.yaml +0 -4
- package/skills/askr-env-config/SKILL.md +0 -74
- package/skills/askr-env-config/agents/openai.yaml +0 -4
- package/skills/askr-error-loading-empty/SKILL.md +0 -89
- package/skills/askr-error-loading-empty/agents/openai.yaml +0 -4
- package/skills/askr-file-upload-artifacts/SKILL.md +0 -77
- package/skills/askr-file-upload-artifacts/agents/openai.yaml +0 -4
- package/skills/askr-forms-tables-crud/SKILL.md +0 -98
- package/skills/askr-forms-tables-crud/agents/openai.yaml +0 -4
- package/skills/askr-mental-model/SKILL.md +0 -109
- package/skills/askr-mental-model/agents/openai.yaml +0 -4
- package/skills/askr-migration-react/SKILL.md +0 -81
- package/skills/askr-migration-react/agents/openai.yaml +0 -4
- package/skills/askr-observability-debugging/SKILL.md +0 -83
- package/skills/askr-observability-debugging/agents/openai.yaml +0 -4
- package/skills/askr-project-structure/SKILL.md +0 -79
- package/skills/askr-project-structure/agents/openai.yaml +0 -4
- package/skills/askr-query-mutation/SKILL.md +0 -115
- package/skills/askr-query-mutation/agents/openai.yaml +0 -4
- package/skills/askr-realtime-streaming/SKILL.md +0 -76
- package/skills/askr-realtime-streaming/agents/openai.yaml +0 -4
- package/skills/askr-resources-data/SKILL.md +0 -100
- package/skills/askr-resources-data/agents/openai.yaml +0 -4
- package/skills/askr-routing-layouts/SKILL.md +0 -107
- package/skills/askr-routing-layouts/agents/openai.yaml +0 -4
- package/skills/askr-runtime-reactivity/SKILL.md +0 -92
- package/skills/askr-runtime-reactivity/agents/openai.yaml +0 -4
- package/skills/askr-ssr-ssg/SKILL.md +0 -76
- package/skills/askr-ssr-ssg/agents/openai.yaml +0 -4
- package/skills/askr-testing-determinism/SKILL.md +0 -75
- package/skills/askr-testing-determinism/agents/openai.yaml +0 -4
- package/skills/askr-theming/SKILL.md +0 -86
- package/skills/askr-theming/agents/openai.yaml +0 -4
- package/skills/askr-ui-composition/SKILL.md +0 -92
- package/skills/askr-ui-composition/agents/openai.yaml +0 -4
- package/templates/full-stack/AGENTS.md +0 -12
- package/templates/full-stack/README.md +0 -18
- package/templates/full-stack/gitignore.template +0 -4
- package/templates/full-stack/index.html +0 -14
- package/templates/full-stack/package.json +0 -37
- package/templates/full-stack/server.ts +0 -13
- package/templates/full-stack/src/action-authorizations.ts +0 -10
- package/templates/full-stack/src/actions/create-message.ts +0 -10
- package/templates/full-stack/src/i18n.ts +0 -8
- package/templates/full-stack/src/main.tsx +0 -12
- package/templates/full-stack/src/pages/home.tsx +0 -25
- package/templates/full-stack/src/pages/layout.tsx +0 -33
- package/templates/full-stack/src/pages/not-found.tsx +0 -4
- package/templates/full-stack/src/routes.tsx +0 -20
- package/templates/full-stack/src/schemas.ts +0 -11
- package/templates/full-stack/src/server/action-registry.ts +0 -12
- package/templates/full-stack/src/server/actions/create-message.ts +0 -14
- package/templates/full-stack/src/server/app.ts +0 -66
- package/templates/full-stack/src/server/dependencies.ts +0 -55
- package/templates/full-stack/src/server/entry-server.ts +0 -8
- package/templates/full-stack/src/telemetry.ts +0 -4
- package/templates/full-stack/src/vite-server.d.ts +0 -6
- package/templates/full-stack/tests/actions/create-message.test.ts +0 -13
- package/templates/full-stack/tsconfig.json +0 -16
- package/templates/full-stack/vite.config.ts +0 -11
- package/templates/spa/AGENTS.md +0 -60
- package/templates/spa/README.md +0 -96
- package/templates/spa/gitignore.template +0 -16
- package/templates/spa/index.html +0 -13
- package/templates/spa/package.json +0 -35
- package/templates/spa/src/adapters/operations-client.ts +0 -90
- package/templates/spa/src/components/shared/metric-card.tsx +0 -27
- package/templates/spa/src/components/shared/status-badge.tsx +0 -24
- package/templates/spa/src/features/operations/operations.query.ts +0 -9
- package/templates/spa/src/main.tsx +0 -10
- package/templates/spa/src/pages/_layout.tsx +0 -9
- package/templates/spa/src/pages/_routes.tsx +0 -27
- package/templates/spa/src/pages/app/_layout.tsx +0 -94
- package/templates/spa/src/pages/app/_routes.tsx +0 -10
- package/templates/spa/src/pages/app/admin-home.tsx +0 -152
- package/templates/spa/src/pages/app/agent-runs.tsx +0 -93
- package/templates/spa/src/pages/app/settings.tsx +0 -91
- package/templates/spa/src/pages/auth/_layout.tsx +0 -38
- package/templates/spa/src/pages/auth/_routes.tsx +0 -6
- package/templates/spa/src/pages/auth/login.tsx +0 -63
- package/templates/spa/src/pages/not-found.tsx +0 -22
- package/templates/spa/src/pages/public/_layout.tsx +0 -47
- package/templates/spa/src/pages/public/_routes.tsx +0 -6
- package/templates/spa/src/pages/public/home.tsx +0 -143
- package/templates/spa/src/shared/format.ts +0 -12
- package/templates/spa/src/shared/navigation.ts +0 -15
- package/templates/spa/src/styles/components.css +0 -49
- package/templates/spa/src/styles/layout.css +0 -192
- package/templates/spa/src/styles/reset.css +0 -44
- package/templates/spa/src/styles/theme.css +0 -57
- package/templates/spa/src/styles/tokens.css +0 -20
- package/templates/spa/src/styles.css +0 -7
- package/templates/spa/src/styles.d.ts +0 -1
- package/templates/spa/tests/app.test.tsx +0 -37
- package/templates/spa/tests/components/shared.test.tsx +0 -12
- package/templates/spa/tests/resources.test.ts +0 -22
- package/templates/spa/tsconfig.json +0 -20
- package/templates/spa/tsconfig.node.json +0 -10
- package/templates/spa/vite.config.ts +0 -24
- package/templates/spa/vitest.config.ts +0 -17
- package/templates/ssg/AGENTS.md +0 -55
- package/templates/ssg/README.md +0 -39
- package/templates/ssg/gitignore.template +0 -17
- package/templates/ssg/index.html +0 -13
- package/templates/ssg/package.json +0 -35
- package/templates/ssg/src/app.tsx +0 -14
- package/templates/ssg/src/components/badge.tsx +0 -3
- package/templates/ssg/src/components/counter.tsx +0 -30
- package/templates/ssg/src/components/site-shell.tsx +0 -111
- package/templates/ssg/src/jsx.d.ts +0 -23
- package/templates/ssg/src/main.tsx +0 -8
- package/templates/ssg/src/pages/about.tsx +0 -82
- package/templates/ssg/src/pages/content.tsx +0 -63
- package/templates/ssg/src/pages/example.tsx +0 -97
- package/templates/ssg/src/pages/home.tsx +0 -51
- package/templates/ssg/src/resources/user.ts +0 -15
- package/templates/ssg/src/routes.tsx +0 -15
- package/templates/ssg/src/styles.css +0 -89
- package/templates/ssg/src/vite-env.d.ts +0 -5
- package/templates/ssg/ssg.config.ts +0 -34
- package/templates/ssg/tests/app.test.tsx +0 -19
- package/templates/ssg/tests/components/counter.test.tsx +0 -18
- package/templates/ssg/tests/resources.test.ts +0 -11
- package/templates/ssg/tests/ssg-config.test.ts +0 -11
- package/templates/ssg/tsconfig.json +0 -20
- package/templates/ssg/tsconfig.node.json +0 -10
- package/templates/ssg/vite.config.ts +0 -24
- package/templates/ssg/vitest.config.ts +0 -17
- package/templates/ssr/AGENTS.md +0 -28
- package/templates/ssr/README.md +0 -38
- package/templates/ssr/gitignore.template +0 -16
- package/templates/ssr/index.html +0 -13
- package/templates/ssr/package.json +0 -34
- package/templates/ssr/server.ts +0 -16
- package/templates/ssr/src/app.tsx +0 -21
- package/templates/ssr/src/components/counter.tsx +0 -26
- package/templates/ssr/src/entry-server.tsx +0 -10
- package/templates/ssr/src/main.tsx +0 -11
- package/templates/ssr/src/pages/about.tsx +0 -75
- package/templates/ssr/src/pages/example.tsx +0 -113
- package/templates/ssr/src/pages/home.tsx +0 -56
- package/templates/ssr/src/resources/user.ts +0 -15
- package/templates/ssr/src/routes.tsx +0 -13
- package/templates/ssr/src/styles.css +0 -148
- package/templates/ssr/src/vite-server.d.ts +0 -7
- package/templates/ssr/tests/app.test.tsx +0 -24
- package/templates/ssr/tests/components/counter.test.tsx +0 -13
- package/templates/ssr/tests/resources.test.ts +0 -11
- package/templates/ssr/tsconfig.json +0 -22
- package/templates/ssr/tsconfig.node.json +0 -10
- package/templates/ssr/tsconfig.server.json +0 -15
- package/templates/ssr/vite.config.ts +0 -25
- package/templates/ssr/vitest.config.ts +0 -13
- package/templates/startkit/AGENTS.md +0 -77
- package/templates/startkit/README.md +0 -192
- package/templates/startkit/gitignore.template +0 -16
- package/templates/startkit/index.html +0 -13
- package/templates/startkit/package.json +0 -35
- package/templates/startkit/src/components/app-header.tsx +0 -93
- package/templates/startkit/src/components/app-sidebar.tsx +0 -95
- package/templates/startkit/src/components/data-table.tsx +0 -80
- package/templates/startkit/src/components/empty-state.tsx +0 -13
- package/templates/startkit/src/components/page-header.tsx +0 -23
- package/templates/startkit/src/components/stat-card.tsx +0 -24
- package/templates/startkit/src/features/accounts/account-filters.tsx +0 -61
- package/templates/startkit/src/features/accounts/account-table.tsx +0 -79
- package/templates/startkit/src/lib/format.ts +0 -31
- package/templates/startkit/src/lib/mock-data.ts +0 -441
- package/templates/startkit/src/lib/routes.ts +0 -116
- package/templates/startkit/src/main.tsx +0 -12
- package/templates/startkit/src/pages/_layout.tsx +0 -56
- package/templates/startkit/src/pages/auth/_layout.tsx +0 -7
- package/templates/startkit/src/pages/auth/login.tsx +0 -129
- package/templates/startkit/src/pages/home.tsx +0 -83
- package/templates/startkit/src/pages/not-found.tsx +0 -24
- package/templates/startkit/src/pages/workspace/_layout.tsx +0 -17
- package/templates/startkit/src/pages/workspace/accounts/index.tsx +0 -217
- package/templates/startkit/src/pages/workspace/dashboard.tsx +0 -118
- package/templates/startkit/src/pages/workspace/settings.tsx +0 -218
- package/templates/startkit/src/router.tsx +0 -7
- package/templates/startkit/src/routes/auth-config.ts +0 -38
- package/templates/startkit/src/routes/auth.ts +0 -8
- package/templates/startkit/src/routes/index.ts +0 -28
- package/templates/startkit/src/routes/public.ts +0 -8
- package/templates/startkit/src/routes/workspace/accounts.ts +0 -8
- package/templates/startkit/src/routes/workspace/index.ts +0 -14
- package/templates/startkit/src/styles/components.css +0 -396
- package/templates/startkit/src/styles/layout.css +0 -192
- package/templates/startkit/src/styles/reset.css +0 -38
- package/templates/startkit/src/styles/theme.css +0 -76
- package/templates/startkit/src/styles/tokens.css +0 -67
- package/templates/startkit/src/styles.css +0 -7
- package/templates/startkit/src/toast.ts +0 -55
- package/templates/startkit/src/utils/join-classes.ts +0 -4
- package/templates/startkit/src/vite-env.d.ts +0 -5
- package/templates/startkit/tests/app.test.tsx +0 -32
- package/templates/startkit/tests/preferences.test.ts +0 -43
- package/templates/startkit/tests/resources.test.ts +0 -82
- package/templates/startkit/tsconfig.json +0 -20
- package/templates/startkit/tsconfig.node.json +0 -10
- package/templates/startkit/vite.config.ts +0 -32
- package/templates/startkit/vitest.config.ts +0 -13
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
import { createRouteRegistry, group, route } from
|
|
2
|
-
import { actionsFor } from
|
|
3
|
-
import { AppLayout } from
|
|
4
|
-
import { HomePage } from
|
|
5
|
-
import { NotFoundPage } from
|
|
1
|
+
import { createRouteRegistry, group, route } from "@askrjs/askr/router";
|
|
2
|
+
import { actionsFor } from "./action-authorizations";
|
|
3
|
+
import { AppLayout } from "./pages/layout";
|
|
4
|
+
import { HomePage } from "./pages/home";
|
|
5
|
+
import { NotFoundPage } from "./pages/not-found";
|
|
6
6
|
|
|
7
7
|
export const pageRegistry = createRouteRegistry(() => {
|
|
8
8
|
group({ layout: AppLayout }, () => {
|
|
9
|
-
route(
|
|
10
|
-
actions: actionsFor(
|
|
9
|
+
route("/", HomePage, {
|
|
10
|
+
actions: actionsFor("/"),
|
|
11
11
|
meta: {
|
|
12
|
-
title:
|
|
13
|
-
description:
|
|
14
|
-
html: { lang:
|
|
12
|
+
title: "{{appName}}",
|
|
13
|
+
description: "A progressive full-stack Askr application.",
|
|
14
|
+
html: { lang: "en", dir: "ltr" },
|
|
15
15
|
},
|
|
16
16
|
});
|
|
17
|
-
route(
|
|
17
|
+
route("/*", NotFoundPage);
|
|
18
18
|
});
|
|
19
19
|
});
|
|
20
|
-
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { schema } from
|
|
1
|
+
import { schema } from "@askrjs/schema";
|
|
2
2
|
|
|
3
3
|
export const MessageInput = schema.object({
|
|
4
4
|
value: schema.string({ minLength: 1, maxLength: 200 }),
|
|
@@ -8,4 +8,3 @@ export const Message = schema.object({
|
|
|
8
8
|
id: schema.string(),
|
|
9
9
|
value: schema.string(),
|
|
10
10
|
});
|
|
11
|
-
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createMessageAction } from
|
|
3
|
-
import { createMessage } from
|
|
4
|
-
import type { AppDependencies } from './dependencies';
|
|
1
|
+
import { handleAction } from "@askrjs/server/askr";
|
|
2
|
+
import { createMessageAction } from "../actions/create-message";
|
|
3
|
+
import { createMessage } from "./actions/create-message";
|
|
5
4
|
|
|
6
|
-
export function
|
|
7
|
-
|
|
8
|
-
csrf: { secret: process.env.CSRF_SECRET ?? 'development-only-secret' },
|
|
9
|
-
});
|
|
10
|
-
registry.register(createMessageAction, createMessage);
|
|
11
|
-
return registry;
|
|
5
|
+
export function createActionHandlers() {
|
|
6
|
+
return [handleAction(createMessageAction, createMessage)] as const;
|
|
12
7
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type { InferSchema } from
|
|
2
|
-
import { createMessageAction } from
|
|
3
|
-
import type { AppDependencies } from
|
|
1
|
+
import type { InferSchema } from "@askrjs/schema";
|
|
2
|
+
import { createMessageAction } from "../../actions/create-message";
|
|
3
|
+
import type { AppDependencies } from "../dependencies";
|
|
4
4
|
|
|
5
5
|
type Input = InferSchema<typeof createMessageAction.input>;
|
|
6
6
|
|
|
7
7
|
export async function createMessage(
|
|
8
8
|
_context: unknown,
|
|
9
9
|
input: Input,
|
|
10
|
-
deps: Pick<AppDependencies,
|
|
10
|
+
deps: Pick<AppDependencies, "actions">,
|
|
11
11
|
) {
|
|
12
12
|
await deps.actions.record({ action: createMessageAction.id, value: input.value });
|
|
13
13
|
return { result: { accepted: true } };
|
|
@@ -1,66 +1,76 @@
|
|
|
1
|
-
import { createAuth } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { createActions } from './action-registry';
|
|
10
|
-
import type { AppDependencies } from './dependencies';
|
|
1
|
+
import { createAuth } from "@askrjs/auth";
|
|
2
|
+
import { createAskrApp } from "@askrjs/server/askr";
|
|
3
|
+
import { csrf, rateLimit, requestId, securityHeaders } from "@askrjs/server/middleware";
|
|
4
|
+
import { pageRegistry } from "../routes";
|
|
5
|
+
import { Message, MessageInput } from "../schemas";
|
|
6
|
+
import { telemetry } from "../telemetry";
|
|
7
|
+
import { createActionHandlers } from "./action-registry";
|
|
8
|
+
import type { AppDependencies } from "./dependencies";
|
|
11
9
|
|
|
12
10
|
export function createApp(deps: AppDependencies) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
return createAskrApp({
|
|
12
|
+
name: "{{appName}}",
|
|
13
|
+
version: "1.0.0",
|
|
14
|
+
dependencies: deps,
|
|
15
|
+
pages: pageRegistry,
|
|
16
|
+
api: {
|
|
17
|
+
define(api) {
|
|
18
|
+
api
|
|
19
|
+
.post("/messages", {
|
|
20
|
+
input: {
|
|
21
|
+
body: {
|
|
22
|
+
schema: MessageInput,
|
|
23
|
+
mediaTypes: ["application/json"],
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
documentation: { body: { required: true } },
|
|
27
|
+
async handler(ctx, input, dependencies) {
|
|
28
|
+
const message = { id: crypto.randomUUID(), value: input.body.value };
|
|
29
|
+
await dependencies.actions.record({
|
|
30
|
+
action: "api.create-message",
|
|
31
|
+
value: message.value,
|
|
32
|
+
});
|
|
33
|
+
return ctx.created(message);
|
|
34
|
+
},
|
|
35
|
+
})
|
|
36
|
+
.operationId("createMessage")
|
|
37
|
+
.summary("Create a message")
|
|
38
|
+
.tags("Messages")
|
|
39
|
+
.use(
|
|
40
|
+
csrf({ secret: process.env.CSRF_SECRET ?? "development-only-secret" }),
|
|
41
|
+
rateLimit({ store: deps.rateLimits, limit: 30, windowMs: 60_000 }),
|
|
42
|
+
)
|
|
43
|
+
.created(Message)
|
|
44
|
+
.badRequest()
|
|
45
|
+
.unprocessableEntity()
|
|
46
|
+
.tooManyRequests();
|
|
47
|
+
api
|
|
48
|
+
.post("/session", (ctx) => {
|
|
49
|
+
const response = ctx.redirect("/", 303);
|
|
50
|
+
return ctx.setCookie(response, "askr-session", "demo-session", {
|
|
51
|
+
httpOnly: true,
|
|
52
|
+
sameSite: "lax",
|
|
53
|
+
secure: ctx.url.protocol === "https:",
|
|
54
|
+
path: "/",
|
|
55
|
+
});
|
|
56
|
+
})
|
|
57
|
+
.operationId("createSession")
|
|
58
|
+
.summary("Create a demo session")
|
|
59
|
+
.seeOther();
|
|
21
60
|
},
|
|
22
61
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
62
|
+
auth: {
|
|
63
|
+
resolver: createAuth({
|
|
64
|
+
sessions: deps.sessions,
|
|
65
|
+
principals: deps.principals,
|
|
66
|
+
sessionCookie: "askr-session",
|
|
67
|
+
}),
|
|
68
|
+
},
|
|
69
|
+
actions: {
|
|
70
|
+
handlers: createActionHandlers(),
|
|
71
|
+
csrf: { secret: process.env.CSRF_SECRET ?? "development-only-secret" },
|
|
28
72
|
},
|
|
29
|
-
})
|
|
30
|
-
.operationId('createMessage')
|
|
31
|
-
.summary('Create a message')
|
|
32
|
-
.tags('Messages')
|
|
33
|
-
.use(
|
|
34
|
-
csrf({ secret: process.env.CSRF_SECRET ?? 'development-only-secret' }),
|
|
35
|
-
rateLimit({ store: deps.rateLimits, limit: 30, windowMs: 60_000 }),
|
|
36
|
-
)
|
|
37
|
-
.created(Message)
|
|
38
|
-
.badRequest()
|
|
39
|
-
.unprocessableEntity()
|
|
40
|
-
.tooManyRequests();
|
|
41
|
-
|
|
42
|
-
const router = api.createRouter(deps);
|
|
43
|
-
router.post('/api/session', (ctx) => {
|
|
44
|
-
const response = ctx.redirect('/', 303);
|
|
45
|
-
return ctx.setCookie(response, 'askr-session', 'demo-session', {
|
|
46
|
-
httpOnly: true,
|
|
47
|
-
sameSite: 'lax',
|
|
48
|
-
secure: ctx.url.protocol === 'https:',
|
|
49
|
-
path: '/',
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
return createServerApp({
|
|
53
|
-
router,
|
|
54
|
-
auth: createAuth({
|
|
55
|
-
sessions: deps.sessions,
|
|
56
|
-
principals: deps.principals,
|
|
57
|
-
sessionCookie: 'askr-session',
|
|
58
|
-
}),
|
|
59
73
|
middleware: [requestId(), securityHeaders()],
|
|
60
74
|
telemetry,
|
|
61
|
-
fallback: createAskrPageHandler({
|
|
62
|
-
registry: pageRegistry,
|
|
63
|
-
actions: createActions(deps),
|
|
64
|
-
}),
|
|
65
75
|
});
|
|
66
76
|
}
|
|
@@ -13,7 +13,11 @@ export interface AppDependencies {
|
|
|
13
13
|
record(entry: { action: string; value: string }): Promise<void>;
|
|
14
14
|
};
|
|
15
15
|
readonly rateLimits: {
|
|
16
|
-
consume(
|
|
16
|
+
consume(
|
|
17
|
+
key: string,
|
|
18
|
+
limit: number,
|
|
19
|
+
windowMs: number,
|
|
20
|
+
): Promise<{
|
|
17
21
|
allowed: boolean;
|
|
18
22
|
remaining: number;
|
|
19
23
|
reset: number;
|
|
@@ -25,23 +29,19 @@ export function createDependencies(): AppDependencies {
|
|
|
25
29
|
const counters = new Map<string, { count: number; reset: number }>();
|
|
26
30
|
return {
|
|
27
31
|
sessions: {
|
|
28
|
-
get: async (id) => id ===
|
|
29
|
-
? { id, subject: 'demo-user' }
|
|
30
|
-
: null,
|
|
32
|
+
get: async (id) => (id === "demo-session" ? { id, subject: "demo-user" } : null),
|
|
31
33
|
},
|
|
32
34
|
principals: {
|
|
33
|
-
get: async (subject) =>
|
|
34
|
-
? { id: subject, subject, permissions: [
|
|
35
|
-
: null,
|
|
35
|
+
get: async (subject) =>
|
|
36
|
+
subject === "demo-user" ? { id: subject, subject, permissions: ["messages:create"] } : null,
|
|
36
37
|
},
|
|
37
38
|
actions: { record: async () => undefined },
|
|
38
39
|
rateLimits: {
|
|
39
40
|
async consume(key, limit, windowMs) {
|
|
40
41
|
const now = Date.now();
|
|
41
42
|
const current = counters.get(key);
|
|
42
|
-
const window =
|
|
43
|
-
? { count: 0, reset: now + windowMs }
|
|
44
|
-
: current;
|
|
43
|
+
const window =
|
|
44
|
+
!current || current.reset <= now ? { count: 0, reset: now + windowMs } : current;
|
|
45
45
|
window.count += 1;
|
|
46
46
|
counters.set(key, window);
|
|
47
47
|
return {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { createApp } from
|
|
2
|
-
import { createDependencies } from
|
|
1
|
+
import { createApp } from "./app";
|
|
2
|
+
import { createDependencies } from "./dependencies";
|
|
3
3
|
|
|
4
4
|
const app = createApp(createDependencies());
|
|
5
5
|
|
|
6
6
|
export { app };
|
|
7
|
-
export { telemetry } from
|
|
7
|
+
export { telemetry } from "../telemetry";
|
|
8
8
|
export default app;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { describe, expect, it } from
|
|
2
|
-
import { createMessageAction } from
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { createMessageAction } from "../../src/actions/create-message";
|
|
3
3
|
|
|
4
|
-
describe(
|
|
5
|
-
it(
|
|
6
|
-
expect(createMessageAction.input.safeParse({ value:
|
|
4
|
+
describe("create message action", () => {
|
|
5
|
+
it("should reject an empty message given declared input validation", () => {
|
|
6
|
+
expect(createMessageAction.input.safeParse({ value: "" }).success).toBe(false);
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
-
it(
|
|
10
|
-
expect(createMessageAction.input.safeParse({ value:
|
|
9
|
+
it("should accept a message given valid input", () => {
|
|
10
|
+
expect(createMessageAction.input.safeParse({ value: "hello" }).success).toBe(true);
|
|
11
11
|
});
|
|
12
12
|
});
|
|
13
|
-
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { defineConfig } from
|
|
2
|
-
import { askr } from
|
|
3
|
-
import { askrServer } from
|
|
1
|
+
import { defineConfig } from "vite-plus";
|
|
2
|
+
import { askr } from "@askrjs/vite";
|
|
3
|
+
import { askrServer } from "@askrjs/vite/server";
|
|
4
4
|
|
|
5
5
|
export default defineConfig({
|
|
6
|
-
plugins: [askr(), askrServer({ entry:
|
|
7
|
-
lint: { ignorePatterns: [
|
|
6
|
+
plugins: [askr(), askrServer({ entry: "./src/server/entry-server.ts" })],
|
|
7
|
+
lint: { ignorePatterns: ["dist/**", "node_modules/**", "coverage/**"] },
|
|
8
8
|
server: { port: 5173, open: true },
|
|
9
9
|
build: { manifest: true, sourcemap: true },
|
|
10
10
|
});
|
|
11
|
-
|
|
@@ -23,7 +23,7 @@ npm run fmt # Prettier
|
|
|
23
23
|
- **Data:** Route/container components own resources; `src/features` owns product workflows; `src/adapters` owns API clients, transports, abort handling, and generated clients.
|
|
24
24
|
- **Consistency:** Event-sourced screens should expose pending writes, projection lag, stale data, retries, and manual refresh instead of hiding everything behind one loading state.
|
|
25
25
|
- **Styling:** Keep `src/styles.css` thin. Customize theme values in `src/styles/tokens.css`, global defaults in `src/styles/theme.css`, shell structure in `src/styles/layout.css`, and component classes in `src/styles/components.css`.
|
|
26
|
-
- **Charts:**
|
|
26
|
+
- **Charts:** Create typed plot namespaces from `@askrjs/charts` at module scope and compose marks inside `Plot.Root`; chart CSS is loaded from `@askrjs/charts/styles`.
|
|
27
27
|
- **Vite plugin:** `askr()` from `@askrjs/vite` handles JSX transform. Do not add manual esbuild JSX config.
|
|
28
28
|
|
|
29
29
|
## File Structure
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"dev": "vp dev",
|
|
8
8
|
"build": "vp build",
|
|
9
9
|
"preview": "vp preview",
|
|
10
|
-
"test": "vp test run",
|
|
10
|
+
"test": "vp test run -c ./vitest.config.ts",
|
|
11
11
|
"typecheck": "tsc --noEmit",
|
|
12
12
|
"lint": "vp lint .",
|
|
13
13
|
"lint:fix": "npm run lint -- --fix",
|
|
@@ -16,15 +16,14 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@askrjs/askr": ">=0.0.53 <0.1.0",
|
|
19
|
-
"@askrjs/charts": ">=0.0
|
|
20
|
-
"@askrjs/logos": ">=0.0.3 <0.1.0",
|
|
19
|
+
"@askrjs/charts": ">=0.1.0 <0.2.0",
|
|
21
20
|
"@askrjs/lucide": ">=0.0.3 <0.1.0",
|
|
22
21
|
"@askrjs/themes": ">=0.0.12 <0.1.0",
|
|
23
22
|
"@askrjs/ui": ">=0.0.13 <0.1.0"
|
|
24
23
|
},
|
|
25
24
|
"devDependencies": {
|
|
26
25
|
"@askrjs/vite": ">=0.0.6 <0.1.0",
|
|
27
|
-
"@types/node": "^
|
|
26
|
+
"@types/node": "^20.19.0",
|
|
28
27
|
"jsdom": "^29.1.1",
|
|
29
28
|
"typescript": "^6.0.3",
|
|
30
29
|
"vite-plus": "^0.2.4"
|
|
@@ -8,13 +8,18 @@ export type OperationRun = {
|
|
|
8
8
|
updatedAt: string;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
export type OperationsChartRow = {
|
|
12
|
+
label: string;
|
|
13
|
+
value: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
11
16
|
export type OperationsSnapshot = {
|
|
12
17
|
version: number;
|
|
13
18
|
consistency: 'fresh' | 'pending-write' | 'stale';
|
|
14
19
|
lastEventId: string;
|
|
15
20
|
metrics: Array<{ label: string; value: string; trend: string }>;
|
|
16
|
-
throughput:
|
|
17
|
-
lag:
|
|
21
|
+
throughput: OperationsChartRow[];
|
|
22
|
+
lag: OperationsChartRow[];
|
|
18
23
|
runs: OperationRun[];
|
|
19
24
|
};
|
|
20
25
|
|
|
@@ -2,8 +2,10 @@ import { route } from '@askrjs/askr/router';
|
|
|
2
2
|
import AgentRunsPage from './agent-runs';
|
|
3
3
|
import AdminHomePage from './admin-home';
|
|
4
4
|
import SettingsPage from './settings';
|
|
5
|
+
// askr:imports
|
|
5
6
|
|
|
6
7
|
export function registerAppRoutes(): void {
|
|
8
|
+
// askr:routes
|
|
7
9
|
route('/app', AdminHomePage);
|
|
8
10
|
route('/app/agents', AgentRunsPage);
|
|
9
11
|
route('/app/settings', SettingsPage);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resource } from '@askrjs/askr/resources';
|
|
2
|
-
import {
|
|
2
|
+
import { createPlot } from '@askrjs/charts';
|
|
3
3
|
import { AlertCircleIcon, RefreshCwIcon } from '@askrjs/lucide';
|
|
4
4
|
import { Button } from '@askrjs/themes/components';
|
|
5
5
|
import {
|
|
@@ -16,9 +16,12 @@ import { Block, Inline, Section, Stack } from '@askrjs/themes/components';
|
|
|
16
16
|
import { EmptyState } from '@askrjs/themes/components';
|
|
17
17
|
import MetricCard from '../../components/shared/metric-card';
|
|
18
18
|
import StatusBadge from '../../components/shared/status-badge';
|
|
19
|
+
import type { OperationsChartRow } from '../../adapters/operations-client';
|
|
19
20
|
import { loadOperations } from '../../features/operations/operations.query';
|
|
20
21
|
import { formatRelativeTime } from '../../shared/format';
|
|
21
22
|
|
|
23
|
+
const OperationsPlot = createPlot<OperationsChartRow>();
|
|
24
|
+
|
|
22
25
|
export default function AdminHomePage() {
|
|
23
26
|
const operations = resource(({ signal }) => loadOperations({ signal }), []);
|
|
24
27
|
const snapshot = operations.value;
|
|
@@ -84,7 +87,14 @@ export default function AdminHomePage() {
|
|
|
84
87
|
</CardDescription>
|
|
85
88
|
</CardHeader>
|
|
86
89
|
<CardContent>
|
|
87
|
-
<
|
|
90
|
+
<OperationsPlot.Root
|
|
91
|
+
data={snapshot.throughput}
|
|
92
|
+
rowKey="label"
|
|
93
|
+
label="Run throughput"
|
|
94
|
+
description="Accepted commands by work type."
|
|
95
|
+
>
|
|
96
|
+
<OperationsPlot.Bar x="label" y="value" />
|
|
97
|
+
</OperationsPlot.Root>
|
|
88
98
|
</CardContent>
|
|
89
99
|
</Card>
|
|
90
100
|
<Card>
|
|
@@ -95,7 +105,15 @@ export default function AdminHomePage() {
|
|
|
95
105
|
</CardDescription>
|
|
96
106
|
</CardHeader>
|
|
97
107
|
<CardContent>
|
|
98
|
-
<
|
|
108
|
+
<OperationsPlot.Root
|
|
109
|
+
data={snapshot.lag}
|
|
110
|
+
rowKey="label"
|
|
111
|
+
label="Projection lag"
|
|
112
|
+
description="Projection lag over the last hour."
|
|
113
|
+
>
|
|
114
|
+
<OperationsPlot.Line x="label" y="value" />
|
|
115
|
+
<OperationsPlot.Point x="label" y="value" />
|
|
116
|
+
</OperationsPlot.Root>
|
|
99
117
|
</CardContent>
|
|
100
118
|
</Card>
|
|
101
119
|
</Block>
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"isolatedModules": true,
|
|
14
14
|
"noEmit": true,
|
|
15
15
|
"jsx": "preserve",
|
|
16
|
-
"jsxImportSource": "@askrjs/askr"
|
|
16
|
+
"jsxImportSource": "@askrjs/askr",
|
|
17
|
+
"types": ["@askrjs/themes"]
|
|
17
18
|
},
|
|
18
19
|
"include": ["src", "tests"],
|
|
19
20
|
"references": [{ "path": "./tsconfig.node.json" }]
|
|
@@ -34,6 +34,6 @@ npm run typecheck # Type check
|
|
|
34
34
|
|
|
35
35
|
## Static generation
|
|
36
36
|
|
|
37
|
-
Run `npm run build` to compile browser assets and pre-render every route into `dist/`. The `askr ssg` command owns both full and incremental generation, and publishes routes, metadata, the incremental manifest,
|
|
37
|
+
Run `npm run build` to compile browser assets and pre-render every route into `dist/`. The `askr ssg` command owns both full and incremental generation, and publishes routes, metadata, the incremental manifest, browser assets, `sitemap.xml`, and the managed `robots.txt` sitemap directive together.
|
|
38
38
|
|
|
39
39
|
`ssg.config.ts` passes the same immutable route registry used in dev mode, so the shell and leaf pages stay in sync.
|
|
@@ -4,6 +4,7 @@ import type { DocumentRenderArgs } from '@askrjs/askr/ssg';
|
|
|
4
4
|
import { pageRegistry } from './src/routes';
|
|
5
5
|
|
|
6
6
|
export const outputDir = './dist';
|
|
7
|
+
export const siteUrl = 'https://example.com';
|
|
7
8
|
|
|
8
9
|
let clientTemplate: string | undefined;
|
|
9
10
|
|
|
@@ -24,6 +25,12 @@ function renderDocument({ appHtml }: DocumentRenderArgs) {
|
|
|
24
25
|
export const staticConfig = {
|
|
25
26
|
registry: pageRegistry,
|
|
26
27
|
outputDir,
|
|
28
|
+
siteUrl,
|
|
29
|
+
sitemap: {
|
|
30
|
+
routes: {
|
|
31
|
+
'/preview': false,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
27
34
|
document: renderDocument,
|
|
28
35
|
assets: [
|
|
29
36
|
{
|
|
@@ -3,9 +3,11 @@ import { staticConfig } from '../ssg.config';
|
|
|
3
3
|
|
|
4
4
|
describe('SSG config', () => {
|
|
5
5
|
it('keeps the sample route tree explicit', () => {
|
|
6
|
-
expect(
|
|
7
|
-
|
|
8
|
-
);
|
|
6
|
+
expect(
|
|
7
|
+
staticConfig.registry.manifest.records.map((route) => route.path).sort()
|
|
8
|
+
).toEqual(['/', '/content', '/preview', '/workflow'].sort());
|
|
9
9
|
expect(staticConfig.registry.routes).toHaveLength(4);
|
|
10
|
+
expect(staticConfig.siteUrl).toBe('https://example.com');
|
|
11
|
+
expect(staticConfig.sitemap.routes['/preview']).toBe(false);
|
|
10
12
|
});
|
|
11
13
|
});
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"isolatedModules": true,
|
|
14
14
|
"noEmit": true,
|
|
15
15
|
"jsx": "react-jsx",
|
|
16
|
-
"jsxImportSource": "@askrjs/askr"
|
|
16
|
+
"jsxImportSource": "@askrjs/askr",
|
|
17
|
+
"types": ["@askrjs/themes"]
|
|
17
18
|
},
|
|
18
19
|
"include": ["src"],
|
|
19
20
|
"references": [{ "path": "./tsconfig.node.json" }]
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"dev": "vp dev",
|
|
7
7
|
"build": "vp build && vp build --ssr server.ts --outDir dist/server",
|
|
8
8
|
"preview": "node dist/server/server.js",
|
|
9
|
-
"test": "vp test run",
|
|
9
|
+
"test": "vp test run -c ./vitest.config.ts",
|
|
10
10
|
"typecheck": "tsc --noEmit",
|
|
11
11
|
"lint": "vp lint src server.ts tests vite.config.ts",
|
|
12
12
|
"lint:fix": "npm run lint -- --fix",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@askrjs/vite": ">=0.0.6 <0.1.0",
|
|
25
|
-
"@types/node": "^
|
|
25
|
+
"@types/node": "^20.19.0",
|
|
26
26
|
"jsdom": "^29.1.1",
|
|
27
27
|
"tsx": "^4.23.1",
|
|
28
28
|
"typescript": "^6.0.3",
|
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { serve } from '@askrjs/node';
|
|
2
2
|
import app from 'virtual:askr-server';
|
|
3
3
|
|
|
4
4
|
const port = Number(process.env.PORT ?? 3000);
|
|
5
|
-
const
|
|
5
|
+
const running = await serve(app, {
|
|
6
6
|
host: process.env.HOST ?? '127.0.0.1',
|
|
7
7
|
port,
|
|
8
|
+
assets: { root: new URL('./dist', import.meta.url).pathname },
|
|
8
9
|
});
|
|
9
|
-
|
|
10
|
-
const boundPort = typeof address === 'object' && address ? address.port : port;
|
|
11
|
-
|
|
12
|
-
console.log(`Server started at http://127.0.0.1:${boundPort}`);
|
|
13
|
-
|
|
14
|
-
const shutdown = () => server.close();
|
|
15
|
-
process.once('SIGINT', shutdown);
|
|
16
|
-
process.once('SIGTERM', shutdown);
|
|
10
|
+
console.log(`Server started at ${running.url}`);
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createAskrPageHandler } from '@askrjs/server/askr';
|
|
1
|
+
import { createAskrApp } from '@askrjs/server/askr';
|
|
3
2
|
import { pageRegistry } from './routes';
|
|
4
3
|
|
|
5
|
-
const app =
|
|
6
|
-
|
|
4
|
+
const app = createAskrApp({
|
|
5
|
+
name: '{{appName}}',
|
|
6
|
+
version: '0.1.0',
|
|
7
|
+
dependencies: undefined,
|
|
8
|
+
pages: pageRegistry,
|
|
7
9
|
});
|
|
8
10
|
|
|
9
11
|
export { app };
|