@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.
Files changed (239) hide show
  1. package/dist/app-config/app-config.feature.js +53 -1
  2. package/dist/app-config/contracts.d.ts +50 -50
  3. package/dist/app-config/contracts.js +396 -1
  4. package/dist/app-config/docs/app-config.docblock.js +22 -220
  5. package/dist/app-config/events.d.ts +27 -27
  6. package/dist/app-config/events.js +168 -1
  7. package/dist/app-config/index.js +8 -1
  8. package/dist/app-config/lifecycle-contracts.d.ts +80 -80
  9. package/dist/app-config/lifecycle-contracts.js +441 -1
  10. package/dist/app-config/runtime.js +617 -1
  11. package/dist/app-config/spec.js +36 -1
  12. package/dist/app-config/validation.js +538 -1
  13. package/dist/capabilities/docs/capabilities.docblock.js +22 -1
  14. package/dist/capabilities/openbanking.js +92 -1
  15. package/dist/capabilities.js +50 -1
  16. package/dist/client/index.js +9 -1
  17. package/dist/client/react/drivers/rn-reusables.js +21 -1
  18. package/dist/client/react/drivers/shadcn.js +11 -1
  19. package/dist/client/react/feature-render.js +43 -1
  20. package/dist/client/react/form-render.js +298 -1
  21. package/dist/client/react/index.js +8 -1
  22. package/dist/contract-registry/index.js +3 -1
  23. package/dist/contract-registry/schemas.js +61 -1
  24. package/dist/contracts-adapter-hydration.js +41 -1
  25. package/dist/contracts-adapter-input.js +77 -1
  26. package/dist/data-views/docs/data-views.docblock.js +22 -1
  27. package/dist/data-views/query-generator.js +48 -1
  28. package/dist/data-views/runtime.js +39 -1
  29. package/dist/data-views.js +35 -1
  30. package/dist/docs/PUBLISHING.docblock.js +17 -76
  31. package/dist/docs/accessibility_wcag_compliance_specs.docblock.js +17 -350
  32. package/dist/docs/index.js +33 -1
  33. package/dist/docs/meta.docs.js +15 -2
  34. package/dist/docs/presentations.js +77 -1
  35. package/dist/docs/registry.js +51 -1
  36. package/dist/docs/tech/PHASE_1_QUICKSTART.docblock.js +17 -383
  37. package/dist/docs/tech/PHASE_2_AI_NATIVE_OPERATIONS.docblock.js +17 -68
  38. package/dist/docs/tech/PHASE_3_AUTO_EVOLUTION.docblock.js +17 -140
  39. package/dist/docs/tech/PHASE_4_PERSONALIZATION_ENGINE.docblock.js +17 -86
  40. package/dist/docs/tech/PHASE_5_ZERO_TOUCH_OPERATIONS.docblock.js +17 -1
  41. package/dist/docs/tech/auth/better-auth-nextjs.docblock.js +25 -2
  42. package/dist/docs/tech/contracts/README.docblock.js +21 -1
  43. package/dist/docs/tech/contracts/create-subscription.docblock.js +21 -1
  44. package/dist/docs/tech/contracts/graphql-typed-outputs.docblock.js +21 -180
  45. package/dist/docs/tech/contracts/migrations.docblock.js +21 -1
  46. package/dist/docs/tech/contracts/openapi-export.docblock.js +22 -2
  47. package/dist/docs/tech/contracts/ops-to-presentation-linking.docblock.js +19 -60
  48. package/dist/docs/tech/contracts/overlays.docblock.js +21 -68
  49. package/dist/docs/tech/contracts/tests.docblock.js +21 -132
  50. package/dist/docs/tech/contracts/themes.docblock.js +21 -1
  51. package/dist/docs/tech/contracts/vertical-pocket-family-office.docblock.js +21 -106
  52. package/dist/docs/tech/lifecycle-stage-system.docblock.js +17 -213
  53. package/dist/docs/tech/llm/llm-integration.docblock.js +74 -5
  54. package/dist/docs/tech/mcp-endpoints.docblock.js +38 -1
  55. package/dist/docs/tech/presentation-runtime.docblock.js +17 -1
  56. package/dist/docs/tech/schema/README.docblock.js +21 -262
  57. package/dist/docs/tech/studio/learning-events.docblock.js +49 -1
  58. package/dist/docs/tech/studio/learning-journeys.docblock.js +25 -2
  59. package/dist/docs/tech/studio/platform-admin-panel.docblock.js +24 -2
  60. package/dist/docs/tech/studio/project-access-teams.docblock.js +26 -16
  61. package/dist/docs/tech/studio/project-routing.docblock.js +68 -1
  62. package/dist/docs/tech/studio/sandbox-unlogged.docblock.js +23 -2
  63. package/dist/docs/tech/studio/team-invitations.docblock.js +41 -36
  64. package/dist/docs/tech/studio/workspace-ops.docblock.js +48 -1
  65. package/dist/docs/tech/studio/workspaces.docblock.js +24 -2
  66. package/dist/docs/tech/telemetry-ingest.docblock.js +37 -3
  67. package/dist/docs/tech/templates/runtime.docblock.js +21 -1
  68. package/dist/docs/tech/vscode-extension.docblock.js +37 -3
  69. package/dist/docs/tech/workflows/overview.docblock.js +21 -1
  70. package/dist/docs/tech-contracts.docs.js +19 -2
  71. package/dist/events.js +12 -1
  72. package/dist/experiments/docs/experiments.docblock.js +22 -128
  73. package/dist/experiments/evaluator.js +101 -1
  74. package/dist/experiments/spec.js +33 -1
  75. package/dist/features.js +68 -1
  76. package/dist/forms/docs/forms.docblock.js +22 -1
  77. package/dist/forms.js +119 -1
  78. package/dist/index.js +107 -1
  79. package/dist/install.js +40 -1
  80. package/dist/integrations/contracts.d.ts +102 -102
  81. package/dist/integrations/contracts.js +388 -1
  82. package/dist/integrations/docs/integrations.docblock.js +95 -1
  83. package/dist/integrations/health.js +69 -1
  84. package/dist/integrations/index.js +23 -1
  85. package/dist/integrations/openbanking/contracts/accounts.d.ts +66 -66
  86. package/dist/integrations/openbanking/contracts/accounts.js +237 -1
  87. package/dist/integrations/openbanking/contracts/balances.d.ts +34 -34
  88. package/dist/integrations/openbanking/contracts/balances.js +167 -1
  89. package/dist/integrations/openbanking/contracts/index.js +12 -1
  90. package/dist/integrations/openbanking/contracts/transactions.d.ts +48 -48
  91. package/dist/integrations/openbanking/contracts/transactions.js +218 -1
  92. package/dist/integrations/openbanking/guards.js +32 -1
  93. package/dist/integrations/openbanking/models.d.ts +55 -55
  94. package/dist/integrations/openbanking/models.js +242 -1
  95. package/dist/integrations/openbanking/openbanking.feature.js +68 -1
  96. package/dist/integrations/openbanking/telemetry.js +39 -1
  97. package/dist/integrations/providers/elevenlabs.js +56 -1
  98. package/dist/integrations/providers/gcs-storage.js +79 -1
  99. package/dist/integrations/providers/gmail.js +91 -1
  100. package/dist/integrations/providers/google-calendar.js +70 -1
  101. package/dist/integrations/providers/impls/elevenlabs-voice.js +95 -1
  102. package/dist/integrations/providers/impls/gcs-storage.js +88 -1
  103. package/dist/integrations/providers/impls/gmail-inbound.js +200 -1
  104. package/dist/integrations/providers/impls/gmail-outbound.js +104 -5
  105. package/dist/integrations/providers/impls/google-calendar.js +154 -1
  106. package/dist/integrations/providers/impls/index.js +16 -1
  107. package/dist/integrations/providers/impls/mistral-embedding.js +41 -1
  108. package/dist/integrations/providers/impls/mistral-llm.js +247 -1
  109. package/dist/integrations/providers/impls/postmark-email.js +55 -1
  110. package/dist/integrations/providers/impls/powens-client.js +171 -1
  111. package/dist/integrations/providers/impls/powens-openbanking.js +218 -1
  112. package/dist/integrations/providers/impls/provider-factory.js +142 -1
  113. package/dist/integrations/providers/impls/qdrant-vector.js +69 -1
  114. package/dist/integrations/providers/impls/stripe-payments.js +202 -1
  115. package/dist/integrations/providers/impls/twilio-sms.js +58 -1
  116. package/dist/integrations/providers/index.js +13 -1
  117. package/dist/integrations/providers/mistral.js +72 -1
  118. package/dist/integrations/providers/postmark.js +72 -1
  119. package/dist/integrations/providers/powens.js +120 -1
  120. package/dist/integrations/providers/qdrant.js +77 -1
  121. package/dist/integrations/providers/registry.js +34 -1
  122. package/dist/integrations/providers/stripe.js +87 -1
  123. package/dist/integrations/providers/twilio-sms.js +65 -1
  124. package/dist/integrations/runtime.js +186 -1
  125. package/dist/integrations/secrets/aws-secret-manager.js +231 -1
  126. package/dist/integrations/secrets/env-secret-provider.js +81 -1
  127. package/dist/integrations/secrets/gcp-secret-manager.js +229 -1
  128. package/dist/integrations/secrets/index.js +8 -1
  129. package/dist/integrations/secrets/manager.js +103 -1
  130. package/dist/integrations/secrets/provider.js +58 -1
  131. package/dist/integrations/secrets/scaleway-secret-manager.js +247 -1
  132. package/dist/integrations/spec.js +39 -1
  133. package/dist/jobs/define-job.js +16 -1
  134. package/dist/jobs/gcp-cloud-tasks.js +53 -1
  135. package/dist/jobs/gcp-pubsub.js +39 -1
  136. package/dist/jobs/handlers/gmail-sync-handler.js +9 -1
  137. package/dist/jobs/handlers/index.js +12 -1
  138. package/dist/jobs/handlers/ping-handler.js +15 -1
  139. package/dist/jobs/handlers/storage-document-handler.js +14 -1
  140. package/dist/jobs/index.js +4 -1
  141. package/dist/jobs/memory-queue.js +71 -1
  142. package/dist/jobs/queue.js +33 -1
  143. package/dist/jobs/scaleway-sqs-queue.js +153 -1
  144. package/dist/jsonschema.d.ts +3 -3
  145. package/dist/jsonschema.js +32 -1
  146. package/dist/knowledge/contracts.d.ts +66 -66
  147. package/dist/knowledge/contracts.js +317 -1
  148. package/dist/knowledge/docs/knowledge.docblock.js +22 -138
  149. package/dist/knowledge/index.js +10 -1
  150. package/dist/knowledge/ingestion/document-processor.js +54 -1
  151. package/dist/knowledge/ingestion/embedding-service.js +25 -1
  152. package/dist/knowledge/ingestion/gmail-adapter.js +50 -5
  153. package/dist/knowledge/ingestion/index.js +7 -1
  154. package/dist/knowledge/ingestion/storage-adapter.js +26 -1
  155. package/dist/knowledge/ingestion/vector-indexer.js +32 -1
  156. package/dist/knowledge/query/index.js +3 -1
  157. package/dist/knowledge/query/service.js +64 -2
  158. package/dist/knowledge/runtime.js +49 -1
  159. package/dist/knowledge/spaces/email-threads.js +38 -1
  160. package/dist/knowledge/spaces/financial-docs.js +38 -1
  161. package/dist/knowledge/spaces/financial-overview.js +42 -1
  162. package/dist/knowledge/spaces/index.js +8 -1
  163. package/dist/knowledge/spaces/product-canon.js +38 -1
  164. package/dist/knowledge/spaces/support-faq.js +41 -1
  165. package/dist/knowledge/spaces/uploaded-docs.js +38 -1
  166. package/dist/knowledge/spec.js +39 -1
  167. package/dist/llm/exporters.js +541 -8
  168. package/dist/llm/index.js +4 -1
  169. package/dist/llm/prompts.js +246 -56
  170. package/dist/markdown.js +116 -3
  171. package/dist/migrations.js +33 -1
  172. package/dist/onboarding-base.d.ts +29 -29
  173. package/dist/onboarding-base.js +196 -1
  174. package/dist/openapi.js +75 -1
  175. package/dist/openbanking/docs/openbanking.docblock.js +22 -109
  176. package/dist/ownership.js +40 -1
  177. package/dist/policy/docs/policy.docblock.js +22 -1
  178. package/dist/policy/engine.js +223 -1
  179. package/dist/policy/opa-adapter.js +71 -1
  180. package/dist/policy/spec.js +33 -1
  181. package/dist/presentations/docs/presentations-conventions.docblock.js +21 -7
  182. package/dist/presentations.backcompat.js +47 -1
  183. package/dist/presentations.d.ts +3 -3
  184. package/dist/presentations.js +66 -1
  185. package/dist/presentations.v2.js +278 -6
  186. package/dist/prompt.js +10 -1
  187. package/dist/promptRegistry.js +34 -1
  188. package/dist/regenerator/docs/regenerator.docblock.js +22 -184
  189. package/dist/regenerator/executor.js +86 -1
  190. package/dist/regenerator/index.js +6 -1
  191. package/dist/regenerator/service.js +92 -1
  192. package/dist/regenerator/sinks.js +32 -1
  193. package/dist/regenerator/utils.js +51 -1
  194. package/dist/registry.js +208 -1
  195. package/dist/resources.js +47 -1
  196. package/dist/schema/dist/EnumType.js +2 -1
  197. package/dist/schema/dist/FieldType.js +49 -1
  198. package/dist/schema/dist/ScalarTypeEnum.js +236 -1
  199. package/dist/schema/dist/SchemaModel.js +39 -1
  200. package/dist/schema/dist/entity/defineEntity.js +1 -1
  201. package/dist/schema/dist/entity/index.js +2 -1
  202. package/dist/schema/dist/entity/types.js +1 -1
  203. package/dist/schema/dist/index.js +6 -1
  204. package/dist/schema-to-markdown.js +214 -10
  205. package/dist/server/graphql-pothos.js +128 -1
  206. package/dist/server/index.js +10 -1
  207. package/dist/server/mcp/createMcpServer.js +28 -1
  208. package/dist/server/mcp/registerPresentations.js +151 -1
  209. package/dist/server/mcp/registerPrompts.js +36 -2
  210. package/dist/server/mcp/registerResources.js +35 -1
  211. package/dist/server/mcp/registerTools.js +22 -1
  212. package/dist/server/provider-mcp.js +3 -1
  213. package/dist/server/rest-elysia.js +20 -1
  214. package/dist/server/rest-express.js +39 -1
  215. package/dist/server/rest-generic.js +125 -1
  216. package/dist/server/rest-next-app.js +38 -1
  217. package/dist/server/rest-next-mcp.js +45 -1
  218. package/dist/server/rest-next-pages.js +25 -1
  219. package/dist/spec.js +35 -1
  220. package/dist/telemetry/anomaly.js +48 -1
  221. package/dist/telemetry/docs/telemetry.docblock.js +22 -139
  222. package/dist/telemetry/index.js +5 -1
  223. package/dist/telemetry/spec.js +69 -1
  224. package/dist/telemetry/tracker.js +76 -1
  225. package/dist/tests/index.js +4 -1
  226. package/dist/tests/runner.js +150 -1
  227. package/dist/tests/spec.js +33 -1
  228. package/dist/themes.js +39 -1
  229. package/dist/workflow/adapters/db-adapter.js +83 -1
  230. package/dist/workflow/adapters/file-adapter.js +11 -1
  231. package/dist/workflow/adapters/index.js +5 -1
  232. package/dist/workflow/adapters/memory-store.js +58 -1
  233. package/dist/workflow/expression.js +98 -1
  234. package/dist/workflow/index.js +9 -1
  235. package/dist/workflow/runner.js +337 -1
  236. package/dist/workflow/sla-monitor.js +47 -1
  237. package/dist/workflow/spec.js +32 -1
  238. package/dist/workflow/validation.js +175 -1
  239. package/package.json +11 -4
@@ -1 +1,10 @@
1
- import{registerContractsOnBuilder as e}from"./graphql-pothos.js";import{createMcpServer as t}from"./mcp/createMcpServer.js";import"./provider-mcp.js";import{createFetchHandler as n}from"./rest-generic.js";import{elysiaPlugin as r}from"./rest-elysia.js";import{expressRouter as i}from"./rest-express.js";import{makeNextAppHandler as a}from"./rest-next-app.js";import{makeNextPagesHandler as o}from"./rest-next-pages.js";export{n as createFetchHandler,t as createMcpServer,r as elysiaPlugin,i as expressRouter,a as makeNextAppHandler,o as makeNextPagesHandler,e as registerContractsOnBuilder};
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{registerMcpTools as e}from"./registerTools.js";import{registerMcpResources as t}from"./registerResources.js";import{registerMcpPrompts as n}from"./registerPrompts.js";import{registerMcpPresentations as r}from"./registerPresentations.js";function i(i,a,o,s,c){return c.logger.info(`Creating MCP server`),e(i,a,{toolCtx:c.toolCtx}),t(i,o,{logger:c.logger,resourceCtx:c.resourceCtx}),r(i,{logger:c.logger,presentations:c.presentations,presentationsV2:c.presentationsV2}),n(i,s,{promptCtx:c.promptCtx}),i}export{i as createMcpServer};
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 as e,registerBasicValidation as t,registerDefaultReactRenderer as n}from"../../presentations.v2.js";import{jsonSchemaForPresentation as r}from"../../presentations.js";function i(e){return!e||typeof e!=`object`?!1:`body`in e&&typeof e.body==`string`}function a(a,o){let s=o.presentations,c=o.presentationsV2;if(s)for(let e of s.list()){let t=`presentation.${e.meta.name.replace(/\./g,`_`)}.v${e.meta.version}`,n=`presentation://${e.meta.name}/v${e.meta.version}`;a.registerResource(t,n,{title:`${e.meta.name} v${e.meta.version}`,description:e.meta.description??`Presentation`},async()=>{if(e.content.kind===`markdown`)return{contents:[{uri:n,mimeType:`text/markdown`,text:e.content.content?e.content.content:`See resource: ${e.content.resourceUri??``}`}]};if(e.content.kind===`data`){let t=r(e);return{contents:[{uri:n,mimeType:`application/json`,text:JSON.stringify(t,null,2)}]}}let t={name:e.meta.name,version:e.meta.version,kind:e.content.kind,description:e.meta.description??``};return{contents:[{uri:n,mimeType:`application/json`,text:JSON.stringify(t,null,2)}]}});for(let i of[{ext:`.md`,target:`markdown`},{ext:`.json`,target:`application/json`},{ext:`.xml`,target:`application/xml`}]){let s=`${t}${i.ext}`,c=`${n}${i.ext}`;o.logger.info(`Registering presentation resource ${c} for ${s}`),a.registerResource(s,c,{title:`${e.meta.name} v${e.meta.version} (${i.ext})`,description:`${e.meta.description??`Presentation`} (${i.ext})`},async()=>{if(e.content.kind===`markdown`&&i.target===`markdown`)return{contents:[{uri:c,mimeType:`text/markdown`,text:e.content.content??`See resource: ${e.content.resourceUri??``}`}]};if(e.content.kind===`data`&&i.target===`application/json`)return{contents:[{uri:c,mimeType:`application/json`,text:JSON.stringify(r(e),null,2)}]};let t=JSON.stringify({meta:e.meta,content:e.content},null,2);return i.target===`application/json`?{contents:[{uri:c,mimeType:`application/json`,text:t}]}:i.target===`application/xml`?{contents:[{uri:c,mimeType:`application/xml`,text:`<presentation name="${e.meta.name}" version="${e.meta.version}"><json>${encodeURIComponent(t)}</json></presentation>`}]}:{contents:[{uri:c,mimeType:`text/markdown`,text:`Unsupported presentation for markdown`}]}})}}if(c&&c.length){let r=t(n(e()));for(let e of c){let t=`presentation.${e.meta.name.replace(/\./g,`_`)}.v${e.meta.version}`,n=`presentation://${e.meta.name}/v${e.meta.version}`;o.logger.info(`Registering presentation descriptor ${n} for ${t}`),a.registerResource(t,n,{title:`${e.meta.name} v${e.meta.version}`,description:e.meta.description??`Presentation`,mimeType:`application/json`},async()=>({contents:[{uri:n,mimeType:`application/json`,text:JSON.stringify({meta:e.meta,source:e.source,targets:e.targets},null,2)}]}));for(let o of[{ext:`.md`,target:`markdown`},{ext:`.json`,target:`application/json`},{ext:`.xml`,target:`application/xml`}]){let s=`${t}${o.ext}`,c=`${n}${o.ext}`;a.registerResource(s,c,{title:`${e.meta.name} v${e.meta.version} (${o.ext})`,description:`${e.meta.description??`Presentation`} (${o.ext})`},async()=>{let t=await r.render(o.target,e);return{contents:[{uri:c,mimeType:i(t)&&t.mimeType?t.mimeType:o.target===`markdown`?`text/markdown`:o.target,text:i(t)&&typeof t.body==`string`?t.body:String(t)}]}})}}}}export{a as registerMcpPresentations};
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 e from"zod";function t(e){let t={};for(let n of e)t[n.name]=n.schema;return t}function n(e,n,r){for(let i of n.list())e.registerPrompt(i.meta.name,{title:i.meta.title,description:i.meta.description,argsSchema:t(i.args)},async e=>{let t=(e,t)=>{let n=e;for(let[e,r]of Object.entries(t))n=n.replace(RegExp(`\\{${e}\\}`,`g`),encodeURIComponent(String(r)));return n};return{messages:[{role:`assistant`,content:{type:`text`,text:(await i.render(i.input.parse(e),{...r.promptCtx(),link:t})).map(e=>e.type===`text`?e.text:`See resource: ${e.title??e.uri}\nURI: ${e.uri}`).join(`
1
+ import z from "zod";
2
2
 
3
- `)}}],description:i.meta.description}})}export{n as registerMcpPrompts};
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 as e}from"@modelcontextprotocol/sdk/server/mcp.js";import{Buffer as t}from"node:buffer";function n(e){return{title:e.meta.title,description:e.meta.description,mimeType:e.meta.mimeType,_meta:{tags:e.meta.tags??[]}}}function r(r,i,a){for(let o of i.listTemplates())a.logger.info(`Registering resource: `+o.meta.uriTemplate),r.registerResource(o.meta.uriTemplate,new e(o.meta.uriTemplate,{list:void 0}),n(o),async(e,n)=>{let r=o.input.parse(n),i=await o.resolve(r,a.resourceCtx());return typeof i.data==`string`?{contents:[{uri:i.uri,mimeType:i.mimeType??o.meta.mimeType,text:i.data}]}:{contents:[{uri:i.uri,mimeType:i.mimeType??o.meta.mimeType,blob:t.from(i.data).toString(`base64`)}]}}),a.logger.info(`Registered resource: `+o.meta.uriTemplate)}export{r as registerMcpResources};
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 as e}from"../../jsonschema.js";function t(t,n,r){for(let i of n.listSpecs()){if(i.meta.kind!==`command`)continue;let a=i.transport?.mcp?.toolName??e(i.meta.name,i.meta.version);t.registerTool(a,{description:i.meta.description,inputSchema:i.io.input?.getZod()},async e=>{let t=await n.execute(i.meta.name,i.meta.version,e??{},r.toolCtx());return{content:[{type:`text`,text:JSON.stringify(t,null,4)}]}})}}export{t as registerMcpTools};
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,3 @@
1
- import{createMcpServer as e}from"./mcp/createMcpServer.js";export{e as createMcpServer};
1
+ import { createMcpServer } from "./mcp/createMcpServer.js";
2
+
3
+ export { createMcpServer };
@@ -1 +1,20 @@
1
- import{createFetchHandler as e}from"./rest-generic.js";function t(t,n,r,i){let a=e(n,e=>r({request:e,store:t.store}),i);for(let e of n.listSpecs()){let n=e.transport?.rest?.method??(e.meta.kind===`query`?`GET`:`POST`),r=(i?.basePath??``)+(e.transport?.rest?.path??`/${e.meta.name.replace(/\./g,`/`)}/v${e.meta.version}`);t[n.toLowerCase()](r,({request:e})=>a(e))}return i?.cors&&t.options(`*`,({request:e})=>a(e)),t}export{t as elysiaPlugin};
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 as e}from"./rest-generic.js";function t(t,n,r,i){let a=t.Router();e(n,e=>{throw Error(`ctxFactory must be called from route`)},i);for(let t of n.listSpecs()){let o=t.transport?.rest?.method??(t.meta.kind===`query`?`GET`:`POST`),s=(i?.basePath??``)+(t.transport?.rest?.path??`/${t.meta.name.replace(/\./g,`/`)}/v${t.meta.version}`);a[o.toLowerCase()](s,async(t,a)=>{let s=new URL(`${t.protocol}://${t.get(`host`)}${t.originalUrl}`),c=new Request(s.toString(),{method:o,headers:Object.fromEntries(Object.entries(t.headers).map(([e,t])=>[e,String(t)])),body:o===`POST`?JSON.stringify(t.body??{}):void 0}),l=await e(n,()=>r(t),i)(c);a.status(l.status),l.headers.forEach((e,t)=>a.setHeader(t,e));let u=await l.text();a.send(u)})}return i?.cors&&a.options(`*`,(e,t)=>{let n=new Headers;new Response(null,{status:204}).headers.forEach((e,t)=>n.set(t,e)),t.status(204).send()}),a}export{t as expressRouter};
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 as e}from"../jsonschema.js";function t(e){let t={};return t[`access-control-allow-origin`]=typeof e==`object`?e.origin??`*`:`*`,t.vary=`Origin`,typeof e==`object`?(e.methods&&(t[`access-control-allow-methods`]=e.methods.join(`, `)),e.headers&&(t[`access-control-allow-headers`]=e.headers.join(`, `)),e.credentials&&(t[`access-control-allow-credentials`]=`true`),typeof e.maxAge==`number`&&(t[`access-control-max-age`]=String(e.maxAge))):(t[`access-control-allow-methods`]=`GET,POST,OPTIONS`,t[`access-control-allow-headers`]=`content-type,x-idempotency-key,x-trace-id`),t}function n(e,t){return`${(e??``).replace(/\/+$/g,``)}/${t.replace(/^\/+/g,``)}`.replace(/\/{2,}/g,`/`)}function r(r,i,a){let o={basePath:a?.basePath??``,cors:a?.cors??!1,prettyJson:a?.prettyJson??!1,onError:a?.onError},s=r.listSpecs().map(t=>({method:t.transport?.rest?.method??(t.meta.kind===`query`?`GET`:`POST`),path:n(o.basePath,t.transport?.rest?.path??e(t.meta.name,t.meta.version)),name:t.meta.name,version:t.meta.version})),c=new Map;for(let e of s)c.set(`${e.method} ${e.path}`,e);Array.from(new Set(s.map(e=>e.method))).join(`, `);let l=(e,t,n)=>{let r=o.prettyJson?JSON.stringify(t,null,o.prettyJson):JSON.stringify(t),i={"content-type":`application/json; charset=utf-8`};return new Response(r,{status:e,headers:n?{...i,...n}:i})};return async function(e){let n=new URL(e.url),a=`${e.method.toUpperCase()} ${n.pathname}`;if(o.cors&&e.method.toUpperCase()===`OPTIONS`){let e=t(o.cors===!0?{}:o.cors);return new Response(null,{status:204,headers:{...e,"content-length":`0`}})}let s=c.get(a);if(!s){let e={};return o.cors&&Object.assign(e,t(o.cors===!0?{}:o.cors)),l(404,{error:`NotFound`,path:n.pathname},e)}try{let a={};if(s.method===`GET`)if(n.searchParams.has(`input`)){let e=n.searchParams.get(`input`);a=e?JSON.parse(e):{}}else{let e={};for(let[t,r]of n.searchParams.entries())e[t]=r;a=e}else{let t=e.headers.get(`content-type`)||``;if(t.includes(`application/json`))a=await e.json();else if(t.includes(`application/x-www-form-urlencoded`)){let t=await e.formData();a=Object.fromEntries(t.entries())}else if(!t)a={};else return l(415,{error:`UnsupportedMediaType`,contentType:t})}let c=i(e),u=await r.execute(s.name,s.version,a,c),d={};return o.cors&&Object.assign(d,t(o.cors===!0?{}:o.cors)),l(200,u,d)}catch(e){if(o.onError){let n=o.onError(e),r={};return o.cors&&Object.assign(r,t(o.cors===!0?{}:o.cors)),l(n.status,n.body,r)}let n={};return o.cors&&Object.assign(n,t(o.cors===!0?{}:o.cors)),e?.issues?l(400,{error:`ValidationError`,issues:e.issues},n):typeof e?.message==`string`&&e.message.startsWith(`PolicyDenied`)?l(403,{error:`PolicyDenied`},n):l(500,{error:`InternalError`},n)}}}export{r as createFetchHandler};
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 as e}from"./rest-generic.js";function t(t,n,r){let i=e(t,n,r);return async function(e){return i(e)}}export{t as makeNextAppHandler};
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 as e,jsonSchemaForSpec as t}from"../jsonschema.js";import{ResourceTemplate as n}from"@modelcontextprotocol/sdk/server/mcp.js";import{createMcpHandler as r}from"mcp-handler";function i(i,a){let o=r(r=>{for(let o of i.listSpecs()){let{input:s,output:c,meta:l}=t(o);if(l.kind===`query`){let t=o.transport?.mcp?.toolName??e(o.meta.name,o.meta.version);r.registerResource(t,new n(`users://{userId}/profile`,{list:void 0}),{description:o.meta.description,inputSchema:s},(async(e,t,n)=>{let r=await i.execute(o.meta.name,o.meta.version,t??{},a());return{contents:[{uri:e.href,text:String(r)}]}}))}else if(l.kind===`command`){let t=o.transport?.mcp?.toolName??e(o.meta.name,o.meta.version);r.registerTool(t,{description:o.meta.description,inputSchema:s},(async(e,t)=>{let n=await i.execute(o.meta.name,o.meta.version,e??{},a());return{content:[{type:`text`,text:String(n)}]}}))}else throw Error(`Unsupported kind: ${l.kind}`)}},{},{basePath:`/api`});return{GET:o,POST:o,DELETE:o}}export{i as makeNextMcpServerFromRegistry};
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 as e}from"./rest-generic.js";function t(t,n,r){return e(t,e=>{throw Error(`Use per-request wrapper`)},r),async function(i,a){let o=`${i.headers[`x-forwarded-proto`]??`http`}://${i.headers.host}${i.url}`,s=i.method?.toUpperCase()||`GET`,c=new Request(o,{method:s,headers:Object.fromEntries(Object.entries(i.headers).map(([e,t])=>[e,String(t)])),body:s===`POST`?JSON.stringify(i.body??{}):void 0}),l=await e(t,()=>n(i),r)(c);a.status(l.status),l.headers.forEach((e,t)=>a.setHeader(t,e));let u=await l.text();a.send(u)}}export{t as makeNextPagesHandler};
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
- const e=e=>`ref`in e,t=e=>({...e,meta:{...e.meta,kind:`command`},policy:{...e.policy,idempotent:e.policy?.policy?.idempotent??!1}}),n=e=>({...e,meta:{...e.meta,kind:`query`},policy:{...e.policy,idempotent:!0}});export{t as defineCommand,n as defineQuery,e as isEmitDeclRef};
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 };