@jskit-ai/agent-docs 0.1.257 → 0.1.259
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/guide/agent/app-extras/assistant-conversation.md +88 -35
- package/guide/agent/app-extras/assistant.md +28 -28
- package/guide/agent/app-setup/authentication.md +36 -17
- package/guide/agent/app-setup/database-layer.md +116 -17
- package/guide/agent/app-setup/existing-application-migration.md +29 -25
- package/guide/agent/app-setup/multi-homing.md +94 -48
- package/guide/agent/app-setup/run-an-accounts-hub.md +6 -4
- package/guide/agent/framework/client-features.md +496 -0
- package/guide/agent/framework/crud-operations.md +5 -5
- package/guide/agent/framework/translation.md +4 -3
- package/guide/agent/framework/typed-features.md +1104 -0
- package/guide/agent/framework/ui-operations.md +2 -2
- package/guide/agent/index.md +6 -1
- package/package.json +1 -1
- package/patterns/feature-package/PATTERN.md +104 -10
- package/patterns/feature-package/example/booking-engine/package.json +9 -4
- package/patterns/feature-package/example/booking-engine/src/server/BookingEngineFeature.js +24 -0
- package/patterns/feature-package/example/booking-engine/src/server/bookingAvailability.js +10 -0
- package/patterns/feature-package/example/booking-engine/src/server/bookingEngine.js +29 -0
- package/patterns/feature-package/example/booking-engine/src/server/bookingEngineActions.js +26 -0
- package/patterns/feature-package/example/booking-engine/src/server/inputSchemas.js +1 -2
- package/patterns/feature-package/example/booking-engine/src/server/types.js +12 -0
- package/patterns/feature-package/example/variations/AvailabilityEngineFeature.js +19 -0
- package/patterns/feature-package/example/variations/InvoiceRollupFeature.js +23 -0
- package/patterns/feature-package/example/variations/availabilityEngineActions.js +26 -0
- package/patterns/feature-package/example/variations/customKnexRepository.js +32 -26
- package/patterns/feature-package/example/variations/invoiceRollupActions.js +26 -0
- package/patterns/feature-package/example/variations/orchestratorService.js +24 -19
- package/patterns/feature-package/example/variations/types.js +7 -0
- package/patterns/minimal-foundation/PATTERN.md +30 -1
- package/patterns/minimal-foundation/example/AGENTS.md +14 -0
- package/patterns/minimal-foundation/example/bin/develop.js +10 -5
- package/patterns/minimal-foundation/example/eslint.config.mjs +21 -2
- package/patterns/minimal-foundation/example/package.json +5 -4
- package/patterns/minimal-foundation/example/playwright.config.mjs +1 -1
- package/patterns/minimal-foundation/example/server/lib/envFile.js +19 -0
- package/patterns/minimal-foundation/example/server/lib/loggerOptions.js +15 -0
- package/patterns/minimal-foundation/example/server/lib/runtimeEnv.js +17 -17
- package/patterns/minimal-foundation/example/server.js +32 -29
- package/patterns/minimal-foundation/example/tests/server/smoke.test.js +2 -1
- package/patterns/shell-foundation/PATTERN.md +29 -0
- package/patterns/shell-foundation/example/AGENTS.md +14 -0
- package/patterns/shell-foundation/example/bin/develop.js +10 -5
- package/patterns/shell-foundation/example/eslint.config.mjs +21 -2
- package/patterns/shell-foundation/example/package.json +6 -5
- package/patterns/shell-foundation/example/packages/main/package.json +1 -1
- package/patterns/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +1 -0
- package/patterns/shell-foundation/example/playwright.config.mjs +1 -1
- package/patterns/shell-foundation/example/server/lib/envFile.js +19 -0
- package/patterns/shell-foundation/example/server/lib/loggerOptions.js +15 -0
- package/patterns/shell-foundation/example/server/lib/runtimeEnv.js +17 -17
- package/patterns/shell-foundation/example/server.js +32 -29
- package/patterns/shell-foundation/example/tests/server/smoke.test.js +2 -1
- package/reference/autogen/KERNEL_MAP.md +14 -8
- package/reference/autogen/PATTERN_INDEX.md +37 -37
- package/reference/autogen/README.md +2 -0
- package/reference/autogen/packages/agent-docs.md +70 -26
- package/reference/autogen/packages/agent-runtime.md +129 -0
- package/reference/autogen/packages/agent.md +149 -0
- package/reference/autogen/packages/architecture-inspector.md +97 -44
- package/reference/autogen/packages/assistant-core.md +786 -292
- package/reference/autogen/packages/assistant-runtime.md +182 -57
- package/reference/autogen/packages/assistant-voice-sherpa.md +4 -0
- package/reference/autogen/packages/assistant-voice.md +54 -8
- package/reference/autogen/packages/auth-core.md +44 -13
- package/reference/autogen/packages/auth-provider-local-core.md +86 -34
- package/reference/autogen/packages/auth-provider-local-db-core.md +1 -2
- package/reference/autogen/packages/auth-provider-oidc-core.md +10 -4
- package/reference/autogen/packages/auth-provider-supabase-core.md +52 -66
- package/reference/autogen/packages/auth-web.md +19 -11
- package/reference/autogen/packages/connectors-catalog.md +71 -43
- package/reference/autogen/packages/connectors-core.md +42 -4
- package/reference/autogen/packages/console-core.md +27 -14
- package/reference/autogen/packages/crud-core.md +178 -170
- package/reference/autogen/packages/database-runtime-mysql.md +0 -2
- package/reference/autogen/packages/database-runtime-postgres.md +0 -2
- package/reference/autogen/packages/database-runtime.md +39 -10
- package/reference/autogen/packages/http-runtime.md +79 -57
- package/reference/autogen/packages/json-rest-api-core.md +11 -8
- package/reference/autogen/packages/kernel.md +144 -83
- package/reference/autogen/packages/oidc-issuer-core.md +49 -20
- package/reference/autogen/packages/payments-core.md +20 -3
- package/reference/autogen/packages/realtime.md +47 -22
- package/reference/autogen/packages/resource-core.md +1 -1
- package/reference/autogen/packages/resource-crud-core.md +64 -26
- package/reference/autogen/packages/rewarded-core.md +47 -36
- package/reference/autogen/packages/shell-web.md +7 -10
- package/reference/autogen/packages/storage-runtime.md +6 -2
- package/reference/autogen/packages/uploads-runtime.md +10 -2
- package/reference/autogen/packages/users-core.md +73 -71
- package/reference/autogen/packages/workspaces-core.md +121 -106
- package/reference/autogen/packages/workspaces-web.md +1 -2
- package/reference/autogen/tooling/config-eslint.md +302 -0
- package/reference/autogen/tooling/jskit-catalog.md +28 -18
- package/reference/autogen/tooling/jskit-release.md +35 -20
- package/reference/autogen/tooling/testUtils.md +3 -1
- package/skills/jskit/SKILL.md +9 -8
- package/skills/jskit/references/app-operations.md +1 -1
- package/skills/jskit/references/client-features.md +491 -0
- package/skills/jskit/references/crud-form-actions.md +1 -1
- package/skills/jskit/references/crud-operations.md +7 -7
- package/skills/jskit/references/existing-application-migration.md +31 -27
- package/skills/jskit/references/heuristics/INDEX.md +5 -1
- package/skills/jskit/references/heuristics/child-cruds.md +1 -1
- package/skills/jskit/references/heuristics/client-features.md +66 -0
- package/skills/jskit/references/heuristics/client-requests.md +1 -1
- package/skills/jskit/references/heuristics/crud-authoring.md +12 -2
- package/skills/jskit/references/heuristics/crud-links.md +1 -1
- package/skills/jskit/references/heuristics/crud-repository-mapping.md +3 -3
- package/skills/jskit/references/heuristics/filters.md +1 -1
- package/skills/jskit/references/heuristics/live-actions.md +1 -1
- package/skills/jskit/references/heuristics/page-redirects.md +1 -1
- package/skills/jskit/references/heuristics/page-scaffolding.md +1 -1
- package/skills/jskit/references/heuristics/placements.md +1 -1
- package/skills/jskit/references/heuristics/row-policies.md +1 -1
- package/skills/jskit/references/heuristics/server-search.md +1 -1
- package/skills/jskit/references/heuristics/surfaces.md +1 -1
- package/skills/jskit/references/heuristics/typed-features.md +100 -0
- package/skills/jskit/references/heuristics/ui-contract.md +1 -1
- package/skills/jskit/references/heuristics/ui-testing.md +4 -4
- package/skills/jskit/references/material-3.md +2 -2
- package/skills/jskit/references/multi-homing.md +96 -50
- package/skills/jskit/references/pattern-index.md +37 -37
- package/skills/jskit/references/patterns/app/minimal-foundation/PATTERN.md +30 -1
- package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +14 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/bin/develop.js +10 -5
- package/skills/jskit/references/patterns/app/minimal-foundation/example/eslint.config.mjs +21 -2
- package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +5 -4
- package/skills/jskit/references/patterns/app/minimal-foundation/example/playwright.config.mjs +1 -1
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/envFile.js +19 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/loggerOptions.js +15 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/runtimeEnv.js +17 -17
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server.js +32 -29
- package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/server/smoke.test.js +2 -1
- package/skills/jskit/references/patterns/app/shell-foundation/PATTERN.md +29 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +14 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/bin/develop.js +10 -5
- package/skills/jskit/references/patterns/app/shell-foundation/example/eslint.config.mjs +21 -2
- package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +6 -5
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +1 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/playwright.config.mjs +1 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/envFile.js +19 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/loggerOptions.js +15 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/runtimeEnv.js +17 -17
- package/skills/jskit/references/patterns/app/shell-foundation/example/server.js +32 -29
- package/skills/jskit/references/patterns/app/shell-foundation/example/tests/server/smoke.test.js +2 -1
- package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/ApplicationAiFeature.js +4 -2
- package/skills/jskit/references/patterns/auth/accounts-hub/PATTERN.md +2 -1
- package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +2 -2
- package/skills/jskit/references/patterns/auth/accounts-hub/example/server/hubPaths.js +9 -3
- package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +25 -12
- package/skills/jskit/references/patterns/auth/auth-surface/example/tools/preview-identity +7 -1
- package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +2 -2
- package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
- package/skills/jskit/references/patterns/connectors/ai-connections/PATTERN.md +16 -1
- package/skills/jskit/references/patterns/connectors/ai-connections/example/ai-model.js +12 -3
- package/skills/jskit/references/patterns/connectors/ai-connections/example/perplexity-answer.js +15 -4
- package/skills/jskit/references/patterns/connectors/api-key-connection/PATTERN.md +9 -1
- package/skills/jskit/references/patterns/connectors/api-key-connection/example/connections.js +5 -2
- package/skills/jskit/references/patterns/connectors/aws-storage-queries/PATTERN.md +13 -3
- package/skills/jskit/references/patterns/connectors/aws-storage-queries/example/s3-transfer.js +14 -3
- package/skills/jskit/references/patterns/connectors/calendar-cli/PATTERN.md +8 -0
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/knexfile.js +1 -1
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/scripts/calendar.js +8 -4
- package/skills/jskit/references/patterns/connectors/event-delivery/PATTERN.md +1 -1
- package/skills/jskit/references/patterns/connectors/firebase-messaging/PATTERN.md +10 -0
- package/skills/jskit/references/patterns/connectors/firebase-messaging/example/server/notifications.js +8 -0
- package/skills/jskit/references/patterns/connectors/google-ads-search/PATTERN.md +18 -7
- package/skills/jskit/references/patterns/connectors/google-ads-search/example/ads-setup.js +13 -5
- package/skills/jskit/references/patterns/connectors/oauth-connection/PATTERN.md +1 -1
- package/skills/jskit/references/patterns/connectors/paddle-catalogue/PATTERN.md +11 -2
- package/skills/jskit/references/patterns/connectors/paddle-catalogue/example/create-products.js +5 -2
- package/skills/jskit/references/patterns/connectors/public-image/PATTERN.md +10 -1
- package/skills/jskit/references/patterns/connectors/public-image/example/logo-url.js +4 -1
- package/skills/jskit/references/patterns/connectors/redshift-queries/PATTERN.md +1 -1
- package/skills/jskit/references/patterns/connectors/source-scanning/PATTERN.md +13 -2
- package/skills/jskit/references/patterns/connectors/source-scanning/example/source-scanner.js +9 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/PATTERN.md +102 -23
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +3 -2
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/server/types.js +5 -0
- package/skills/jskit/references/patterns/crud/resource-contract/PATTERN.md +54 -1
- package/skills/jskit/references/patterns/database/mysql-application/PATTERN.md +16 -5
- package/skills/jskit/references/patterns/database/mysql-application/example/knexfile.js +2 -2
- package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/database/mysql-application/example/scripts/prepare-database.js +1 -1
- package/skills/jskit/references/patterns/database/postgres-application/PATTERN.md +16 -5
- package/skills/jskit/references/patterns/database/postgres-application/example/knexfile.js +2 -2
- package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/database/postgres-application/example/scripts/prepare-database.js +1 -1
- package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
- package/skills/jskit/references/patterns/rewards/google-rewarded/example/GoogleRewardedDeliveryProvider.js +1 -1
- package/skills/jskit/references/patterns/rewards/google-rewarded/example/googlePublisherTag.js +5 -11
- package/skills/jskit/references/patterns/server/feature-package/PATTERN.md +104 -10
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +9 -4
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineFeature.js +24 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingAvailability.js +10 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingEngine.js +29 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingEngineActions.js +26 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/inputSchemas.js +1 -2
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/types.js +12 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineFeature.js +19 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupFeature.js +23 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/availabilityEngineActions.js +26 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/customKnexRepository.js +32 -26
- package/skills/jskit/references/patterns/server/feature-package/example/variations/invoiceRollupActions.js +26 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/orchestratorService.js +24 -19
- package/skills/jskit/references/patterns/server/feature-package/example/variations/types.js +7 -0
- package/skills/jskit/references/patterns/users/user-administration-server/PATTERN.md +16 -1
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +3 -2
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/server/types.js +5 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +4 -3
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/UsersWorkspaceFeature.js +2 -9
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/types.js +5 -0
- package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +42 -17
- package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/WorkspaceInvitationsFeature.js +27 -0
- package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteEmail.js +11 -10
- package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteMailer.js +27 -0
- package/skills/jskit/references/translation.md +5 -4
- package/skills/jskit/references/typed-features.md +1099 -0
- package/skills/jskit/references/ui-operations.md +3 -3
- package/patterns/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +0 -33
- package/patterns/feature-package/example/booking-engine/src/server/actions.js +0 -24
- package/patterns/feature-package/example/variations/AvailabilityEngineProvider.js +0 -31
- package/patterns/feature-package/example/variations/InvoiceRollupProvider.js +0 -36
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +0 -33
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/actions.js +0 -24
- package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineProvider.js +0 -31
- package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupProvider.js +0 -36
|
@@ -2,6 +2,7 @@ import Fastify from "fastify";
|
|
|
2
2
|
import SerializerSelector from "@fastify/fast-json-stringify-compiler";
|
|
3
3
|
import { createCachedResponseSerializerFactory } from "@jskit-ai/kernel/server/http";
|
|
4
4
|
import fastifyStatic from "@fastify/static";
|
|
5
|
+
import { buildLoggerOptions } from "./server/lib/loggerOptions.js";
|
|
5
6
|
import { resolveRuntimeEnv } from "./server/lib/runtimeEnv.js";
|
|
6
7
|
import { existsSync, readFileSync } from "node:fs";
|
|
7
8
|
import path from "node:path";
|
|
@@ -11,11 +12,17 @@ import {
|
|
|
11
12
|
resolveRuntimeProfileFromSurface
|
|
12
13
|
} from "@jskit-ai/kernel/server/platform";
|
|
13
14
|
import { loadAppConfigFromAppRoot } from "@jskit-ai/kernel/server/support";
|
|
14
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
API_BASE_PATH,
|
|
17
|
+
matchesPathPrefix,
|
|
18
|
+
normalizePathname,
|
|
19
|
+
toRequestPathname
|
|
20
|
+
} from "@jskit-ai/kernel/shared/surface/paths";
|
|
15
21
|
import { surfaceRuntime } from "./server/lib/surfaceRuntime.js";
|
|
16
22
|
|
|
23
|
+
/** @typedef {import("@jskit-ai/kernel/server/types").RuntimeEnv} RuntimeEnv */
|
|
24
|
+
|
|
17
25
|
const SPA_INDEX_FILE = "index.html";
|
|
18
|
-
const API_BASE_PATH = "/api";
|
|
19
26
|
const STATIC_GLOBAL_UI_PATHS = Object.freeze([
|
|
20
27
|
"/assets",
|
|
21
28
|
"/favicon.svg",
|
|
@@ -24,15 +31,6 @@ const STATIC_GLOBAL_UI_PATHS = Object.freeze([
|
|
|
24
31
|
"/manifest.webmanifest"
|
|
25
32
|
]);
|
|
26
33
|
|
|
27
|
-
function toRequestPathname(urlValue) {
|
|
28
|
-
const rawUrl = String(urlValue || "").trim() || "/";
|
|
29
|
-
try {
|
|
30
|
-
return normalizePathname(new URL(rawUrl, "http://localhost").pathname || "/");
|
|
31
|
-
} catch {
|
|
32
|
-
return normalizePathname(rawUrl.split("?")[0] || "/");
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
34
|
function isApiPath(pathname) {
|
|
37
35
|
return matchesPathPrefix(pathname, API_BASE_PATH);
|
|
38
36
|
}
|
|
@@ -41,15 +39,15 @@ function hasFileExtension(pathname) {
|
|
|
41
39
|
return path.extname(normalizePathname(pathname)) !== "";
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
function
|
|
45
|
-
const paths = new Set(
|
|
42
|
+
function buildGlobalUiPaths(runtimeGlobalUiPaths) {
|
|
43
|
+
const paths = new Set(runtimeGlobalUiPaths);
|
|
46
44
|
for (const staticPath of STATIC_GLOBAL_UI_PATHS) {
|
|
47
45
|
paths.add(staticPath);
|
|
48
46
|
}
|
|
49
47
|
return [...paths];
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
function
|
|
50
|
+
function toStaticFilePath(pathname) {
|
|
53
51
|
const normalizedPathname = normalizePathname(pathname);
|
|
54
52
|
|
|
55
53
|
const relativePath = normalizedPathname.replace(/^\/+/, "");
|
|
@@ -85,9 +83,13 @@ function canServeStaticFile(distRoot, relativePath) {
|
|
|
85
83
|
return existsSync(resolvedPath);
|
|
86
84
|
}
|
|
87
85
|
|
|
88
|
-
|
|
86
|
+
/**
|
|
87
|
+
* The application's Fastify server with its installed JSKIT runtime, for the environment given.
|
|
88
|
+
* @param {{ runtimeEnv: RuntimeEnv }} settings
|
|
89
|
+
*/
|
|
90
|
+
async function createServer({ runtimeEnv }) {
|
|
89
91
|
const app = Fastify({
|
|
90
|
-
logger:
|
|
92
|
+
logger: buildLoggerOptions(),
|
|
91
93
|
schemaController: {
|
|
92
94
|
compilersFactory: {
|
|
93
95
|
buildSerializer: createCachedResponseSerializerFactory(SerializerSelector())
|
|
@@ -126,7 +128,7 @@ async function createServer({ runtimeEnv = resolveRuntimeEnv() } = {}) {
|
|
|
126
128
|
fastify: app,
|
|
127
129
|
surfaceRuntime,
|
|
128
130
|
serverSurface: runtimeEnv.SERVER_SURFACE,
|
|
129
|
-
globalUiPaths:
|
|
131
|
+
globalUiPaths: buildGlobalUiPaths(runtime.globalUiPaths)
|
|
130
132
|
});
|
|
131
133
|
|
|
132
134
|
if (hasWebBuild) {
|
|
@@ -140,10 +142,8 @@ async function createServer({ runtimeEnv = resolveRuntimeEnv() } = {}) {
|
|
|
140
142
|
}
|
|
141
143
|
|
|
142
144
|
app.setNotFoundHandler(async (request, reply) => {
|
|
143
|
-
const pathname = toRequestPathname(request
|
|
144
|
-
const method =
|
|
145
|
-
.trim()
|
|
146
|
-
.toUpperCase();
|
|
145
|
+
const pathname = toRequestPathname(request.url);
|
|
146
|
+
const method = request.method;
|
|
147
147
|
if (isApiPath(pathname) || (method !== "GET" && method !== "HEAD")) {
|
|
148
148
|
return reply.code(404).send({
|
|
149
149
|
message: `Route ${method}:${pathname} not found`,
|
|
@@ -152,7 +152,7 @@ async function createServer({ runtimeEnv = resolveRuntimeEnv() } = {}) {
|
|
|
152
152
|
});
|
|
153
153
|
}
|
|
154
154
|
if (hasFileExtension(pathname)) {
|
|
155
|
-
const staticFilePath =
|
|
155
|
+
const staticFilePath = toStaticFilePath(pathname);
|
|
156
156
|
if (hasWebBuild && staticFilePath && canServeStaticFile(distRoot, staticFilePath)) {
|
|
157
157
|
return reply.sendFile(staticFilePath);
|
|
158
158
|
}
|
|
@@ -183,19 +183,22 @@ async function createServer({ runtimeEnv = resolveRuntimeEnv() } = {}) {
|
|
|
183
183
|
return app;
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Starts the server on the host and port given, else on the environment's HOST and PORT.
|
|
188
|
+
* @param {{ host?: string, port?: number }} [options]
|
|
189
|
+
*/
|
|
190
|
+
async function startServer({ host, port } = {}) {
|
|
187
191
|
const runtimeEnv = resolveRuntimeEnv();
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
const host = String(options?.host || "").trim() || runtimeEnv.HOST;
|
|
192
|
+
const listenHost = host || runtimeEnv.HOST;
|
|
193
|
+
const listenPort = port ?? Number(runtimeEnv.PORT);
|
|
191
194
|
const app = await createServer({
|
|
192
195
|
runtimeEnv: {
|
|
193
196
|
...runtimeEnv,
|
|
194
|
-
HOST:
|
|
195
|
-
PORT:
|
|
197
|
+
HOST: listenHost,
|
|
198
|
+
PORT: String(listenPort)
|
|
196
199
|
}
|
|
197
200
|
});
|
|
198
|
-
await app.listen({ port, host });
|
|
201
|
+
await app.listen({ port: listenPort, host: listenHost });
|
|
199
202
|
return app;
|
|
200
203
|
}
|
|
201
204
|
|
package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/server/smoke.test.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import test from "node:test";
|
|
3
3
|
import { createServer } from "../../server.js";
|
|
4
|
+
import { resolveRuntimeEnv } from "../../server/lib/runtimeEnv.js";
|
|
4
5
|
|
|
5
6
|
test("GET /api/health returns built-in health response", async () => {
|
|
6
|
-
const app = await createServer();
|
|
7
|
+
const app = await createServer({ runtimeEnv: resolveRuntimeEnv() });
|
|
7
8
|
const response = await app.inject({
|
|
8
9
|
method: "GET",
|
|
9
10
|
url: "/api/health"
|
|
@@ -59,6 +59,33 @@ not convert those choices into a generator questionnaire.
|
|
|
59
59
|
scrims or coordinates.
|
|
60
60
|
- Do not attach generator provenance, receipts, completion state, or replay
|
|
61
61
|
history to copied source.
|
|
62
|
+
- Server code the application adds follows
|
|
63
|
+
[typed features](https://github.com/mobily-enterprises/jskit-ai/blob/main/packages/agent-docs/site/guide/framework/typed-features.md):
|
|
64
|
+
a provided capability exports its type from `types.js`; collaborators arrive
|
|
65
|
+
through declared capabilities, typed in a JSDoc `@param` and required, never
|
|
66
|
+
probed or defaulted to nothing; slots are `optional` tokens with a named
|
|
67
|
+
default; one `create<Name>Actions({ <api> })` per feature returns frozen
|
|
68
|
+
actions whose `execute` is one call; every `create*` returns a frozen object
|
|
69
|
+
of named functions; one copy of each helper per package; files stay under
|
|
70
|
+
750 lines and functions under 600. `createServer({ runtimeEnv })` requires
|
|
71
|
+
the environment it runs with, typed as the kernel's `RuntimeEnv` (the process
|
|
72
|
+
environment, string values: `resolveRuntimeEnv()` keeps `PORT` a string), and
|
|
73
|
+
`server.js` takes `API_BASE_PATH` and `toRequestPathname` from the kernel's
|
|
74
|
+
`shared/surface/paths`. `server/lib/envFile.js` loads `.env` once per process
|
|
75
|
+
for every entry point. `server/lib/loggerOptions.js` gives Fastify's logger
|
|
76
|
+
pino's error serializer under `error` as well as `err`, so
|
|
77
|
+
`logger.error({ error }, "...")` keeps the error's message and stack. `eslint.config.mjs` holds
|
|
78
|
+
server and shared code to every typed-features rule (`typedFeaturesConfig`),
|
|
79
|
+
client code (`src/**` and `packages/*/src/client/**`, Vue components
|
|
80
|
+
included) to the client rules (`clientFeaturesConfig`), all hand-written
|
|
81
|
+
code to the size limits (`sizeLimitsConfig`), and server, config and script
|
|
82
|
+
code to the formatter (`formatterConfig`), all as errors, so `npm run lint`
|
|
83
|
+
reports code that breaks the
|
|
84
|
+
[typed features guide](https://mobily-enterprises.github.io/jskit-ai/guide/framework/typed-features)
|
|
85
|
+
or the
|
|
86
|
+
[client features guide](https://mobily-enterprises.github.io/jskit-ai/guide/framework/client-features).
|
|
87
|
+
Client code the application adds keeps simple, direct code first, and types
|
|
88
|
+
each provider hook with `@jskit-ai/kernel/client/types`.
|
|
62
89
|
|
|
63
90
|
## Framework APIs
|
|
64
91
|
|
|
@@ -126,3 +153,5 @@ horizontal overflow.
|
|
|
126
153
|
- Do not push content down with persistent transient-error banners; use the
|
|
127
154
|
standard toast/error presentation.
|
|
128
155
|
- Do not preserve historical template ownership after copying.
|
|
156
|
+
- Do not probe a collaborator, default one to `null`, `{}` or a no-op, fill a
|
|
157
|
+
slot with a setter after construction, or keep a module-level registry.
|
|
@@ -8,6 +8,20 @@ Framework references:
|
|
|
8
8
|
- `https://mobily-enterprises.github.io/jskit-ai/guide/`
|
|
9
9
|
- `https://mobily-enterprises.github.io/jskit-ai/patterns/`
|
|
10
10
|
|
|
11
|
+
Before writing or reviewing server code (a feature, provider, action, service,
|
|
12
|
+
repository, route, error or test), read the typed features guide at
|
|
13
|
+
`https://mobily-enterprises.github.io/jskit-ai/guide/framework/typed-features`.
|
|
14
|
+
`npm run lint` checks its rules, and each finding links the section that
|
|
15
|
+
explains it; `npm run verify` adds the package graph, tests and build. Fix a
|
|
16
|
+
finding in the code; excuse one only with the guide's `readable-check: allow`
|
|
17
|
+
comment and reason prefix.
|
|
18
|
+
|
|
19
|
+
Before writing or reviewing client code (a composable, component, client
|
|
20
|
+
factory or client provider), read the client features guide at
|
|
21
|
+
`https://mobily-enterprises.github.io/jskit-ai/guide/framework/client-features`.
|
|
22
|
+
Simple, direct code comes first: never add a layer, wrapper, registry or tiny
|
|
23
|
+
module only to satisfy a rule. `npm run lint` checks its rules too.
|
|
24
|
+
|
|
11
25
|
Before implementation, read the narrow relevant source pattern completely. If
|
|
12
26
|
its owner package is installed, prefer that version-matched package-owned copy.
|
|
13
27
|
Do not install an unrelated runtime package only to read documentation.
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { startServer } from "../server.js";
|
|
3
|
+
import { DEFAULT_PORT } from "../server/lib/runtimeEnv.js";
|
|
3
4
|
|
|
4
5
|
const LOOPBACK_HOST = "127.0.0.1";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* The development port a value names; anything that is not a TCP port stops the launcher.
|
|
9
|
+
* @param {string} value
|
|
10
|
+
*/
|
|
11
|
+
function requiredPort(value) {
|
|
12
|
+
const normalized = value.trim();
|
|
13
|
+
const parsed = Number.parseInt(normalized, 10);
|
|
9
14
|
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65_535) {
|
|
10
15
|
throw new Error(`Invalid development port: ${normalized || "(empty)"}.`);
|
|
11
16
|
}
|
|
@@ -20,7 +25,7 @@ function waitForChild(child) {
|
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
const previewHost = String(process.env.HOST || "").trim() || "0.0.0.0";
|
|
23
|
-
const previewPort = requiredPort(process.env.PORT);
|
|
28
|
+
const previewPort = requiredPort(process.env.PORT || String(DEFAULT_PORT));
|
|
24
29
|
let apiServer = null;
|
|
25
30
|
let viteProcess = null;
|
|
26
31
|
let requestedSignal = "";
|
|
@@ -37,7 +42,7 @@ process.once("SIGTERM", () => requestShutdown("SIGTERM"));
|
|
|
37
42
|
|
|
38
43
|
try {
|
|
39
44
|
apiServer = await startServer({ host: LOOPBACK_HOST, port: 0 });
|
|
40
|
-
const apiPort =
|
|
45
|
+
const apiPort = /** @type {import("node:net").AddressInfo} */ (apiServer.server.address()).port;
|
|
41
46
|
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
42
47
|
viteProcess = spawn(
|
|
43
48
|
npmCommand,
|
|
@@ -1,4 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
baseConfig,
|
|
3
|
+
clientFeaturesConfig,
|
|
4
|
+
formatterConfig,
|
|
5
|
+
nodeConfig,
|
|
6
|
+
sizeLimitsConfig,
|
|
7
|
+
typedFeaturesConfig,
|
|
8
|
+
vueConfig,
|
|
9
|
+
webConfig
|
|
10
|
+
} from "@jskit-ai/config-eslint/server";
|
|
11
|
+
|
|
12
|
+
// The checks of https://mobily-enterprises.github.io/jskit-ai/guide/framework/typed-features and
|
|
13
|
+
// https://mobily-enterprises.github.io/jskit-ai/guide/framework/client-features, as errors.
|
|
14
|
+
const SERVER_SOURCES = ["packages/*/src/server/**", "packages/*/src/shared/**", "server/**", "server.js"];
|
|
15
|
+
const CLIENT_SOURCES = ["packages/*/src/client/**", "src/**"];
|
|
16
|
+
const HAND_WRITTEN_SOURCES = ["packages/*/src/**", "src/**", "config/**", "server/**", "server.js", "bin/**"];
|
|
2
17
|
|
|
3
18
|
export default [
|
|
4
19
|
{
|
|
@@ -13,7 +28,11 @@ export default [
|
|
|
13
28
|
}
|
|
14
29
|
},
|
|
15
30
|
...baseConfig,
|
|
31
|
+
...typedFeaturesConfig(SERVER_SOURCES),
|
|
32
|
+
...sizeLimitsConfig(HAND_WRITTEN_SOURCES),
|
|
16
33
|
...vueConfig,
|
|
34
|
+
...clientFeaturesConfig(CLIENT_SOURCES),
|
|
17
35
|
...webConfig,
|
|
18
|
-
...nodeConfig
|
|
36
|
+
...nodeConfig,
|
|
37
|
+
...formatterConfig([...SERVER_SOURCES, "config/**", "bin/**"])
|
|
19
38
|
];
|
|
@@ -34,23 +34,24 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@local/main": "0.1.0",
|
|
36
36
|
"@fastify/static": "^10.1.3",
|
|
37
|
-
"@jskit-ai/kernel": "0.2.
|
|
37
|
+
"@jskit-ai/kernel": "0.2.4",
|
|
38
38
|
"@tanstack/vue-query": "^5.101.0",
|
|
39
39
|
"fastify": "^5.8.5",
|
|
40
|
+
"pino": "^10.3.1",
|
|
40
41
|
"json-rest-schema": "^1.0.17",
|
|
41
42
|
"pinia": "^4.0.3",
|
|
42
43
|
"vue": "^3.5.44",
|
|
43
44
|
"vue-router": "^5.3.1",
|
|
44
45
|
"vuetify": "^4.1.2",
|
|
45
|
-
"@jskit-ai/http-runtime": "0.2.
|
|
46
|
+
"@jskit-ai/http-runtime": "0.2.4",
|
|
46
47
|
"@mdi/js": "^7.4.47",
|
|
47
|
-
"@jskit-ai/shell-web": "0.2.
|
|
48
|
+
"@jskit-ai/shell-web": "0.2.4",
|
|
48
49
|
"@fastify/fast-json-stringify-compiler": "^5.1.0",
|
|
49
50
|
"@vue/devtools-api": "^8.2.1"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
|
-
"@jskit-ai/config-eslint": "0.1.
|
|
53
|
-
"@jskit-ai/jskit-catalog": "0.2.
|
|
53
|
+
"@jskit-ai/config-eslint": "0.1.242",
|
|
54
|
+
"@jskit-ai/jskit-catalog": "0.2.11",
|
|
54
55
|
"@playwright/test": "1.61.1",
|
|
55
56
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
56
57
|
"eslint": "^10.8.0",
|
|
@@ -8,6 +8,7 @@ const MainClientProvider = defineProvider({
|
|
|
8
8
|
requires: {
|
|
9
9
|
components: "client.components"
|
|
10
10
|
},
|
|
11
|
+
/** @param {{ components: import("@jskit-ai/kernel/client/types").ClientComponents }} capabilities */
|
|
11
12
|
setup({ components }) {
|
|
12
13
|
components.register("local.main.ui.menu-link-item", MenuLinkItem);
|
|
13
14
|
components.register("local.main.ui.surface-aware-menu-link-item", SurfaceAwareMenuLinkItem);
|
|
@@ -4,7 +4,7 @@ const managedBaseUrl = String(process.env.PLAYWRIGHT_BASE_URL || "")
|
|
|
4
4
|
.trim()
|
|
5
5
|
.replace(/\/+$/u, "");
|
|
6
6
|
const baseURL = managedBaseUrl || "http://127.0.0.1:4173";
|
|
7
|
-
const storageState = String(process.env.
|
|
7
|
+
const storageState = String(process.env.PLAYWRIGHT_STORAGE_STATE || "").trim();
|
|
8
8
|
|
|
9
9
|
export default defineConfig({
|
|
10
10
|
testDir: "./tests/e2e",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// .env is loaded into process.env, which every caller shares, at most once per process.
|
|
2
|
+
let loaded = false;
|
|
3
|
+
|
|
4
|
+
/** Loads .env into process.env once per process; a missing file is not an error. */
|
|
5
|
+
function loadEnvFile() {
|
|
6
|
+
if (loaded) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
process.loadEnvFile(".env");
|
|
11
|
+
} catch (error) {
|
|
12
|
+
if (error.code !== "ENOENT") {
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
loaded = true;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { loadEnvFile };
|
package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/loggerOptions.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import pino from "pino";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The Fastify logger's options. Fastify's logger serializes only the `err` key, so the same serializer under `error`
|
|
5
|
+
* keeps the message and stack of `logger.error({ error }, "...")`.
|
|
6
|
+
*/
|
|
7
|
+
function buildLoggerOptions() {
|
|
8
|
+
return {
|
|
9
|
+
serializers: {
|
|
10
|
+
error: pino.stdSerializers.err
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { buildLoggerOptions };
|
package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/runtimeEnv.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loadEnvFile } from "./envFile.js";
|
|
2
2
|
import { surfaceRuntime } from "./surfaceRuntime.js";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const DEFAULT_PORT = 3000;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The port a value names, else the fallback.
|
|
8
|
+
* @param {string | undefined} value
|
|
9
|
+
* @param {number} fallback
|
|
10
|
+
*/
|
|
11
|
+
function toPort(value, fallback) {
|
|
5
12
|
const parsed = Number.parseInt(String(value || "").trim(), 10);
|
|
6
13
|
if (Number.isInteger(parsed) && parsed > 0) {
|
|
7
14
|
return parsed;
|
|
@@ -9,29 +16,22 @@ function toPort(value, fallback = 3000) {
|
|
|
9
16
|
return fallback;
|
|
10
17
|
}
|
|
11
18
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
if (existsSync(".env")) {
|
|
19
|
-
process.loadEnvFile(".env");
|
|
20
|
-
}
|
|
21
|
-
envLoaded = true;
|
|
22
|
-
}
|
|
23
|
-
|
|
19
|
+
/**
|
|
20
|
+
* The process environment, with .env loaded and SERVER_SURFACE, PORT and HOST resolved. Every value stays a string,
|
|
21
|
+
* as the kernel's RuntimeEnv type says.
|
|
22
|
+
* @returns {import("@jskit-ai/kernel/server/types").RuntimeEnv}
|
|
23
|
+
*/
|
|
24
24
|
function resolveRuntimeEnv() {
|
|
25
|
-
|
|
25
|
+
loadEnvFile();
|
|
26
26
|
const serverSurface = surfaceRuntime.normalizeSurfaceMode(
|
|
27
27
|
process.env.JSKIT_SERVER_SURFACE || process.env.SERVER_SURFACE
|
|
28
28
|
);
|
|
29
29
|
return {
|
|
30
30
|
...process.env,
|
|
31
31
|
SERVER_SURFACE: serverSurface,
|
|
32
|
-
PORT: toPort(process.env.PORT,
|
|
32
|
+
PORT: String(toPort(process.env.PORT, DEFAULT_PORT)),
|
|
33
33
|
HOST: String(process.env.HOST || "").trim() || "0.0.0.0"
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export { resolveRuntimeEnv };
|
|
37
|
+
export { DEFAULT_PORT, resolveRuntimeEnv };
|
|
@@ -2,6 +2,7 @@ import Fastify from "fastify";
|
|
|
2
2
|
import SerializerSelector from "@fastify/fast-json-stringify-compiler";
|
|
3
3
|
import { createCachedResponseSerializerFactory } from "@jskit-ai/kernel/server/http";
|
|
4
4
|
import fastifyStatic from "@fastify/static";
|
|
5
|
+
import { buildLoggerOptions } from "./server/lib/loggerOptions.js";
|
|
5
6
|
import { resolveRuntimeEnv } from "./server/lib/runtimeEnv.js";
|
|
6
7
|
import { existsSync, readFileSync } from "node:fs";
|
|
7
8
|
import path from "node:path";
|
|
@@ -11,11 +12,17 @@ import {
|
|
|
11
12
|
resolveRuntimeProfileFromSurface
|
|
12
13
|
} from "@jskit-ai/kernel/server/platform";
|
|
13
14
|
import { loadAppConfigFromAppRoot } from "@jskit-ai/kernel/server/support";
|
|
14
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
API_BASE_PATH,
|
|
17
|
+
matchesPathPrefix,
|
|
18
|
+
normalizePathname,
|
|
19
|
+
toRequestPathname
|
|
20
|
+
} from "@jskit-ai/kernel/shared/surface/paths";
|
|
15
21
|
import { surfaceRuntime } from "./server/lib/surfaceRuntime.js";
|
|
16
22
|
|
|
23
|
+
/** @typedef {import("@jskit-ai/kernel/server/types").RuntimeEnv} RuntimeEnv */
|
|
24
|
+
|
|
17
25
|
const SPA_INDEX_FILE = "index.html";
|
|
18
|
-
const API_BASE_PATH = "/api";
|
|
19
26
|
const STATIC_GLOBAL_UI_PATHS = Object.freeze([
|
|
20
27
|
"/assets",
|
|
21
28
|
"/favicon.svg",
|
|
@@ -24,15 +31,6 @@ const STATIC_GLOBAL_UI_PATHS = Object.freeze([
|
|
|
24
31
|
"/manifest.webmanifest"
|
|
25
32
|
]);
|
|
26
33
|
|
|
27
|
-
function toRequestPathname(urlValue) {
|
|
28
|
-
const rawUrl = String(urlValue || "").trim() || "/";
|
|
29
|
-
try {
|
|
30
|
-
return normalizePathname(new URL(rawUrl, "http://localhost").pathname || "/");
|
|
31
|
-
} catch {
|
|
32
|
-
return normalizePathname(rawUrl.split("?")[0] || "/");
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
34
|
function isApiPath(pathname) {
|
|
37
35
|
return matchesPathPrefix(pathname, API_BASE_PATH);
|
|
38
36
|
}
|
|
@@ -41,15 +39,15 @@ function hasFileExtension(pathname) {
|
|
|
41
39
|
return path.extname(normalizePathname(pathname)) !== "";
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
function
|
|
45
|
-
const paths = new Set(
|
|
42
|
+
function buildGlobalUiPaths(runtimeGlobalUiPaths) {
|
|
43
|
+
const paths = new Set(runtimeGlobalUiPaths);
|
|
46
44
|
for (const staticPath of STATIC_GLOBAL_UI_PATHS) {
|
|
47
45
|
paths.add(staticPath);
|
|
48
46
|
}
|
|
49
47
|
return [...paths];
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
function
|
|
50
|
+
function toStaticFilePath(pathname) {
|
|
53
51
|
const normalizedPathname = normalizePathname(pathname);
|
|
54
52
|
|
|
55
53
|
const relativePath = normalizedPathname.replace(/^\/+/, "");
|
|
@@ -85,9 +83,13 @@ function canServeStaticFile(distRoot, relativePath) {
|
|
|
85
83
|
return existsSync(resolvedPath);
|
|
86
84
|
}
|
|
87
85
|
|
|
88
|
-
|
|
86
|
+
/**
|
|
87
|
+
* The application's Fastify server with its installed JSKIT runtime, for the environment given.
|
|
88
|
+
* @param {{ runtimeEnv: RuntimeEnv }} settings
|
|
89
|
+
*/
|
|
90
|
+
async function createServer({ runtimeEnv }) {
|
|
89
91
|
const app = Fastify({
|
|
90
|
-
logger:
|
|
92
|
+
logger: buildLoggerOptions(),
|
|
91
93
|
schemaController: {
|
|
92
94
|
compilersFactory: {
|
|
93
95
|
buildSerializer: createCachedResponseSerializerFactory(SerializerSelector())
|
|
@@ -126,7 +128,7 @@ async function createServer({ runtimeEnv = resolveRuntimeEnv() } = {}) {
|
|
|
126
128
|
fastify: app,
|
|
127
129
|
surfaceRuntime,
|
|
128
130
|
serverSurface: runtimeEnv.SERVER_SURFACE,
|
|
129
|
-
globalUiPaths:
|
|
131
|
+
globalUiPaths: buildGlobalUiPaths(runtime.globalUiPaths)
|
|
130
132
|
});
|
|
131
133
|
|
|
132
134
|
if (hasWebBuild) {
|
|
@@ -140,10 +142,8 @@ async function createServer({ runtimeEnv = resolveRuntimeEnv() } = {}) {
|
|
|
140
142
|
}
|
|
141
143
|
|
|
142
144
|
app.setNotFoundHandler(async (request, reply) => {
|
|
143
|
-
const pathname = toRequestPathname(request
|
|
144
|
-
const method =
|
|
145
|
-
.trim()
|
|
146
|
-
.toUpperCase();
|
|
145
|
+
const pathname = toRequestPathname(request.url);
|
|
146
|
+
const method = request.method;
|
|
147
147
|
if (isApiPath(pathname) || (method !== "GET" && method !== "HEAD")) {
|
|
148
148
|
return reply.code(404).send({
|
|
149
149
|
message: `Route ${method}:${pathname} not found`,
|
|
@@ -152,7 +152,7 @@ async function createServer({ runtimeEnv = resolveRuntimeEnv() } = {}) {
|
|
|
152
152
|
});
|
|
153
153
|
}
|
|
154
154
|
if (hasFileExtension(pathname)) {
|
|
155
|
-
const staticFilePath =
|
|
155
|
+
const staticFilePath = toStaticFilePath(pathname);
|
|
156
156
|
if (hasWebBuild && staticFilePath && canServeStaticFile(distRoot, staticFilePath)) {
|
|
157
157
|
return reply.sendFile(staticFilePath);
|
|
158
158
|
}
|
|
@@ -183,19 +183,22 @@ async function createServer({ runtimeEnv = resolveRuntimeEnv() } = {}) {
|
|
|
183
183
|
return app;
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Starts the server on the host and port given, else on the environment's HOST and PORT.
|
|
188
|
+
* @param {{ host?: string, port?: number }} [options]
|
|
189
|
+
*/
|
|
190
|
+
async function startServer({ host, port } = {}) {
|
|
187
191
|
const runtimeEnv = resolveRuntimeEnv();
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
const host = String(options?.host || "").trim() || runtimeEnv.HOST;
|
|
192
|
+
const listenHost = host || runtimeEnv.HOST;
|
|
193
|
+
const listenPort = port ?? Number(runtimeEnv.PORT);
|
|
191
194
|
const app = await createServer({
|
|
192
195
|
runtimeEnv: {
|
|
193
196
|
...runtimeEnv,
|
|
194
|
-
HOST:
|
|
195
|
-
PORT:
|
|
197
|
+
HOST: listenHost,
|
|
198
|
+
PORT: String(listenPort)
|
|
196
199
|
}
|
|
197
200
|
});
|
|
198
|
-
await app.listen({ port, host });
|
|
201
|
+
await app.listen({ port: listenPort, host: listenHost });
|
|
199
202
|
return app;
|
|
200
203
|
}
|
|
201
204
|
|
package/skills/jskit/references/patterns/app/shell-foundation/example/tests/server/smoke.test.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import test from "node:test";
|
|
3
3
|
import { createServer } from "../../server.js";
|
|
4
|
+
import { resolveRuntimeEnv } from "../../server/lib/runtimeEnv.js";
|
|
4
5
|
|
|
5
6
|
test("GET /api/health returns built-in health response", async () => {
|
|
6
|
-
const app = await createServer();
|
|
7
|
+
const app = await createServer({ runtimeEnv: resolveRuntimeEnv() });
|
|
7
8
|
const response = await app.inject({
|
|
8
9
|
method: "GET",
|
|
9
10
|
url: "/api/health"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveActorId } from "@jskit-ai/kernel/server/actions/actionContributorHelpers";
|
|
1
2
|
import { defineFeature } from "@jskit-ai/kernel/server/features";
|
|
2
3
|
import { createAiConnectionResolver } from "@jskit-ai/connectors-catalog/server/ai";
|
|
3
4
|
import { createEnvironmentReferenceResolver } from "@jskit-ai/connectors-core/server";
|
|
@@ -10,9 +11,10 @@ export const ApplicationAiFeature = defineFeature({
|
|
|
10
11
|
return { ai: createAiConnectionResolver({
|
|
11
12
|
configuration,
|
|
12
13
|
authorize(context) {
|
|
13
|
-
|
|
14
|
+
const actorId = resolveActorId(context);
|
|
15
|
+
if (!actorId) return null;
|
|
14
16
|
// Apply the app's AI-use policy here; the actor comes from authentication.
|
|
15
|
-
return { applicationId: "my-app", subjectId:
|
|
17
|
+
return { applicationId: "my-app", subjectId: actorId };
|
|
16
18
|
},
|
|
17
19
|
resolveReference: createEnvironmentReferenceResolver(env)
|
|
18
20
|
}) };
|
|
@@ -66,7 +66,8 @@ server's global UI paths so a surface-filtered server still serves them.
|
|
|
66
66
|
Pages send `x-hub-request: 1` on every state-changing call.
|
|
67
67
|
|
|
68
68
|
Commands (`jskit-oidc-issuer`): `keys rotate`, `import-accounts --in <file>
|
|
69
|
-
[--apply]` (dry run by default), `preview-identity
|
|
69
|
+
[--apply]` (dry run by default), `preview-identity [--protocol <id>]
|
|
70
|
+
[--local-hostname <pattern>]...`.
|
|
70
71
|
|
|
71
72
|
## Example files
|
|
72
73
|
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { HUB_GLOBAL_PATHS } from "@jskit-ai/oidc-issuer-core/server";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The global UI paths with the hub's added to the runtime's own. Pass them to
|
|
5
|
+
* registerSurfaceRequestConstraint({ globalUiPaths }), so every surface server
|
|
6
|
+
* serves the hub.
|
|
7
|
+
* @param {string[]} runtimeGlobalUiPaths
|
|
8
|
+
*/
|
|
9
|
+
function hubGlobalUiPaths(runtimeGlobalUiPaths) {
|
|
6
10
|
return [...new Set([...runtimeGlobalUiPaths, ...HUB_GLOBAL_PATHS])];
|
|
7
11
|
}
|
|
12
|
+
|
|
13
|
+
export { hubGlobalUiPaths };
|