@lssm/lib.contracts 0.0.0-canary-20251217063201 → 0.0.0-canary-20251217072406
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app-config/app-config.feature.js +53 -1
- package/dist/app-config/contracts.d.ts +50 -50
- package/dist/app-config/contracts.js +396 -1
- package/dist/app-config/docs/app-config.docblock.js +22 -220
- package/dist/app-config/events.d.ts +27 -27
- package/dist/app-config/events.js +168 -1
- package/dist/app-config/index.js +8 -1
- package/dist/app-config/lifecycle-contracts.d.ts +80 -80
- package/dist/app-config/lifecycle-contracts.js +441 -1
- package/dist/app-config/runtime.js +617 -1
- package/dist/app-config/spec.js +36 -1
- package/dist/app-config/validation.js +538 -1
- package/dist/capabilities/docs/capabilities.docblock.js +22 -1
- package/dist/capabilities/openbanking.js +92 -1
- package/dist/capabilities.js +50 -1
- package/dist/client/index.js +9 -1
- package/dist/client/react/drivers/rn-reusables.js +21 -1
- package/dist/client/react/drivers/shadcn.js +11 -1
- package/dist/client/react/feature-render.js +43 -1
- package/dist/client/react/form-render.js +298 -1
- package/dist/client/react/index.js +8 -1
- package/dist/contract-registry/index.js +3 -1
- package/dist/contract-registry/schemas.js +61 -1
- package/dist/contracts-adapter-hydration.js +41 -1
- package/dist/contracts-adapter-input.js +77 -1
- package/dist/data-views/docs/data-views.docblock.js +22 -1
- package/dist/data-views/query-generator.js +48 -1
- package/dist/data-views/runtime.js +39 -1
- package/dist/data-views.js +35 -1
- package/dist/docs/PUBLISHING.docblock.js +17 -76
- package/dist/docs/accessibility_wcag_compliance_specs.docblock.js +17 -350
- package/dist/docs/index.js +33 -1
- package/dist/docs/meta.docs.js +15 -2
- package/dist/docs/presentations.js +77 -1
- package/dist/docs/registry.js +51 -1
- package/dist/docs/tech/PHASE_1_QUICKSTART.docblock.js +17 -383
- package/dist/docs/tech/PHASE_2_AI_NATIVE_OPERATIONS.docblock.js +17 -68
- package/dist/docs/tech/PHASE_3_AUTO_EVOLUTION.docblock.js +17 -140
- package/dist/docs/tech/PHASE_4_PERSONALIZATION_ENGINE.docblock.js +17 -86
- package/dist/docs/tech/PHASE_5_ZERO_TOUCH_OPERATIONS.docblock.js +17 -1
- package/dist/docs/tech/auth/better-auth-nextjs.docblock.js +25 -2
- package/dist/docs/tech/contracts/README.docblock.js +21 -1
- package/dist/docs/tech/contracts/create-subscription.docblock.js +21 -1
- package/dist/docs/tech/contracts/graphql-typed-outputs.docblock.js +21 -180
- package/dist/docs/tech/contracts/migrations.docblock.js +21 -1
- package/dist/docs/tech/contracts/openapi-export.docblock.js +22 -2
- package/dist/docs/tech/contracts/ops-to-presentation-linking.docblock.js +19 -60
- package/dist/docs/tech/contracts/overlays.docblock.js +21 -68
- package/dist/docs/tech/contracts/tests.docblock.js +21 -132
- package/dist/docs/tech/contracts/themes.docblock.js +21 -1
- package/dist/docs/tech/contracts/vertical-pocket-family-office.docblock.js +21 -106
- package/dist/docs/tech/lifecycle-stage-system.docblock.js +17 -213
- package/dist/docs/tech/llm/llm-integration.docblock.js +74 -5
- package/dist/docs/tech/mcp-endpoints.docblock.js +38 -1
- package/dist/docs/tech/presentation-runtime.docblock.js +17 -1
- package/dist/docs/tech/schema/README.docblock.js +21 -262
- package/dist/docs/tech/studio/learning-events.docblock.js +49 -1
- package/dist/docs/tech/studio/learning-journeys.docblock.js +25 -2
- package/dist/docs/tech/studio/platform-admin-panel.docblock.js +24 -2
- package/dist/docs/tech/studio/project-access-teams.docblock.js +26 -16
- package/dist/docs/tech/studio/project-routing.docblock.js +68 -1
- package/dist/docs/tech/studio/sandbox-unlogged.docblock.js +23 -2
- package/dist/docs/tech/studio/team-invitations.docblock.js +41 -36
- package/dist/docs/tech/studio/workspace-ops.docblock.js +48 -1
- package/dist/docs/tech/studio/workspaces.docblock.js +24 -2
- package/dist/docs/tech/telemetry-ingest.docblock.js +37 -3
- package/dist/docs/tech/templates/runtime.docblock.js +21 -1
- package/dist/docs/tech/vscode-extension.docblock.js +37 -3
- package/dist/docs/tech/workflows/overview.docblock.js +21 -1
- package/dist/docs/tech-contracts.docs.js +19 -2
- package/dist/events.js +12 -1
- package/dist/experiments/docs/experiments.docblock.js +22 -128
- package/dist/experiments/evaluator.js +101 -1
- package/dist/experiments/spec.js +33 -1
- package/dist/features.js +68 -1
- package/dist/forms/docs/forms.docblock.js +22 -1
- package/dist/forms.js +119 -1
- package/dist/index.js +107 -1
- package/dist/install.js +40 -1
- package/dist/integrations/contracts.d.ts +102 -102
- package/dist/integrations/contracts.js +388 -1
- package/dist/integrations/docs/integrations.docblock.js +95 -1
- package/dist/integrations/health.js +69 -1
- package/dist/integrations/index.js +23 -1
- package/dist/integrations/openbanking/contracts/accounts.d.ts +66 -66
- package/dist/integrations/openbanking/contracts/accounts.js +237 -1
- package/dist/integrations/openbanking/contracts/balances.d.ts +34 -34
- package/dist/integrations/openbanking/contracts/balances.js +167 -1
- package/dist/integrations/openbanking/contracts/index.js +12 -1
- package/dist/integrations/openbanking/contracts/transactions.d.ts +48 -48
- package/dist/integrations/openbanking/contracts/transactions.js +218 -1
- package/dist/integrations/openbanking/guards.js +32 -1
- package/dist/integrations/openbanking/models.d.ts +55 -55
- package/dist/integrations/openbanking/models.js +242 -1
- package/dist/integrations/openbanking/openbanking.feature.js +68 -1
- package/dist/integrations/openbanking/telemetry.js +39 -1
- package/dist/integrations/providers/elevenlabs.js +56 -1
- package/dist/integrations/providers/gcs-storage.js +79 -1
- package/dist/integrations/providers/gmail.js +91 -1
- package/dist/integrations/providers/google-calendar.js +70 -1
- package/dist/integrations/providers/impls/elevenlabs-voice.js +95 -1
- package/dist/integrations/providers/impls/gcs-storage.js +88 -1
- package/dist/integrations/providers/impls/gmail-inbound.js +200 -1
- package/dist/integrations/providers/impls/gmail-outbound.js +104 -5
- package/dist/integrations/providers/impls/google-calendar.js +154 -1
- package/dist/integrations/providers/impls/index.js +16 -1
- package/dist/integrations/providers/impls/mistral-embedding.js +41 -1
- package/dist/integrations/providers/impls/mistral-llm.js +247 -1
- package/dist/integrations/providers/impls/postmark-email.js +55 -1
- package/dist/integrations/providers/impls/powens-client.js +171 -1
- package/dist/integrations/providers/impls/powens-openbanking.js +218 -1
- package/dist/integrations/providers/impls/provider-factory.js +142 -1
- package/dist/integrations/providers/impls/qdrant-vector.js +69 -1
- package/dist/integrations/providers/impls/stripe-payments.js +202 -1
- package/dist/integrations/providers/impls/twilio-sms.js +58 -1
- package/dist/integrations/providers/index.js +13 -1
- package/dist/integrations/providers/mistral.js +72 -1
- package/dist/integrations/providers/postmark.js +72 -1
- package/dist/integrations/providers/powens.js +120 -1
- package/dist/integrations/providers/qdrant.js +77 -1
- package/dist/integrations/providers/registry.js +34 -1
- package/dist/integrations/providers/stripe.js +87 -1
- package/dist/integrations/providers/twilio-sms.js +65 -1
- package/dist/integrations/runtime.js +186 -1
- package/dist/integrations/secrets/aws-secret-manager.js +231 -1
- package/dist/integrations/secrets/env-secret-provider.js +81 -1
- package/dist/integrations/secrets/gcp-secret-manager.js +229 -1
- package/dist/integrations/secrets/index.js +8 -1
- package/dist/integrations/secrets/manager.js +103 -1
- package/dist/integrations/secrets/provider.js +58 -1
- package/dist/integrations/secrets/scaleway-secret-manager.js +247 -1
- package/dist/integrations/spec.js +39 -1
- package/dist/jobs/define-job.js +16 -1
- package/dist/jobs/gcp-cloud-tasks.js +53 -1
- package/dist/jobs/gcp-pubsub.js +39 -1
- package/dist/jobs/handlers/gmail-sync-handler.js +9 -1
- package/dist/jobs/handlers/index.js +12 -1
- package/dist/jobs/handlers/ping-handler.js +15 -1
- package/dist/jobs/handlers/storage-document-handler.js +14 -1
- package/dist/jobs/index.js +4 -1
- package/dist/jobs/memory-queue.js +71 -1
- package/dist/jobs/queue.js +33 -1
- package/dist/jobs/scaleway-sqs-queue.js +153 -1
- package/dist/jsonschema.d.ts +3 -3
- package/dist/jsonschema.js +32 -1
- package/dist/knowledge/contracts.d.ts +66 -66
- package/dist/knowledge/contracts.js +317 -1
- package/dist/knowledge/docs/knowledge.docblock.js +22 -138
- package/dist/knowledge/index.js +10 -1
- package/dist/knowledge/ingestion/document-processor.js +54 -1
- package/dist/knowledge/ingestion/embedding-service.js +25 -1
- package/dist/knowledge/ingestion/gmail-adapter.js +50 -5
- package/dist/knowledge/ingestion/index.js +7 -1
- package/dist/knowledge/ingestion/storage-adapter.js +26 -1
- package/dist/knowledge/ingestion/vector-indexer.js +32 -1
- package/dist/knowledge/query/index.js +3 -1
- package/dist/knowledge/query/service.js +64 -2
- package/dist/knowledge/runtime.js +49 -1
- package/dist/knowledge/spaces/email-threads.js +38 -1
- package/dist/knowledge/spaces/financial-docs.js +38 -1
- package/dist/knowledge/spaces/financial-overview.js +42 -1
- package/dist/knowledge/spaces/index.js +8 -1
- package/dist/knowledge/spaces/product-canon.js +38 -1
- package/dist/knowledge/spaces/support-faq.js +41 -1
- package/dist/knowledge/spaces/uploaded-docs.js +38 -1
- package/dist/knowledge/spec.js +39 -1
- package/dist/llm/exporters.js +541 -8
- package/dist/llm/index.js +4 -1
- package/dist/llm/prompts.js +246 -56
- package/dist/markdown.js +116 -3
- package/dist/migrations.js +33 -1
- package/dist/onboarding-base.d.ts +29 -29
- package/dist/onboarding-base.js +196 -1
- package/dist/openapi.js +75 -1
- package/dist/openbanking/docs/openbanking.docblock.js +22 -109
- package/dist/ownership.js +40 -1
- package/dist/policy/docs/policy.docblock.js +22 -1
- package/dist/policy/engine.js +223 -1
- package/dist/policy/opa-adapter.js +71 -1
- package/dist/policy/spec.js +33 -1
- package/dist/presentations/docs/presentations-conventions.docblock.js +21 -7
- package/dist/presentations.backcompat.js +47 -1
- package/dist/presentations.d.ts +3 -3
- package/dist/presentations.js +66 -1
- package/dist/presentations.v2.js +278 -6
- package/dist/prompt.js +10 -1
- package/dist/promptRegistry.js +34 -1
- package/dist/regenerator/docs/regenerator.docblock.js +22 -184
- package/dist/regenerator/executor.js +86 -1
- package/dist/regenerator/index.js +6 -1
- package/dist/regenerator/service.js +92 -1
- package/dist/regenerator/sinks.js +32 -1
- package/dist/regenerator/utils.js +51 -1
- package/dist/registry.js +208 -1
- package/dist/resources.js +47 -1
- package/dist/schema/dist/EnumType.js +2 -1
- package/dist/schema/dist/FieldType.js +49 -1
- package/dist/schema/dist/ScalarTypeEnum.js +236 -1
- package/dist/schema/dist/SchemaModel.js +39 -1
- package/dist/schema/dist/entity/defineEntity.js +1 -1
- package/dist/schema/dist/entity/index.js +2 -1
- package/dist/schema/dist/entity/types.js +1 -1
- package/dist/schema/dist/index.js +6 -1
- package/dist/schema-to-markdown.js +214 -10
- package/dist/server/graphql-pothos.js +128 -1
- package/dist/server/index.js +10 -1
- package/dist/server/mcp/createMcpServer.js +28 -1
- package/dist/server/mcp/registerPresentations.js +151 -1
- package/dist/server/mcp/registerPrompts.js +36 -2
- package/dist/server/mcp/registerResources.js +35 -1
- package/dist/server/mcp/registerTools.js +22 -1
- package/dist/server/provider-mcp.js +3 -1
- package/dist/server/rest-elysia.js +20 -1
- package/dist/server/rest-express.js +39 -1
- package/dist/server/rest-generic.js +125 -1
- package/dist/server/rest-next-app.js +38 -1
- package/dist/server/rest-next-mcp.js +45 -1
- package/dist/server/rest-next-pages.js +25 -1
- package/dist/spec.js +35 -1
- package/dist/telemetry/anomaly.js +48 -1
- package/dist/telemetry/docs/telemetry.docblock.js +22 -139
- package/dist/telemetry/index.js +5 -1
- package/dist/telemetry/spec.js +69 -1
- package/dist/telemetry/tracker.js +76 -1
- package/dist/tests/index.js +4 -1
- package/dist/tests/runner.js +150 -1
- package/dist/tests/spec.js +33 -1
- package/dist/themes.js +39 -1
- package/dist/workflow/adapters/db-adapter.js +83 -1
- package/dist/workflow/adapters/file-adapter.js +11 -1
- package/dist/workflow/adapters/index.js +5 -1
- package/dist/workflow/adapters/memory-store.js +58 -1
- package/dist/workflow/expression.js +98 -1
- package/dist/workflow/index.js +9 -1
- package/dist/workflow/runner.js +337 -1
- package/dist/workflow/sla-monitor.js +47 -1
- package/dist/workflow/spec.js +32 -1
- package/dist/workflow/validation.js +175 -1
- package/package.json +11 -4
package/dist/server/index.js
CHANGED
|
@@ -1 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { registerContractsOnBuilder } from "./graphql-pothos.js";
|
|
2
|
+
import { createMcpServer } from "./mcp/createMcpServer.js";
|
|
3
|
+
import "./provider-mcp.js";
|
|
4
|
+
import { createFetchHandler } from "./rest-generic.js";
|
|
5
|
+
import { elysiaPlugin } from "./rest-elysia.js";
|
|
6
|
+
import { expressRouter } from "./rest-express.js";
|
|
7
|
+
import { makeNextAppHandler } from "./rest-next-app.js";
|
|
8
|
+
import { makeNextPagesHandler } from "./rest-next-pages.js";
|
|
9
|
+
|
|
10
|
+
export { createFetchHandler, createMcpServer, elysiaPlugin, expressRouter, makeNextAppHandler, makeNextPagesHandler, registerContractsOnBuilder };
|
|
@@ -1 +1,28 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { registerMcpTools } from "./registerTools.js";
|
|
2
|
+
import { registerMcpResources } from "./registerResources.js";
|
|
3
|
+
import { registerMcpPrompts } from "./registerPrompts.js";
|
|
4
|
+
import { registerMcpPresentations } from "./registerPresentations.js";
|
|
5
|
+
|
|
6
|
+
//#region src/server/mcp/createMcpServer.ts
|
|
7
|
+
/**
|
|
8
|
+
* Creates a unified Model Context Protocol (MCP) server exposing operations, resources, prompts,
|
|
9
|
+
* and (optionally) presentations.\n+ *
|
|
10
|
+
* ContractSpec exposes:\n+ * - Tools: `command` operations from `SpecRegistry`.\n+ * - Resources: templates from `ResourceRegistry`.\n+ * - Prompts: templates from `PromptRegistry`.\n+ * - Presentations: V1 registry and/or V2 descriptors as read-only resources.\n+ */
|
|
11
|
+
function createMcpServer(server, ops, resources, prompts, ctxFactories) {
|
|
12
|
+
ctxFactories.logger.info("Creating MCP server");
|
|
13
|
+
registerMcpTools(server, ops, { toolCtx: ctxFactories.toolCtx });
|
|
14
|
+
registerMcpResources(server, resources, {
|
|
15
|
+
logger: ctxFactories.logger,
|
|
16
|
+
resourceCtx: ctxFactories.resourceCtx
|
|
17
|
+
});
|
|
18
|
+
registerMcpPresentations(server, {
|
|
19
|
+
logger: ctxFactories.logger,
|
|
20
|
+
presentations: ctxFactories.presentations,
|
|
21
|
+
presentationsV2: ctxFactories.presentationsV2
|
|
22
|
+
});
|
|
23
|
+
registerMcpPrompts(server, prompts, { promptCtx: ctxFactories.promptCtx });
|
|
24
|
+
return server;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
export { createMcpServer };
|
|
@@ -1 +1,151 @@
|
|
|
1
|
-
import{createDefaultTransformEngine
|
|
1
|
+
import { createDefaultTransformEngine, registerBasicValidation, registerDefaultReactRenderer } from "../../presentations.v2.js";
|
|
2
|
+
import { jsonSchemaForPresentation } from "../../presentations.js";
|
|
3
|
+
|
|
4
|
+
//#region src/server/mcp/registerPresentations.ts
|
|
5
|
+
function isEngineRenderOutput(x) {
|
|
6
|
+
if (!x || typeof x !== "object") return false;
|
|
7
|
+
return "body" in x && typeof x.body === "string";
|
|
8
|
+
}
|
|
9
|
+
function registerMcpPresentations(server, ctx) {
|
|
10
|
+
const __presentations = ctx.presentations;
|
|
11
|
+
const __presentationsV2 = ctx.presentationsV2;
|
|
12
|
+
if (__presentations) for (const p of __presentations.list()) {
|
|
13
|
+
const baseKey = `presentation.${p.meta.name.replace(/\./g, "_")}.v${p.meta.version}`;
|
|
14
|
+
const baseUri = `presentation://${p.meta.name}/v${p.meta.version}`;
|
|
15
|
+
server.registerResource(baseKey, baseUri, {
|
|
16
|
+
title: `${p.meta.name} v${p.meta.version}`,
|
|
17
|
+
description: p.meta.description ?? "Presentation"
|
|
18
|
+
}, async () => {
|
|
19
|
+
if (p.content.kind === "markdown") return { contents: [{
|
|
20
|
+
uri: baseUri,
|
|
21
|
+
mimeType: "text/markdown",
|
|
22
|
+
text: p.content.content ? p.content.content : `See resource: ${p.content.resourceUri ?? ""}`
|
|
23
|
+
}] };
|
|
24
|
+
if (p.content.kind === "data") {
|
|
25
|
+
const schema = jsonSchemaForPresentation(p);
|
|
26
|
+
return { contents: [{
|
|
27
|
+
uri: baseUri,
|
|
28
|
+
mimeType: "application/json",
|
|
29
|
+
text: JSON.stringify(schema, null, 2)
|
|
30
|
+
}] };
|
|
31
|
+
}
|
|
32
|
+
const metaOnly = {
|
|
33
|
+
name: p.meta.name,
|
|
34
|
+
version: p.meta.version,
|
|
35
|
+
kind: p.content.kind,
|
|
36
|
+
description: p.meta.description ?? ""
|
|
37
|
+
};
|
|
38
|
+
return { contents: [{
|
|
39
|
+
uri: baseUri,
|
|
40
|
+
mimeType: "application/json",
|
|
41
|
+
text: JSON.stringify(metaOnly, null, 2)
|
|
42
|
+
}] };
|
|
43
|
+
});
|
|
44
|
+
for (const v of [
|
|
45
|
+
{
|
|
46
|
+
ext: ".md",
|
|
47
|
+
target: "markdown"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
ext: ".json",
|
|
51
|
+
target: "application/json"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
ext: ".xml",
|
|
55
|
+
target: "application/xml"
|
|
56
|
+
}
|
|
57
|
+
]) {
|
|
58
|
+
const key = `${baseKey}${v.ext}`;
|
|
59
|
+
const uri = `${baseUri}${v.ext}`;
|
|
60
|
+
ctx.logger.info(`Registering presentation resource ${uri} for ${key}`);
|
|
61
|
+
server.registerResource(key, uri, {
|
|
62
|
+
title: `${p.meta.name} v${p.meta.version} (${v.ext})`,
|
|
63
|
+
description: `${p.meta.description ?? "Presentation"} (${v.ext})`
|
|
64
|
+
}, async () => {
|
|
65
|
+
if (p.content.kind === "markdown" && v.target === "markdown") return { contents: [{
|
|
66
|
+
uri,
|
|
67
|
+
mimeType: "text/markdown",
|
|
68
|
+
text: p.content.content ?? `See resource: ${p.content.resourceUri ?? ""}`
|
|
69
|
+
}] };
|
|
70
|
+
if (p.content.kind === "data" && v.target === "application/json") return { contents: [{
|
|
71
|
+
uri,
|
|
72
|
+
mimeType: "application/json",
|
|
73
|
+
text: JSON.stringify(jsonSchemaForPresentation(p), null, 2)
|
|
74
|
+
}] };
|
|
75
|
+
const jsonText = JSON.stringify({
|
|
76
|
+
meta: p.meta,
|
|
77
|
+
content: p.content
|
|
78
|
+
}, null, 2);
|
|
79
|
+
if (v.target === "application/json") return { contents: [{
|
|
80
|
+
uri,
|
|
81
|
+
mimeType: "application/json",
|
|
82
|
+
text: jsonText
|
|
83
|
+
}] };
|
|
84
|
+
if (v.target === "application/xml") return { contents: [{
|
|
85
|
+
uri,
|
|
86
|
+
mimeType: "application/xml",
|
|
87
|
+
text: `<presentation name="${p.meta.name}" version="${p.meta.version}"><json>${encodeURIComponent(jsonText)}</json></presentation>`
|
|
88
|
+
}] };
|
|
89
|
+
return { contents: [{
|
|
90
|
+
uri,
|
|
91
|
+
mimeType: "text/markdown",
|
|
92
|
+
text: "Unsupported presentation for markdown"
|
|
93
|
+
}] };
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (__presentationsV2 && __presentationsV2.length) {
|
|
98
|
+
const engine = registerBasicValidation(registerDefaultReactRenderer(createDefaultTransformEngine()));
|
|
99
|
+
for (const d of __presentationsV2) {
|
|
100
|
+
const baseKey = `presentation.${d.meta.name.replace(/\./g, "_")}.v${d.meta.version}`;
|
|
101
|
+
const baseUri = `presentation://${d.meta.name}/v${d.meta.version}`;
|
|
102
|
+
ctx.logger.info(`Registering presentation descriptor ${baseUri} for ${baseKey}`);
|
|
103
|
+
server.registerResource(baseKey, baseUri, {
|
|
104
|
+
title: `${d.meta.name} v${d.meta.version}`,
|
|
105
|
+
description: d.meta.description ?? "Presentation",
|
|
106
|
+
mimeType: "application/json"
|
|
107
|
+
}, async () => {
|
|
108
|
+
return { contents: [{
|
|
109
|
+
uri: baseUri,
|
|
110
|
+
mimeType: "application/json",
|
|
111
|
+
text: JSON.stringify({
|
|
112
|
+
meta: d.meta,
|
|
113
|
+
source: d.source,
|
|
114
|
+
targets: d.targets
|
|
115
|
+
}, null, 2)
|
|
116
|
+
}] };
|
|
117
|
+
});
|
|
118
|
+
for (const v of [
|
|
119
|
+
{
|
|
120
|
+
ext: ".md",
|
|
121
|
+
target: "markdown"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
ext: ".json",
|
|
125
|
+
target: "application/json"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
ext: ".xml",
|
|
129
|
+
target: "application/xml"
|
|
130
|
+
}
|
|
131
|
+
]) {
|
|
132
|
+
const key = `${baseKey}${v.ext}`;
|
|
133
|
+
const uri = `${baseUri}${v.ext}`;
|
|
134
|
+
server.registerResource(key, uri, {
|
|
135
|
+
title: `${d.meta.name} v${d.meta.version} (${v.ext})`,
|
|
136
|
+
description: `${d.meta.description ?? "Presentation"} (${v.ext})`
|
|
137
|
+
}, async () => {
|
|
138
|
+
const out = await engine.render(v.target, d);
|
|
139
|
+
return { contents: [{
|
|
140
|
+
uri,
|
|
141
|
+
mimeType: isEngineRenderOutput(out) && out.mimeType ? out.mimeType : v.target === "markdown" ? "text/markdown" : v.target,
|
|
142
|
+
text: isEngineRenderOutput(out) && typeof out.body === "string" ? out.body : String(out)
|
|
143
|
+
}] };
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
//#endregion
|
|
151
|
+
export { registerMcpPresentations };
|
|
@@ -1,3 +1,37 @@
|
|
|
1
|
-
import
|
|
1
|
+
import z from "zod";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
//#region src/server/mcp/registerPrompts.ts
|
|
4
|
+
function promptArgsSchemaFromPromptArgs(args) {
|
|
5
|
+
const shape = {};
|
|
6
|
+
for (const a of args) shape[a.name] = a.schema;
|
|
7
|
+
return shape;
|
|
8
|
+
}
|
|
9
|
+
function registerMcpPrompts(server, prompts, ctx) {
|
|
10
|
+
for (const prompt of prompts.list()) server.registerPrompt(prompt.meta.name, {
|
|
11
|
+
title: prompt.meta.title,
|
|
12
|
+
description: prompt.meta.description,
|
|
13
|
+
argsSchema: promptArgsSchemaFromPromptArgs(prompt.args)
|
|
14
|
+
}, async (args) => {
|
|
15
|
+
const link = (tpl, vars) => {
|
|
16
|
+
let out = tpl;
|
|
17
|
+
for (const [k, v] of Object.entries(vars)) out = out.replace(new RegExp(`\\{${k}\\}`, "g"), encodeURIComponent(String(v)));
|
|
18
|
+
return out;
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
messages: [{
|
|
22
|
+
role: "assistant",
|
|
23
|
+
content: {
|
|
24
|
+
type: "text",
|
|
25
|
+
text: (await prompt.render(prompt.input.parse(args), {
|
|
26
|
+
...ctx.promptCtx(),
|
|
27
|
+
link
|
|
28
|
+
})).map((p) => p.type === "text" ? p.text : `See resource: ${p.title ?? p.uri}\nURI: ${p.uri}`).join("\n\n")
|
|
29
|
+
}
|
|
30
|
+
}],
|
|
31
|
+
description: prompt.meta.description
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
export { registerMcpPrompts };
|
|
@@ -1 +1,35 @@
|
|
|
1
|
-
import{ResourceTemplate
|
|
1
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { Buffer } from "node:buffer";
|
|
3
|
+
|
|
4
|
+
//#region src/server/mcp/registerResources.ts
|
|
5
|
+
function mcpResourceMeta(resource) {
|
|
6
|
+
return {
|
|
7
|
+
title: resource.meta.title,
|
|
8
|
+
description: resource.meta.description,
|
|
9
|
+
mimeType: resource.meta.mimeType,
|
|
10
|
+
_meta: { tags: resource.meta.tags ?? [] }
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function registerMcpResources(server, resources, ctx) {
|
|
14
|
+
for (const resource of resources.listTemplates()) {
|
|
15
|
+
ctx.logger.info("Registering resource: " + resource.meta.uriTemplate);
|
|
16
|
+
server.registerResource(resource.meta.uriTemplate, new ResourceTemplate(resource.meta.uriTemplate, { list: void 0 }), mcpResourceMeta(resource), async (_uri, variables) => {
|
|
17
|
+
const parsedArgs = resource.input.parse(variables);
|
|
18
|
+
const out = await resource.resolve(parsedArgs, ctx.resourceCtx());
|
|
19
|
+
if (typeof out.data === "string") return { contents: [{
|
|
20
|
+
uri: out.uri,
|
|
21
|
+
mimeType: out.mimeType ?? resource.meta.mimeType,
|
|
22
|
+
text: out.data
|
|
23
|
+
}] };
|
|
24
|
+
return { contents: [{
|
|
25
|
+
uri: out.uri,
|
|
26
|
+
mimeType: out.mimeType ?? resource.meta.mimeType,
|
|
27
|
+
blob: Buffer.from(out.data).toString("base64")
|
|
28
|
+
}] };
|
|
29
|
+
});
|
|
30
|
+
ctx.logger.info("Registered resource: " + resource.meta.uriTemplate);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { registerMcpResources };
|
|
@@ -1 +1,22 @@
|
|
|
1
|
-
import{defaultMcpTool
|
|
1
|
+
import { defaultMcpTool } from "../../jsonschema.js";
|
|
2
|
+
|
|
3
|
+
//#region src/server/mcp/registerTools.ts
|
|
4
|
+
function registerMcpTools(server, ops, ctx) {
|
|
5
|
+
for (const spec of ops.listSpecs()) {
|
|
6
|
+
if (spec.meta.kind !== "command") continue;
|
|
7
|
+
const toolName = spec.transport?.mcp?.toolName ?? defaultMcpTool(spec.meta.name, spec.meta.version);
|
|
8
|
+
server.registerTool(toolName, {
|
|
9
|
+
description: spec.meta.description,
|
|
10
|
+
inputSchema: spec.io.input?.getZod()
|
|
11
|
+
}, async (args) => {
|
|
12
|
+
const result = await ops.execute(spec.meta.name, spec.meta.version, args ?? {}, ctx.toolCtx());
|
|
13
|
+
return { content: [{
|
|
14
|
+
type: "text",
|
|
15
|
+
text: JSON.stringify(result, null, 4)
|
|
16
|
+
}] };
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { registerMcpTools };
|
|
@@ -1 +1,20 @@
|
|
|
1
|
-
import{createFetchHandler
|
|
1
|
+
import { createFetchHandler } from "./rest-generic.js";
|
|
2
|
+
|
|
3
|
+
//#region src/server/rest-elysia.ts
|
|
4
|
+
/** Mount routes on an Elysia instance */
|
|
5
|
+
function elysiaPlugin(app, reg, ctxFactory, options) {
|
|
6
|
+
const handler = createFetchHandler(reg, (req) => ctxFactory({
|
|
7
|
+
request: req,
|
|
8
|
+
store: app.store
|
|
9
|
+
}), options);
|
|
10
|
+
for (const spec of reg.listSpecs()) {
|
|
11
|
+
const method = spec.transport?.rest?.method ?? (spec.meta.kind === "query" ? "GET" : "POST");
|
|
12
|
+
const path = (options?.basePath ?? "") + (spec.transport?.rest?.path ?? `/${spec.meta.name.replace(/\./g, "/")}/v${spec.meta.version}`);
|
|
13
|
+
app[method.toLowerCase()](path, ({ request }) => handler(request));
|
|
14
|
+
}
|
|
15
|
+
if (options?.cors) app.options("*", ({ request }) => handler(request));
|
|
16
|
+
return app;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
export { elysiaPlugin };
|
|
@@ -1 +1,39 @@
|
|
|
1
|
-
import{createFetchHandler
|
|
1
|
+
import { createFetchHandler } from "./rest-generic.js";
|
|
2
|
+
|
|
3
|
+
//#region src/server/rest-express.ts
|
|
4
|
+
/**
|
|
5
|
+
* Build an Express Router that proxies to the Fetch-style handler.
|
|
6
|
+
* You can mount it at any base path; pass the same basePath in options.
|
|
7
|
+
*/
|
|
8
|
+
function expressRouter(express, reg, ctxFactory, options) {
|
|
9
|
+
const router = express.Router();
|
|
10
|
+
createFetchHandler(reg, (_r) => {
|
|
11
|
+
throw new Error("ctxFactory must be called from route");
|
|
12
|
+
}, options);
|
|
13
|
+
for (const spec of reg.listSpecs()) {
|
|
14
|
+
const method = spec.transport?.rest?.method ?? (spec.meta.kind === "query" ? "GET" : "POST");
|
|
15
|
+
const path = (options?.basePath ?? "") + (spec.transport?.rest?.path ?? `/${spec.meta.name.replace(/\./g, "/")}/v${spec.meta.version}`);
|
|
16
|
+
router[method.toLowerCase()](path, async (req, res) => {
|
|
17
|
+
const url = new URL(`${req.protocol}://${req.get("host")}${req.originalUrl}`);
|
|
18
|
+
const request = new Request(url.toString(), {
|
|
19
|
+
method,
|
|
20
|
+
headers: Object.fromEntries(Object.entries(req.headers).map(([k, v]) => [k, String(v)])),
|
|
21
|
+
body: method === "POST" ? JSON.stringify(req.body ?? {}) : void 0
|
|
22
|
+
});
|
|
23
|
+
const response = await createFetchHandler(reg, () => ctxFactory(req), options)(request);
|
|
24
|
+
res.status(response.status);
|
|
25
|
+
response.headers.forEach((v, k) => res.setHeader(k, v));
|
|
26
|
+
const text = await response.text();
|
|
27
|
+
res.send(text);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (options?.cors) router.options("*", (_req, res) => {
|
|
31
|
+
const h = new Headers();
|
|
32
|
+
new Response(null, { status: 204 }).headers.forEach((v, k) => h.set(k, v));
|
|
33
|
+
res.status(204).send();
|
|
34
|
+
});
|
|
35
|
+
return router;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
export { expressRouter };
|
|
@@ -1 +1,125 @@
|
|
|
1
|
-
import{defaultRestPath
|
|
1
|
+
import { defaultRestPath } from "../jsonschema.js";
|
|
2
|
+
|
|
3
|
+
//#region src/server/rest-generic.ts
|
|
4
|
+
/** Minimal WHATWG Response polyfill util for Node < 18 (if needed) */
|
|
5
|
+
function corsHeaders(opt) {
|
|
6
|
+
const h = {};
|
|
7
|
+
h["access-control-allow-origin"] = typeof opt === "object" ? opt.origin ?? "*" : "*";
|
|
8
|
+
h["vary"] = "Origin";
|
|
9
|
+
if (typeof opt === "object") {
|
|
10
|
+
if (opt.methods) h["access-control-allow-methods"] = opt.methods.join(", ");
|
|
11
|
+
if (opt.headers) h["access-control-allow-headers"] = opt.headers.join(", ");
|
|
12
|
+
if (opt.credentials) h["access-control-allow-credentials"] = "true";
|
|
13
|
+
if (typeof opt.maxAge === "number") h["access-control-max-age"] = String(opt.maxAge);
|
|
14
|
+
} else {
|
|
15
|
+
h["access-control-allow-methods"] = "GET,POST,OPTIONS";
|
|
16
|
+
h["access-control-allow-headers"] = "content-type,x-idempotency-key,x-trace-id";
|
|
17
|
+
}
|
|
18
|
+
return h;
|
|
19
|
+
}
|
|
20
|
+
function joinPath(a, b) {
|
|
21
|
+
return `${(a ?? "").replace(/\/+$/g, "")}/${b.replace(/^\/+/g, "")}`.replace(/\/{2,}/g, "/");
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Build a single Fetch-style handler: (req) => Response
|
|
25
|
+
* - Discovers routes from SpecRegistry
|
|
26
|
+
* - Validates with zod via registry.execute()
|
|
27
|
+
* - Handles CORS (optional)
|
|
28
|
+
*/
|
|
29
|
+
function createFetchHandler(reg, ctxFactory, options) {
|
|
30
|
+
const opts = {
|
|
31
|
+
basePath: options?.basePath ?? "",
|
|
32
|
+
cors: options?.cors ?? false,
|
|
33
|
+
prettyJson: options?.prettyJson ?? false,
|
|
34
|
+
onError: options?.onError
|
|
35
|
+
};
|
|
36
|
+
const routes = reg.listSpecs().map((spec) => ({
|
|
37
|
+
method: spec.transport?.rest?.method ?? (spec.meta.kind === "query" ? "GET" : "POST"),
|
|
38
|
+
path: joinPath(opts.basePath, spec.transport?.rest?.path ?? defaultRestPath(spec.meta.name, spec.meta.version)),
|
|
39
|
+
name: spec.meta.name,
|
|
40
|
+
version: spec.meta.version
|
|
41
|
+
}));
|
|
42
|
+
const routeTable = /* @__PURE__ */ new Map();
|
|
43
|
+
for (const r of routes) routeTable.set(`${r.method} ${r.path}`, r);
|
|
44
|
+
Array.from(new Set(routes.map((r) => r.method))).join(", ");
|
|
45
|
+
const makeJson = (status, data, extraHeaders) => {
|
|
46
|
+
const body = opts.prettyJson ? JSON.stringify(data, null, opts.prettyJson) : JSON.stringify(data);
|
|
47
|
+
const base = { "content-type": "application/json; charset=utf-8" };
|
|
48
|
+
return new Response(body, {
|
|
49
|
+
status,
|
|
50
|
+
headers: extraHeaders ? {
|
|
51
|
+
...base,
|
|
52
|
+
...extraHeaders
|
|
53
|
+
} : base
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
return async function handle(req) {
|
|
57
|
+
const url = new URL(req.url);
|
|
58
|
+
const key = `${req.method.toUpperCase()} ${url.pathname}`;
|
|
59
|
+
if (opts.cors && req.method.toUpperCase() === "OPTIONS") {
|
|
60
|
+
const h = corsHeaders(opts.cors === true ? {} : opts.cors);
|
|
61
|
+
return new Response(null, {
|
|
62
|
+
status: 204,
|
|
63
|
+
headers: {
|
|
64
|
+
...h,
|
|
65
|
+
"content-length": "0"
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const route = routeTable.get(key);
|
|
70
|
+
if (!route) {
|
|
71
|
+
const headers = {};
|
|
72
|
+
if (opts.cors) Object.assign(headers, corsHeaders(opts.cors === true ? {} : opts.cors));
|
|
73
|
+
return makeJson(404, {
|
|
74
|
+
error: "NotFound",
|
|
75
|
+
path: url.pathname
|
|
76
|
+
}, headers);
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
let input = {};
|
|
80
|
+
if (route.method === "GET") if (url.searchParams.has("input")) {
|
|
81
|
+
const raw = url.searchParams.get("input");
|
|
82
|
+
input = raw ? JSON.parse(raw) : {};
|
|
83
|
+
} else {
|
|
84
|
+
const obj = {};
|
|
85
|
+
for (const [k, v] of url.searchParams.entries()) obj[k] = v;
|
|
86
|
+
input = obj;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const contentType = req.headers.get("content-type") || "";
|
|
90
|
+
if (contentType.includes("application/json")) input = await req.json();
|
|
91
|
+
else if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
92
|
+
const form = await req.formData();
|
|
93
|
+
input = Object.fromEntries(form.entries());
|
|
94
|
+
} else if (!contentType) input = {};
|
|
95
|
+
else return makeJson(415, {
|
|
96
|
+
error: "UnsupportedMediaType",
|
|
97
|
+
contentType
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const ctx = ctxFactory(req);
|
|
101
|
+
const result = await reg.execute(route.name, route.version, input, ctx);
|
|
102
|
+
const headers = {};
|
|
103
|
+
if (opts.cors) Object.assign(headers, corsHeaders(opts.cors === true ? {} : opts.cors));
|
|
104
|
+
return makeJson(200, result, headers);
|
|
105
|
+
} catch (err) {
|
|
106
|
+
if (opts.onError) {
|
|
107
|
+
const mapped = opts.onError(err);
|
|
108
|
+
const headers$1 = {};
|
|
109
|
+
if (opts.cors) Object.assign(headers$1, corsHeaders(opts.cors === true ? {} : opts.cors));
|
|
110
|
+
return makeJson(mapped.status, mapped.body, headers$1);
|
|
111
|
+
}
|
|
112
|
+
const headers = {};
|
|
113
|
+
if (opts.cors) Object.assign(headers, corsHeaders(opts.cors === true ? {} : opts.cors));
|
|
114
|
+
if (err?.issues) return makeJson(400, {
|
|
115
|
+
error: "ValidationError",
|
|
116
|
+
issues: err.issues
|
|
117
|
+
}, headers);
|
|
118
|
+
if (typeof err?.message === "string" && err.message.startsWith("PolicyDenied")) return makeJson(403, { error: "PolicyDenied" }, headers);
|
|
119
|
+
return makeJson(500, { error: "InternalError" }, headers);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
//#endregion
|
|
125
|
+
export { createFetchHandler };
|
|
@@ -1 +1,38 @@
|
|
|
1
|
-
import{createFetchHandler
|
|
1
|
+
import { createFetchHandler } from "./rest-generic.js";
|
|
2
|
+
|
|
3
|
+
//#region src/server/rest-next-app.ts
|
|
4
|
+
/**
|
|
5
|
+
* Creates a Next.js App Router route handler for ContractSpec operations.
|
|
6
|
+
*
|
|
7
|
+
* This function returns a handler suitable for `export const { GET, POST }` in a `route.ts` file.
|
|
8
|
+
* It handles:
|
|
9
|
+
* - Path parsing to determine the operation name and version.
|
|
10
|
+
* - Body parsing (JSON).
|
|
11
|
+
* - Context creation via `ctxFactory`.
|
|
12
|
+
* - Execution via `SpecRegistry`.
|
|
13
|
+
* - Response formatting (JSON success/error).
|
|
14
|
+
*
|
|
15
|
+
* @param reg - The SpecRegistry containing the operations.
|
|
16
|
+
* @param ctxFactory - A factory function to build the `HandlerCtx` (e.g., auth, tenant) from the request.
|
|
17
|
+
* @param options - Optional configuration for the REST handler.
|
|
18
|
+
* @returns A function `(req: Request) => Promise<Response>`.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* // app/api/[...route]/route.ts
|
|
23
|
+
* import { makeNextAppHandler } from '@lssm/lib.contracts/server/rest-next-app';
|
|
24
|
+
* import { registry } from '@/lib/registry';
|
|
25
|
+
*
|
|
26
|
+
* const handler = makeNextAppHandler(registry, (req) => ({ actor: 'anonymous' }));
|
|
27
|
+
* export { handler as GET, handler as POST };
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
function makeNextAppHandler(reg, ctxFactory, options) {
|
|
31
|
+
const handler = createFetchHandler(reg, ctxFactory, options);
|
|
32
|
+
return async function requestHandler(req) {
|
|
33
|
+
return handler(req);
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { makeNextAppHandler };
|
|
@@ -1 +1,45 @@
|
|
|
1
|
-
import{defaultMcpTool
|
|
1
|
+
import { defaultMcpTool, jsonSchemaForSpec } from "../jsonschema.js";
|
|
2
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { createMcpHandler } from "mcp-handler";
|
|
4
|
+
|
|
5
|
+
//#region src/server/rest-next-mcp.ts
|
|
6
|
+
function makeNextMcpServerFromRegistry(reg, ctxFactory) {
|
|
7
|
+
const handler = createMcpHandler((server) => {
|
|
8
|
+
for (const spec of reg.listSpecs()) {
|
|
9
|
+
const { input, output, meta } = jsonSchemaForSpec(spec);
|
|
10
|
+
if (meta.kind === "query") {
|
|
11
|
+
const resourceName = spec.transport?.mcp?.toolName ?? defaultMcpTool(spec.meta.name, spec.meta.version);
|
|
12
|
+
server.registerResource(resourceName, new ResourceTemplate("users://{userId}/profile", { list: void 0 }), {
|
|
13
|
+
description: spec.meta.description,
|
|
14
|
+
inputSchema: input
|
|
15
|
+
}, (async (uri, args, _req) => {
|
|
16
|
+
const result = await reg.execute(spec.meta.name, spec.meta.version, args ?? {}, ctxFactory());
|
|
17
|
+
return { contents: [{
|
|
18
|
+
uri: uri.href,
|
|
19
|
+
text: String(result)
|
|
20
|
+
}] };
|
|
21
|
+
}));
|
|
22
|
+
} else if (meta.kind === "command") {
|
|
23
|
+
const toolName = spec.transport?.mcp?.toolName ?? defaultMcpTool(spec.meta.name, spec.meta.version);
|
|
24
|
+
server.registerTool(toolName, {
|
|
25
|
+
description: spec.meta.description,
|
|
26
|
+
inputSchema: input
|
|
27
|
+
}, (async (args, _req) => {
|
|
28
|
+
const result = await reg.execute(spec.meta.name, spec.meta.version, args ?? {}, ctxFactory());
|
|
29
|
+
return { content: [{
|
|
30
|
+
type: "text",
|
|
31
|
+
text: String(result)
|
|
32
|
+
}] };
|
|
33
|
+
}));
|
|
34
|
+
} else throw new Error(`Unsupported kind: ${meta.kind}`);
|
|
35
|
+
}
|
|
36
|
+
}, {}, { basePath: "/api" });
|
|
37
|
+
return {
|
|
38
|
+
GET: handler,
|
|
39
|
+
POST: handler,
|
|
40
|
+
DELETE: handler
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
//#endregion
|
|
45
|
+
export { makeNextMcpServerFromRegistry };
|
|
@@ -1 +1,25 @@
|
|
|
1
|
-
import{createFetchHandler
|
|
1
|
+
import { createFetchHandler } from "./rest-generic.js";
|
|
2
|
+
|
|
3
|
+
//#region src/server/rest-next-pages.ts
|
|
4
|
+
function makeNextPagesHandler(reg, ctxFactory, options) {
|
|
5
|
+
createFetchHandler(reg, (_req) => {
|
|
6
|
+
throw new Error("Use per-request wrapper");
|
|
7
|
+
}, options);
|
|
8
|
+
return async function handler(req, res) {
|
|
9
|
+
const url = `${req.headers["x-forwarded-proto"] ?? "http"}://${req.headers.host}${req.url}`;
|
|
10
|
+
const method = req.method?.toUpperCase() || "GET";
|
|
11
|
+
const request = new Request(url, {
|
|
12
|
+
method,
|
|
13
|
+
headers: Object.fromEntries(Object.entries(req.headers).map(([k, v]) => [k, String(v)])),
|
|
14
|
+
body: method === "POST" ? JSON.stringify(req.body ?? {}) : void 0
|
|
15
|
+
});
|
|
16
|
+
const response = await createFetchHandler(reg, () => ctxFactory(req), options)(request);
|
|
17
|
+
res.status(response.status);
|
|
18
|
+
response.headers.forEach((v, k) => res.setHeader(k, v));
|
|
19
|
+
const text = await response.text();
|
|
20
|
+
res.send(text);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
export { makeNextPagesHandler };
|
package/dist/spec.js
CHANGED
|
@@ -1 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/spec.ts
|
|
2
|
+
const isEmitDeclRef = (e) => "ref" in e;
|
|
3
|
+
/**
|
|
4
|
+
* Helper to define a Command (write operation).
|
|
5
|
+
* Sets `kind: 'command'` and defaults `idempotent: false`.
|
|
6
|
+
*/
|
|
7
|
+
const defineCommand = (spec) => ({
|
|
8
|
+
...spec,
|
|
9
|
+
meta: {
|
|
10
|
+
...spec.meta,
|
|
11
|
+
kind: "command"
|
|
12
|
+
},
|
|
13
|
+
policy: {
|
|
14
|
+
...spec.policy,
|
|
15
|
+
idempotent: spec.policy?.["policy"]?.idempotent ?? false
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Helper to define a Query (read-only operation).
|
|
20
|
+
* Sets `kind: 'query'` and forces `idempotent: true`.
|
|
21
|
+
*/
|
|
22
|
+
const defineQuery = (spec) => ({
|
|
23
|
+
...spec,
|
|
24
|
+
meta: {
|
|
25
|
+
...spec.meta,
|
|
26
|
+
kind: "query"
|
|
27
|
+
},
|
|
28
|
+
policy: {
|
|
29
|
+
...spec.policy,
|
|
30
|
+
idempotent: true
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { defineCommand, defineQuery, isEmitDeclRef };
|