@mdsnai/sdk 0.1.0

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 (125) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/cli/args.d.ts +8 -0
  4. package/dist/cli/args.js +63 -0
  5. package/dist/cli/commands/build.d.ts +5 -0
  6. package/dist/cli/commands/build.js +19 -0
  7. package/dist/cli/commands/create.d.ts +2 -0
  8. package/dist/cli/commands/create.js +39 -0
  9. package/dist/cli/commands/dev.d.ts +10 -0
  10. package/dist/cli/commands/dev.js +13 -0
  11. package/dist/cli/commands/start.d.ts +9 -0
  12. package/dist/cli/commands/start.js +13 -0
  13. package/dist/cli/entry.d.ts +2 -0
  14. package/dist/cli/entry.js +8 -0
  15. package/dist/cli/index.d.ts +9 -0
  16. package/dist/cli/index.js +58 -0
  17. package/dist/core/action/execution.d.ts +4 -0
  18. package/dist/core/action/execution.js +57 -0
  19. package/dist/core/action/index.d.ts +2 -0
  20. package/dist/core/action/index.js +7 -0
  21. package/dist/core/action/types.d.ts +19 -0
  22. package/dist/core/action/types.js +2 -0
  23. package/dist/core/document/frontmatter.d.ts +5 -0
  24. package/dist/core/document/frontmatter.js +41 -0
  25. package/dist/core/document/markdown.d.ts +5 -0
  26. package/dist/core/document/markdown.js +83 -0
  27. package/dist/core/document/page-definition.d.ts +2 -0
  28. package/dist/core/document/page-definition.js +24 -0
  29. package/dist/core/index.d.ts +3 -0
  30. package/dist/core/index.js +5 -0
  31. package/dist/core/model/block.d.ts +30 -0
  32. package/dist/core/model/block.js +2 -0
  33. package/dist/core/model/document.d.ts +13 -0
  34. package/dist/core/model/document.js +2 -0
  35. package/dist/core/model/fragment.d.ts +4 -0
  36. package/dist/core/model/fragment.js +2 -0
  37. package/dist/core/model/index.d.ts +5 -0
  38. package/dist/core/model/index.js +2 -0
  39. package/dist/core/model/input.d.ts +11 -0
  40. package/dist/core/model/input.js +2 -0
  41. package/dist/core/model/schema.d.ts +4 -0
  42. package/dist/core/model/schema.js +2 -0
  43. package/dist/core/protocol/mdsn.d.ts +6 -0
  44. package/dist/core/protocol/mdsn.js +80 -0
  45. package/dist/core/protocol/statements.d.ts +12 -0
  46. package/dist/core/protocol/statements.js +140 -0
  47. package/dist/core/protocol/validation.d.ts +4 -0
  48. package/dist/core/protocol/validation.js +60 -0
  49. package/dist/framework/create-framework-app.d.ts +12 -0
  50. package/dist/framework/create-framework-app.js +11 -0
  51. package/dist/framework/hosted-app.d.ts +13 -0
  52. package/dist/framework/hosted-app.js +133 -0
  53. package/dist/framework/index.d.ts +4 -0
  54. package/dist/framework/index.js +7 -0
  55. package/dist/framework/site-app.d.ts +12 -0
  56. package/dist/framework/site-app.js +146 -0
  57. package/dist/index.d.ts +8 -0
  58. package/dist/index.js +18 -0
  59. package/dist/server/action-host.d.ts +3 -0
  60. package/dist/server/action-host.js +8 -0
  61. package/dist/server/action-runtime.d.ts +8 -0
  62. package/dist/server/action-runtime.js +81 -0
  63. package/dist/server/action.d.ts +41 -0
  64. package/dist/server/action.js +97 -0
  65. package/dist/server/build.d.ts +10 -0
  66. package/dist/server/build.js +166 -0
  67. package/dist/server/config.d.ts +56 -0
  68. package/dist/server/config.js +42 -0
  69. package/dist/server/dev.d.ts +48 -0
  70. package/dist/server/dev.js +90 -0
  71. package/dist/server/index.d.ts +8 -0
  72. package/dist/server/index.js +16 -0
  73. package/dist/server/init.d.ts +1 -0
  74. package/dist/server/init.js +176 -0
  75. package/dist/server/layout.d.ts +17 -0
  76. package/dist/server/layout.js +40 -0
  77. package/dist/server/markdown.d.ts +53 -0
  78. package/dist/server/markdown.js +76 -0
  79. package/dist/server/module-loader.d.ts +4 -0
  80. package/dist/server/module-loader.js +71 -0
  81. package/dist/server/negotiate.d.ts +3 -0
  82. package/dist/server/negotiate.js +55 -0
  83. package/dist/server/page-host.d.ts +21 -0
  84. package/dist/server/page-host.js +66 -0
  85. package/dist/server/page-links.d.ts +10 -0
  86. package/dist/server/page-links.js +80 -0
  87. package/dist/server/route-matcher.d.ts +6 -0
  88. package/dist/server/route-matcher.js +73 -0
  89. package/dist/server/routes.d.ts +6 -0
  90. package/dist/server/routes.js +73 -0
  91. package/dist/server/server.d.ts +27 -0
  92. package/dist/server/server.js +152 -0
  93. package/dist/server/site.d.ts +11 -0
  94. package/dist/server/site.js +59 -0
  95. package/dist/server/targets.d.ts +7 -0
  96. package/dist/server/targets.js +21 -0
  97. package/dist/web/block-runtime.d.ts +2 -0
  98. package/dist/web/block-runtime.js +27 -0
  99. package/dist/web/fragment-render.d.ts +10 -0
  100. package/dist/web/fragment-render.js +59 -0
  101. package/dist/web/headless.d.ts +95 -0
  102. package/dist/web/headless.js +370 -0
  103. package/dist/web/i18n.d.ts +31 -0
  104. package/dist/web/i18n.js +69 -0
  105. package/dist/web/index.d.ts +11 -0
  106. package/dist/web/index.js +22 -0
  107. package/dist/web/navigation.d.ts +3 -0
  108. package/dist/web/navigation.js +32 -0
  109. package/dist/web/page-bootstrap.d.ts +6 -0
  110. package/dist/web/page-bootstrap.js +29 -0
  111. package/dist/web/page-client-runtime.d.ts +15 -0
  112. package/dist/web/page-client-runtime.js +22 -0
  113. package/dist/web/page-client-script.d.ts +2 -0
  114. package/dist/web/page-client-script.js +567 -0
  115. package/dist/web/page-html.d.ts +8 -0
  116. package/dist/web/page-html.js +49 -0
  117. package/dist/web/page-render.d.ts +20 -0
  118. package/dist/web/page-render.js +92 -0
  119. package/dist/web/public-client-runtime.d.ts +1 -0
  120. package/dist/web/public-client-runtime.js +5 -0
  121. package/dist/web/public-render.d.ts +12 -0
  122. package/dist/web/public-render.js +18 -0
  123. package/dist/web/target-path.d.ts +1 -0
  124. package/dist/web/target-path.js +35 -0
  125. package/package.json +91 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MDSN Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # @mdsnai/sdk
2
+
3
+ `@mdsnai/sdk` is the reference SDK and runtime for MDSN.
4
+
5
+ MDSN keeps page content and page interaction in the same source by combining a Markdown body with an executable `mdsn` block.
6
+
7
+ ## Why MDSN
8
+
9
+ Plain Markdown is good for content, but weak at expressing interaction.
10
+
11
+ Once a page needs inputs, actions, partial updates, or navigation, that structure usually gets pushed into templates, frontend state, and custom API glue.
12
+
13
+ MDSN makes that interaction layer explicit while keeping the page source readable for humans, AI agents, and agentic AI systems.
14
+
15
+ ## What This Package Includes
16
+
17
+ - the MDSN parser and core model
18
+ - server helpers for actions and Markdown fragments
19
+ - a built-in framework host and CLI
20
+ - headless web APIs for custom rendering
21
+ - default browser runtime utilities
22
+
23
+ ## Package Entry Points
24
+
25
+ - `@mdsnai/sdk`
26
+ - `@mdsnai/sdk/core`
27
+ - `@mdsnai/sdk/server`
28
+ - `@mdsnai/sdk/web`
29
+ - `@mdsnai/sdk/framework`
30
+ - `@mdsnai/sdk/cli`
31
+
32
+ ## Use Cases
33
+
34
+ - skills apps for non-technical users
35
+ - agent apps that agents can enter and operate directly
36
+ - interactive documents with embedded actions
37
+ - human-agent collaboration on the same page model
38
+ - agentic workflows and AI workflow automation
39
+ - custom hosted interfaces with React, Vue, or your own server stack
40
+
41
+ ## Quick Start
42
+
43
+ ```bash
44
+ npm create mdsn@latest skills-app
45
+ cd skills-app
46
+ npm install
47
+ npm run dev
48
+ ```
49
+
50
+ Open:
51
+
52
+ ```text
53
+ http://localhost:3000/
54
+ ```
55
+
56
+ The starter generates a minimal runnable site with:
57
+
58
+ - `pages/index.md`
59
+ - `server/actions.cjs`
60
+
61
+ ## Docs
62
+
63
+ - [Getting Started](https://docs.mdsn.ai/docs/getting-started)
64
+ - [Framework Development](https://docs.mdsn.ai/docs/site-development)
65
+ - [Server Development](https://docs.mdsn.ai/docs/server-development)
66
+ - [Action Reference](https://docs.mdsn.ai/docs/action-reference)
67
+ - [SDK Reference](https://docs.mdsn.ai/docs/sdk-reference)
@@ -0,0 +1,8 @@
1
+ export type ParsedCliArgs = {
2
+ cwd?: string;
3
+ port?: number;
4
+ positional: string[];
5
+ };
6
+ export declare function parseCliArgs(argv: string[], options: {
7
+ allowPort: boolean;
8
+ }): ParsedCliArgs;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseCliArgs = parseCliArgs;
4
+ function parseCliArgs(argv, options) {
5
+ const parsed = {
6
+ positional: [],
7
+ };
8
+ for (let index = 0; index < argv.length; index += 1) {
9
+ const token = argv[index];
10
+ if (token === "--cwd" || token === "-C") {
11
+ const value = argv[index + 1];
12
+ if (!value || value.startsWith("-")) {
13
+ throw new Error(`Missing value for ${token}`);
14
+ }
15
+ parsed.cwd = value;
16
+ index += 1;
17
+ continue;
18
+ }
19
+ if (token.startsWith("--cwd=")) {
20
+ const value = token.slice("--cwd=".length);
21
+ if (!value) {
22
+ throw new Error("Missing value for --cwd");
23
+ }
24
+ parsed.cwd = value;
25
+ continue;
26
+ }
27
+ if (token === "--port" || token === "-p") {
28
+ if (!options.allowPort) {
29
+ throw new Error("Option --port is only supported by dev/start");
30
+ }
31
+ const value = argv[index + 1];
32
+ if (!value || value.startsWith("-")) {
33
+ throw new Error(`Missing value for ${token}`);
34
+ }
35
+ parsed.port = parsePort(value);
36
+ index += 1;
37
+ continue;
38
+ }
39
+ if (token.startsWith("--port=")) {
40
+ if (!options.allowPort) {
41
+ throw new Error("Option --port is only supported by dev/start");
42
+ }
43
+ const value = token.slice("--port=".length);
44
+ if (!value) {
45
+ throw new Error("Missing value for --port");
46
+ }
47
+ parsed.port = parsePort(value);
48
+ continue;
49
+ }
50
+ if (token.startsWith("-")) {
51
+ throw new Error(`Unknown option: ${token}`);
52
+ }
53
+ parsed.positional.push(token);
54
+ }
55
+ return parsed;
56
+ }
57
+ function parsePort(raw) {
58
+ const numeric = Number(raw);
59
+ if (!Number.isInteger(numeric) || numeric <= 0 || numeric > 65535) {
60
+ throw new Error(`Invalid value for --port: ${raw}`);
61
+ }
62
+ return numeric;
63
+ }
@@ -0,0 +1,5 @@
1
+ export declare function runBuild(options?: {
2
+ cwd?: string;
3
+ positional?: string[];
4
+ log?: (message: string) => void;
5
+ }): Promise<void>;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runBuild = runBuild;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const build_1 = require("../../server/build");
9
+ const server_1 = require("../../server/server");
10
+ async function runBuild(options = {}) {
11
+ if ((options.positional ?? []).length > 0) {
12
+ throw new Error("build does not accept positional arguments");
13
+ }
14
+ const rootDir = node_path_1.default.resolve(options.cwd ?? process.cwd());
15
+ const config = await (0, server_1.loadUserConfig)(rootDir);
16
+ const output = await (0, build_1.buildFrameworkSite)({ rootDir, config });
17
+ const log = options.log ?? console.log;
18
+ log(`MDSN build complete: ${output.outDir}`);
19
+ }
@@ -0,0 +1,2 @@
1
+ import type { ParsedCliArgs } from "../args";
2
+ export declare function runCreate(options?: ParsedCliArgs): Promise<void>;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runCreate = runCreate;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const node_child_process_1 = require("node:child_process");
9
+ const init_1 = require("../../server/init");
10
+ function installStarterDependencies(targetDir) {
11
+ if (process.env.MDSN_CREATE_SKIP_INSTALL === "1") {
12
+ return;
13
+ }
14
+ const command = process.platform === "win32" ? "npm.cmd" : "npm";
15
+ const result = (0, node_child_process_1.spawnSync)(command, ["install"], {
16
+ cwd: targetDir,
17
+ stdio: "inherit",
18
+ env: process.env,
19
+ });
20
+ if (result.error) {
21
+ throw new Error(`Failed to install starter dependencies: ${result.error.message}`);
22
+ }
23
+ if (result.status !== 0) {
24
+ throw new Error(`npm install failed in ${targetDir}`);
25
+ }
26
+ }
27
+ async function runCreate(options = { positional: [] }) {
28
+ if (options.port !== undefined) {
29
+ throw new Error("Option --port is only supported by dev/start");
30
+ }
31
+ if (options.positional.length > 1) {
32
+ throw new Error("create accepts at most one target directory");
33
+ }
34
+ const cwd = node_path_1.default.resolve(options.cwd ?? process.cwd());
35
+ const targetDir = options.positional[0] ?? ".";
36
+ const absoluteTargetDir = node_path_1.default.resolve(cwd, targetDir);
37
+ (0, init_1.createStarterSite)(absoluteTargetDir);
38
+ installStarterDependencies(absoluteTargetDir);
39
+ }
@@ -0,0 +1,10 @@
1
+ import type { CreateFrameworkAppFn, ListenFn, OpenBrowserFn } from "../../server/server";
2
+ export declare function runDev(options?: {
3
+ cwd?: string;
4
+ port?: number;
5
+ positional?: string[];
6
+ createApp?: CreateFrameworkAppFn;
7
+ listen?: ListenFn;
8
+ openBrowser?: OpenBrowserFn;
9
+ log?: (message: string) => void;
10
+ }): Promise<void>;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runDev = runDev;
4
+ const server_1 = require("../../server/server");
5
+ async function runDev(options = {}) {
6
+ if ((options.positional ?? []).length > 0) {
7
+ throw new Error("dev does not accept positional arguments");
8
+ }
9
+ await (0, server_1.startFrameworkServer)({
10
+ ...options,
11
+ mode: "dev",
12
+ });
13
+ }
@@ -0,0 +1,9 @@
1
+ import type { CreateFrameworkAppFn, ListenFn } from "../../server/server";
2
+ export declare function runStart(options?: {
3
+ cwd?: string;
4
+ port?: number;
5
+ positional?: string[];
6
+ createApp?: CreateFrameworkAppFn;
7
+ listen?: ListenFn;
8
+ log?: (message: string) => void;
9
+ }): Promise<void>;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runStart = runStart;
4
+ const server_1 = require("../../server/server");
5
+ async function runStart(options = {}) {
6
+ if ((options.positional ?? []).length > 0) {
7
+ throw new Error("start does not accept positional arguments");
8
+ }
9
+ await (0, server_1.startFrameworkServer)({
10
+ ...options,
11
+ mode: "start",
12
+ });
13
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const index_1 = require("./index");
5
+ (0, index_1.runCli)(process.argv.slice(2)).catch((error) => {
6
+ console.error(error);
7
+ process.exitCode = 1;
8
+ });
@@ -0,0 +1,9 @@
1
+ export { parseCliArgs } from "./args";
2
+ export type { ParsedCliArgs } from "./args";
3
+ export type CliHandlers = {
4
+ create?: (args: string[]) => Promise<void> | void;
5
+ dev?: (args: string[]) => Promise<void> | void;
6
+ build?: (args: string[]) => Promise<void> | void;
7
+ start?: (args: string[]) => Promise<void> | void;
8
+ };
9
+ export declare function runCli(argv: string[], handlers?: CliHandlers): Promise<void>;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseCliArgs = void 0;
4
+ exports.runCli = runCli;
5
+ const build_1 = require("./commands/build");
6
+ const create_1 = require("./commands/create");
7
+ const dev_1 = require("./commands/dev");
8
+ const start_1 = require("./commands/start");
9
+ const args_1 = require("./args");
10
+ var args_2 = require("./args");
11
+ Object.defineProperty(exports, "parseCliArgs", { enumerable: true, get: function () { return args_2.parseCliArgs; } });
12
+ const KNOWN_COMMANDS = ["create", "dev", "build", "start"];
13
+ async function runCli(argv, handlers = {}) {
14
+ const command = argv[0];
15
+ const commandArgs = argv.slice(1);
16
+ switch (command) {
17
+ case "create":
18
+ if (handlers.create) {
19
+ await handlers.create(commandArgs);
20
+ return;
21
+ }
22
+ await (0, create_1.runCreate)((0, args_1.parseCliArgs)(commandArgs, { allowPort: false }));
23
+ return;
24
+ case "dev":
25
+ if (handlers.dev) {
26
+ await handlers.dev(commandArgs);
27
+ return;
28
+ }
29
+ await (0, dev_1.runDev)((0, args_1.parseCliArgs)(commandArgs, { allowPort: true }));
30
+ return;
31
+ case "build":
32
+ if (handlers.build) {
33
+ await handlers.build(commandArgs);
34
+ return;
35
+ }
36
+ await (0, build_1.runBuild)((0, args_1.parseCliArgs)(commandArgs, { allowPort: false }));
37
+ return;
38
+ case "start":
39
+ if (handlers.start) {
40
+ await handlers.start(commandArgs);
41
+ return;
42
+ }
43
+ await (0, start_1.runStart)((0, args_1.parseCliArgs)(commandArgs, { allowPort: true }));
44
+ return;
45
+ default:
46
+ throw new Error(`Unknown command: ${command ?? "(none)"}. Expected one of: ${KNOWN_COMMANDS.join(", ")}`);
47
+ }
48
+ }
49
+ function isDirectExecution() {
50
+ const entry = process.argv[1];
51
+ return typeof entry === "string" && /src[\\/]cli[\\/]index\.ts$/.test(entry);
52
+ }
53
+ if (isDirectExecution()) {
54
+ runCli(process.argv.slice(2)).catch((error) => {
55
+ console.error(error);
56
+ process.exitCode = 1;
57
+ });
58
+ }
@@ -0,0 +1,4 @@
1
+ import type { ActionResult, FragmentActionSuccess, RedirectActionSuccess } from "./types";
2
+ export declare function fragmentActionResult(markdown: string): FragmentActionSuccess;
3
+ export declare function redirectActionResult(location: string): RedirectActionSuccess;
4
+ export declare function normalizeActionResult(value: unknown): ActionResult;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fragmentActionResult = fragmentActionResult;
4
+ exports.redirectActionResult = redirectActionResult;
5
+ exports.normalizeActionResult = normalizeActionResult;
6
+ function isFailure(value) {
7
+ return !!value && typeof value === "object" && value.ok === false;
8
+ }
9
+ function isFragmentSuccess(value) {
10
+ return !!value
11
+ && typeof value === "object"
12
+ && value.ok === true
13
+ && value.kind === "fragment"
14
+ && typeof value.markdown === "string";
15
+ }
16
+ function isRedirectSuccess(value) {
17
+ return !!value
18
+ && typeof value === "object"
19
+ && value.ok === true
20
+ && value.kind === "redirect"
21
+ && typeof value.location === "string";
22
+ }
23
+ function fragmentActionResult(markdown) {
24
+ return {
25
+ ok: true,
26
+ kind: "fragment",
27
+ markdown,
28
+ };
29
+ }
30
+ function redirectActionResult(location) {
31
+ return {
32
+ ok: true,
33
+ kind: "redirect",
34
+ location,
35
+ };
36
+ }
37
+ function normalizeActionResult(value) {
38
+ if (typeof value === "string") {
39
+ return fragmentActionResult(value);
40
+ }
41
+ if (isFailure(value) || isFragmentSuccess(value) || isRedirectSuccess(value)) {
42
+ return value;
43
+ }
44
+ if (value
45
+ && typeof value === "object"
46
+ && value.ok === true
47
+ && value.kind === "fragment") {
48
+ throw new Error("Invalid fragment action result");
49
+ }
50
+ if (value
51
+ && typeof value === "object"
52
+ && value.ok === true
53
+ && value.kind === "redirect") {
54
+ throw new Error("Invalid redirect action result");
55
+ }
56
+ throw new Error("Invalid action result");
57
+ }
@@ -0,0 +1,2 @@
1
+ export { fragmentActionResult, normalizeActionResult, redirectActionResult, } from "./execution";
2
+ export type { ActionFailure, ActionFieldErrors, ActionResult, ActionSuccess, FragmentActionSuccess, RedirectActionSuccess, } from "./types";
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.redirectActionResult = exports.normalizeActionResult = exports.fragmentActionResult = void 0;
4
+ var execution_1 = require("./execution");
5
+ Object.defineProperty(exports, "fragmentActionResult", { enumerable: true, get: function () { return execution_1.fragmentActionResult; } });
6
+ Object.defineProperty(exports, "normalizeActionResult", { enumerable: true, get: function () { return execution_1.normalizeActionResult; } });
7
+ Object.defineProperty(exports, "redirectActionResult", { enumerable: true, get: function () { return execution_1.redirectActionResult; } });
@@ -0,0 +1,19 @@
1
+ export type ActionFieldErrors = Record<string, string>;
2
+ export type FragmentActionSuccess = {
3
+ ok: true;
4
+ kind: "fragment";
5
+ markdown: string;
6
+ };
7
+ export type RedirectActionSuccess = {
8
+ ok: true;
9
+ kind: "redirect";
10
+ location: string;
11
+ };
12
+ export type ActionFailure = {
13
+ ok: false;
14
+ errorCode: string;
15
+ message?: string;
16
+ fieldErrors?: ActionFieldErrors;
17
+ };
18
+ export type ActionSuccess = FragmentActionSuccess | RedirectActionSuccess;
19
+ export type ActionResult = ActionSuccess | ActionFailure;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ import type { FrontmatterData } from "../model/document";
2
+ export declare function parseFrontmatter(raw: string): {
3
+ frontmatter: FrontmatterData;
4
+ body: string;
5
+ };
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseFrontmatter = parseFrontmatter;
4
+ function parseScalarValue(raw) {
5
+ const value = raw.trim();
6
+ if (value === "true")
7
+ return true;
8
+ if (value === "false")
9
+ return false;
10
+ if (/^-?\d+(?:\.\d+)?$/.test(value))
11
+ return Number(value);
12
+ return value.replace(/^["']|["']$/g, "");
13
+ }
14
+ function parseFrontmatter(raw) {
15
+ if (!raw.startsWith("---\n") && !raw.startsWith("---\r\n")) {
16
+ return { frontmatter: {}, body: raw };
17
+ }
18
+ const lines = raw.split(/\r?\n/);
19
+ const frontmatter = {};
20
+ let index = 1;
21
+ while (index < lines.length && lines[index] !== "---") {
22
+ const line = lines[index].trim();
23
+ if (line) {
24
+ const separatorIndex = line.indexOf(":");
25
+ if (separatorIndex === -1) {
26
+ throw new Error(`Invalid frontmatter line: ${line}`);
27
+ }
28
+ const key = line.slice(0, separatorIndex).trim();
29
+ const value = line.slice(separatorIndex + 1).trim();
30
+ frontmatter[key] = parseScalarValue(value);
31
+ }
32
+ index += 1;
33
+ }
34
+ if (index >= lines.length) {
35
+ throw new Error("Unterminated frontmatter block");
36
+ }
37
+ return {
38
+ frontmatter,
39
+ body: lines.slice(index + 1).join("\n"),
40
+ };
41
+ }
@@ -0,0 +1,5 @@
1
+ export declare function extractExecutableMdsnBlocks(markdown: string): {
2
+ markdownWithoutMdsn: string;
3
+ blocks: string[];
4
+ };
5
+ export declare function extractBlockAnchors(markdown: string): string[];
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractExecutableMdsnBlocks = extractExecutableMdsnBlocks;
4
+ exports.extractBlockAnchors = extractBlockAnchors;
5
+ function trimTrailingBlankLines(value) {
6
+ return value.replace(/\n+$/u, "\n");
7
+ }
8
+ function extractExecutableMdsnBlocks(markdown) {
9
+ const lines = markdown.split(/\r?\n/);
10
+ const keptLines = [];
11
+ const blocks = [];
12
+ let index = 0;
13
+ let activeFence = null;
14
+ while (index < lines.length) {
15
+ const line = lines[index];
16
+ const trimmed = line.trim();
17
+ const fenceMatch = trimmed.match(/^(`{3,}|~{3,})(.*)$/);
18
+ if (fenceMatch) {
19
+ const marker = fenceMatch[1];
20
+ const info = fenceMatch[2].trim();
21
+ if (activeFence) {
22
+ if (trimmed === activeFence.marker) {
23
+ activeFence = null;
24
+ }
25
+ keptLines.push(line);
26
+ index += 1;
27
+ continue;
28
+ }
29
+ if (marker === "```" && info === "mdsn") {
30
+ index += 1;
31
+ const blockLines = [];
32
+ while (index < lines.length && lines[index].trim() !== "```") {
33
+ blockLines.push(lines[index]);
34
+ index += 1;
35
+ }
36
+ if (index >= lines.length) {
37
+ throw new Error("Unterminated mdsn code block");
38
+ }
39
+ blocks.push(blockLines.join("\n"));
40
+ index += 1;
41
+ continue;
42
+ }
43
+ activeFence = { marker, info };
44
+ keptLines.push(line);
45
+ index += 1;
46
+ continue;
47
+ }
48
+ keptLines.push(line);
49
+ index += 1;
50
+ }
51
+ return {
52
+ markdownWithoutMdsn: trimTrailingBlankLines(keptLines.join("\n")),
53
+ blocks,
54
+ };
55
+ }
56
+ function extractBlockAnchors(markdown) {
57
+ const anchors = [];
58
+ let activeFence = null;
59
+ for (const line of markdown.split(/\r?\n/)) {
60
+ const trimmed = line.trim();
61
+ const fenceMatch = trimmed.match(/^(`{3,}|~{3,})(.*)$/);
62
+ if (fenceMatch) {
63
+ const marker = fenceMatch[1];
64
+ if (activeFence) {
65
+ if (trimmed === activeFence) {
66
+ activeFence = null;
67
+ }
68
+ }
69
+ else {
70
+ activeFence = marker;
71
+ }
72
+ continue;
73
+ }
74
+ if (activeFence) {
75
+ continue;
76
+ }
77
+ const anchorMatch = trimmed.match(/^<!--\s*mdsn:block\s+([a-zA-Z_][\w-]*)\s*-->$/);
78
+ if (anchorMatch) {
79
+ anchors.push(anchorMatch[1]);
80
+ }
81
+ }
82
+ return anchors;
83
+ }
@@ -0,0 +1,2 @@
1
+ import type { DocumentDefinition } from "../model/document";
2
+ export declare function parsePageDefinition(raw: string): DocumentDefinition;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parsePageDefinition = parsePageDefinition;
4
+ const frontmatter_1 = require("./frontmatter");
5
+ const markdown_1 = require("./markdown");
6
+ const mdsn_1 = require("../protocol/mdsn");
7
+ const validation_1 = require("../protocol/validation");
8
+ function parsePageDefinition(raw) {
9
+ const { frontmatter, body } = (0, frontmatter_1.parseFrontmatter)(raw);
10
+ const { markdownWithoutMdsn, blocks } = (0, markdown_1.extractExecutableMdsnBlocks)(body);
11
+ if (blocks.length > 1) {
12
+ throw new Error("An MDSN page must contain at most one mdsn code block");
13
+ }
14
+ const parsed = (0, mdsn_1.parseMdsnBlocks)(blocks);
15
+ const blockAnchors = (0, markdown_1.extractBlockAnchors)(markdownWithoutMdsn).map((name) => ({ name }));
16
+ (0, validation_1.validateDocumentStructure)(parsed.schemas, parsed.blocks, blockAnchors);
17
+ return {
18
+ frontmatter,
19
+ markdown: markdownWithoutMdsn,
20
+ schemas: parsed.schemas,
21
+ blocks: parsed.blocks,
22
+ blockAnchors,
23
+ };
24
+ }
@@ -0,0 +1,3 @@
1
+ export { parsePageDefinition } from "./document/page-definition";
2
+ export type { FrontmatterData } from "./model/document";
3
+ export type { BlockAnchorDefinition, BlockDefinition, DocumentDefinition, InputDefinition, InputType, ReadDefinition, RedirectDefinition, SchemaDefinition, WriteDefinition, } from "./model";
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parsePageDefinition = void 0;
4
+ var page_definition_1 = require("./document/page-definition");
5
+ Object.defineProperty(exports, "parsePageDefinition", { enumerable: true, get: function () { return page_definition_1.parsePageDefinition; } });