@plitzi/sdk-server 0.32.14 → 0.32.16

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 (68) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/adapters/jsonAdapters.js +2 -1
  3. package/dist/core/createServer.js +10 -2
  4. package/dist/core/http/stages/middlewares.js +3 -2
  5. package/dist/core/http/stages/pluginAssets.js +3 -2
  6. package/dist/core/http/stages/static.js +3 -2
  7. package/dist/core/requestParser.js +1 -1
  8. package/dist/core/server/{ssrServer.js → pageServer.js} +15 -6
  9. package/dist/core/services/registry.js +2 -2
  10. package/dist/helpers/cache/defaults.js +3 -3
  11. package/dist/index.js +1 -1
  12. package/dist/modules/mcp/catalogs/cssCatalog/border.js +30 -0
  13. package/dist/modules/mcp/catalogs/cssCatalog/box.js +31 -0
  14. package/dist/modules/mcp/catalogs/cssCatalog/helpers.js +185 -0
  15. package/dist/modules/mcp/catalogs/cssCatalog/index.js +131 -0
  16. package/dist/modules/mcp/catalogs/cssCatalog/layout.js +98 -0
  17. package/dist/modules/mcp/catalogs/cssCatalog/visual.js +144 -0
  18. package/dist/modules/mcp/catalogs/registry.js +1 -1
  19. package/dist/modules/mcp/helpers/guide.js +23 -13
  20. package/dist/modules/mcp/resources/core.js +5 -2
  21. package/dist/modules/mcp/resources/primer.js +2 -1
  22. package/dist/modules/mcp/resources/register.js +6 -3
  23. package/dist/modules/mcp/server.js +1 -1
  24. package/dist/modules/mcp/tools/operations/schema/interactions/upsertInteractionFlow.js +3 -2
  25. package/dist/modules/mcp/tools/operations/style/shared.js +2 -2
  26. package/dist/modules/mcp/tools/operations/style/write.js +2 -2
  27. package/dist/modules/mcp/tools/shared/validator/audit.js +1 -4
  28. package/dist/modules/mcp/tools/shared/validator/css.js +3 -11
  29. package/dist/modules/mcp/tools/shared/validator/elements.js +4 -1
  30. package/dist/modules/mcp/tools/shared/validator/index.js +15 -15
  31. package/dist/modules/mcp/tools/shared/validator/interactions.js +1 -4
  32. package/dist/modules/oauth/authorize.js +2 -1
  33. package/dist/modules/oauth/metadata.js +8 -2
  34. package/dist/modules/oauth/records.js +11 -2
  35. package/dist/modules/oauth/register.js +15 -8
  36. package/dist/modules/oauth/respond.js +4 -4
  37. package/dist/modules/oauth/token.js +2 -2
  38. package/dist/modules/ssr/registerExternalPlugins.js +1 -1
  39. package/dist/plugins/manager.js +1 -1
  40. package/dist/src/core/createServer.d.ts +9 -1
  41. package/dist/src/core/server/pageServer.d.ts +10 -0
  42. package/dist/src/core/services/registry.d.ts +1 -1
  43. package/dist/src/modules/mcp/catalogs/cssCatalog/border.d.ts +4 -0
  44. package/dist/src/modules/mcp/catalogs/cssCatalog/box.d.ts +4 -0
  45. package/dist/src/modules/mcp/catalogs/cssCatalog/helpers.d.ts +34 -0
  46. package/dist/src/modules/mcp/catalogs/{cssCatalog.d.ts → cssCatalog/index.d.ts} +10 -5
  47. package/dist/src/modules/mcp/catalogs/cssCatalog/layout.d.ts +9 -0
  48. package/dist/src/modules/mcp/catalogs/cssCatalog/visual.d.ts +8 -0
  49. package/dist/src/modules/mcp/helpers/guide.d.ts +2 -2
  50. package/dist/src/modules/mcp/resources/index.d.ts +1 -1
  51. package/dist/src/modules/mcp/tests/apply.test.d.ts +1 -0
  52. package/dist/src/modules/mcp/tests/bindings.test.d.ts +1 -0
  53. package/dist/src/modules/mcp/tests/css.test.d.ts +1 -0
  54. package/dist/src/modules/mcp/tests/helpers.d.ts +13 -0
  55. package/dist/src/modules/mcp/tests/interactions.test.d.ts +1 -0
  56. package/dist/src/modules/mcp/tests/pages.test.d.ts +1 -0
  57. package/dist/src/modules/mcp/tests/reads.test.d.ts +1 -0
  58. package/dist/src/modules/mcp/tests/search.test.d.ts +1 -0
  59. package/dist/src/modules/mcp/tests/styles.test.d.ts +1 -0
  60. package/dist/src/modules/mcp/tests/tools.test.d.ts +1 -0
  61. package/dist/src/modules/mcp/tests/validation.test.d.ts +1 -0
  62. package/dist/src/modules/mcp/tools/screenshot.d.ts +1 -1
  63. package/dist/src/modules/oauth/metadata.d.ts +7 -1
  64. package/dist/src/modules/oauth/records.d.ts +6 -0
  65. package/package.json +9 -9
  66. package/dist/modules/mcp/catalogs/cssCatalog.js +0 -205
  67. package/dist/src/core/server/ssrServer.d.ts +0 -2
  68. /package/dist/src/modules/mcp/{mcp.test.d.ts → catalogs/cssCatalog/cssCatalog.test.d.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @plitzi/sdk-server
2
2
 
3
+ ## 0.32.16
4
+
5
+ ### Patch Changes
6
+
7
+ - v0.32.16
8
+ - Updated dependencies
9
+ - @plitzi/plitzi-sdk@0.32.16
10
+ - @plitzi/sdk-schema@0.32.16
11
+ - @plitzi/sdk-shared@0.32.16
12
+
13
+ ## 0.32.15
14
+
15
+ ### Patch Changes
16
+
17
+ - v0.32.15
18
+ - Updated dependencies
19
+ - @plitzi/plitzi-sdk@0.32.15
20
+ - @plitzi/sdk-schema@0.32.15
21
+ - @plitzi/sdk-shared@0.32.15
22
+
3
23
  ## 0.32.14
4
24
 
5
25
  ### Patch Changes
@@ -13,7 +13,8 @@ var createJsonAdapters = (config) => {
13
13
  }
14
14
  };
15
15
  const saveOfflineData = (spaceId, environment, data) => {
16
- writeFileSync(typeof config.offlineData === "function" ? config.offlineData(spaceId, environment) : config.offlineData, JSON.stringify(data, null, 2));
16
+ const filePath = typeof config.offlineData === "function" ? config.offlineData(spaceId, environment) : config.offlineData;
17
+ writeFileSync(filePath, JSON.stringify(data, null, 2));
17
18
  return Promise.resolve();
18
19
  };
19
20
  const getSpaceDeployment = (req) => {
@@ -1,11 +1,19 @@
1
1
  import { createMCPServer } from "./server/mcpServer.js";
2
2
  import { resolveServices } from "./services/resolve.js";
3
- import { createSSRServer } from "./server/ssrServer.js";
3
+ import { createPageServer, createSSRServer } from "./server/pageServer.js";
4
4
  //#region src/core/createServer.ts
5
+ /** The general server: mounts whatever the config asks for — SSR, RSC and MCP together, if that is what it
6
+ * enables — and is what a deployment reaches for when it serves more than one surface from a single port (the
7
+ * package's own standalone harness does exactly that).
8
+ *
9
+ * Prefer the surface-specific factories whenever the surface IS known, so the process states what it serves by
10
+ * the name it calls: createSSRServer for pages + RSC, createMCPServer for a dedicated MCP server. An MCP-only
11
+ * config is handed to the latter here, since the lean pipeline builds none of the render template, caches or
12
+ * plugin manager a page server would carry unused. */
5
13
  var createServer = (config) => {
6
14
  const services = resolveServices(config);
7
15
  if (services.mcp && !services.ssr && !services.rsc && !services.ai) return createMCPServer(config);
8
- return createSSRServer(config);
16
+ return createPageServer(config, services);
9
17
  };
10
18
  //#endregion
11
19
  export { createMCPServer, createSSRServer, createServer, resolveServices };
@@ -5,12 +5,13 @@ import { spaceDeploymentMiddleware } from "../../../middlewares/spaceDeployment.
5
5
  //#region src/core/http/stages/middlewares.ts
6
6
  var middlewaresStage = async (ctx) => {
7
7
  const { config, req, res } = ctx;
8
- return await runMiddlewares([
8
+ const middlewares = [
9
9
  spaceDeploymentMiddleware(config.adapters),
10
10
  basicAuthMiddleware({ cacheTtlMs: config.cacheTtlMs }),
11
11
  authMiddleware(config.adapters),
12
12
  ...config.middlewares || []
13
- ], req, res) || res.status !== 200;
13
+ ];
14
+ return await runMiddlewares(middlewares, req, res) || res.status !== 200;
14
15
  };
15
16
  //#endregion
16
17
  export { middlewaresStage };
@@ -7,10 +7,11 @@ var pluginAssetsStage = async (ctx) => {
7
7
  const pluginName = relative.split("/")[1];
8
8
  if (pluginName && pluginManager.hasPlugin(pluginName)) {
9
9
  await pluginManager.prepare(pluginName);
10
- if (serveStatic({
10
+ const strippedReq = {
11
11
  ...req,
12
12
  path: relative
13
- }, res, pluginManager.outputDir)) return true;
13
+ };
14
+ if (serveStatic(strippedReq, res, pluginManager.outputDir)) return true;
14
15
  }
15
16
  res.setStatus(404);
16
17
  res.send("Not found");
@@ -20,10 +20,11 @@ var configStaticStage = (ctx) => {
20
20
  if (ctx.req.path === prefix || ctx.req.path.startsWith(normalizedPrefix)) {
21
21
  ctx.res.setHeader("Access-Control-Allow-Origin", "*");
22
22
  ctx.res.setHeader("Cross-Origin-Resource-Policy", "cross-origin");
23
- if (serveStatic({
23
+ const strippedReq = {
24
24
  ...ctx.req,
25
25
  path: ctx.req.path.slice(prefix.length) || "/"
26
- }, ctx.res, rootDir)) return true;
26
+ };
27
+ if (serveStatic(strippedReq, ctx.res, rootDir)) return true;
27
28
  }
28
29
  }
29
30
  return false;
@@ -47,7 +47,7 @@ var clientIp = (raw, req) => {
47
47
  const forwardedFor = headerValue(req.headers["x-forwarded-for"]).split(",")[0] ?? "";
48
48
  return unmapIpv4(headerValue(req.headers["cf-connecting-ip"]) || headerValue(req.headers["x-real-ip"]) || forwardedFor.trim() || raw.socket.remoteAddress || "");
49
49
  };
50
- var MAX_BODY_BYTES = 1024 * 1024;
50
+ var MAX_BODY_BYTES = 1048576;
51
51
  var readRawBody = (raw) => new Promise((resolve, reject) => {
52
52
  const chunks = [];
53
53
  let size = 0;
@@ -4,16 +4,18 @@ import { DEFAULT_TTL_MS } from "../../helpers/cache/defaults.js";
4
4
  import { buildCacheManager } from "../../helpers/cache/cacheManager.js";
5
5
  import { createServerCaches, destroyServerCaches } from "../../helpers/cache/serverCaches.js";
6
6
  import { createMemoryDraftStore } from "../../modules/ssr/preview.js";
7
- import { buildSSRPipeline } from "../services/registry.js";
7
+ import { buildPagePipeline } from "../services/registry.js";
8
8
  import normalizePlugins, { normalizePluginSource } from "../../helpers/normalizePlugins.js";
9
9
  import { compileTemplate } from "../../modules/ssr/template.js";
10
10
  import { PluginManager } from "../../plugins/manager.js";
11
11
  import { resolveServices } from "../services/resolve.js";
12
- //#region src/core/server/ssrServer.ts
13
- var createSSRServer = (config) => {
12
+ //#region src/core/server/pageServer.ts
13
+ /** The page-serving machinery: html/rsc caches, the render template and the plugin manager, driving the page
14
+ * pipeline. Which services it mounts is the CALLER's decision — {@link createServer} passes whatever the config
15
+ * enables, createSSRServer pins the page surface — so this unit never second-guesses a factory's promise. */
16
+ var createPageServer = (config, services) => {
14
17
  const { cacheTtlMs: htmlTtlMs = DEFAULT_TTL_MS.html } = config;
15
18
  if (config.preview?.enabled && !config.draftStore) config.draftStore = createMemoryDraftStore();
16
- const services = resolveServices(config);
17
19
  const caches = createServerCaches(htmlTtlMs, config.rsc?.cacheTtlMs ?? DEFAULT_TTL_MS.rsc);
18
20
  const cache = caches.html ? buildCacheManager(caches.html) : null;
19
21
  const renderFn = config.templateFn ?? compileTemplate();
@@ -25,7 +27,7 @@ var createSSRServer = (config) => {
25
27
  },
26
28
  invalidate: (name, version) => pluginManager.invalidate(name, version)
27
29
  };
28
- const stages = buildSSRPipeline(services);
30
+ const stages = buildPagePipeline(services);
29
31
  const makeHandlerForPort = (port) => {
30
32
  const buildContext = (raw, rawRes, req, res) => ({
31
33
  raw,
@@ -50,5 +52,12 @@ var createSSRServer = (config) => {
50
52
  }
51
53
  });
52
54
  };
55
+ /** The page server: SSR and RSC, and nothing else. MCP is pinned OFF here even when the config asks for it —
56
+ * what a factory named after a surface mounts must be readable from its name alone. A deployment that wants
57
+ * both surfaces in one process asks {@link createServer} for them; a dedicated MCP server is createMCPServer. */
58
+ var createSSRServer = (config) => createPageServer(config, {
59
+ ...resolveServices(config),
60
+ mcp: false
61
+ });
53
62
  //#endregion
54
- export { createSSRServer };
63
+ export { createPageServer, createSSRServer };
@@ -9,7 +9,7 @@ import { middlewaresStage } from "../http/stages/middlewares.js";
9
9
  import { pluginAssetsStage } from "../http/stages/pluginAssets.js";
10
10
  import { builtinPublicStage, configStaticStage, publicDirStage, wellKnownStage } from "../http/stages/static.js";
11
11
  //#region src/core/services/registry.ts
12
- var buildSSRPipeline = (services) => {
12
+ var buildPagePipeline = (services) => {
13
13
  const stages = [
14
14
  healthStage,
15
15
  builtinPublicStage,
@@ -34,4 +34,4 @@ var buildMCPPipeline = () => [
34
34
  mcpOnlyStage
35
35
  ];
36
36
  //#endregion
37
- export { buildMCPPipeline, buildSSRPipeline };
37
+ export { buildMCPPipeline, buildPagePipeline };
@@ -1,9 +1,9 @@
1
1
  //#region src/helpers/cache/defaults.ts
2
2
  var DEFAULT_TTL_MS = {
3
- html: 300 * 1e3,
3
+ html: 3e5,
4
4
  rsc: 3e4,
5
- auth: 300 * 1e3,
6
- offlineData: 300 * 1e3
5
+ auth: 3e5,
6
+ offlineData: 3e5
7
7
  };
8
8
  //#endregion
9
9
  export { DEFAULT_TTL_MS };
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ import { createMemoryDraftStore, createPreview } from "./modules/ssr/preview.js"
16
16
  import { buildHealthPayload, registerHealthCheck } from "./core/health.js";
17
17
  import { createMCPServer } from "./core/server/mcpServer.js";
18
18
  import { resolveServices } from "./core/services/resolve.js";
19
- import { createSSRServer } from "./core/server/ssrServer.js";
19
+ import { createSSRServer } from "./core/server/pageServer.js";
20
20
  import { createServer } from "./core/createServer.js";
21
21
  import { createJsonAdapters } from "./adapters/jsonAdapters.js";
22
22
  import AIEngine from "./modules/ai/AIEngine.js";
@@ -0,0 +1,30 @@
1
+ import { BORDER_STYLES, BORDER_WIDTH_KEYWORDS, LENGTH_RE, SIDES, expandTo4, splitTokens } from "./helpers.js";
2
+ //#region src/modules/mcp/catalogs/cssCatalog/border.ts
3
+ var BORDER_INITIAL = {
4
+ width: "medium",
5
+ style: "none",
6
+ color: "currentcolor"
7
+ };
8
+ var classifyBorderToken = (token) => {
9
+ if (BORDER_STYLES.has(token)) return "style";
10
+ if (BORDER_WIDTH_KEYWORDS.has(token) || LENGTH_RE.test(token)) return "width";
11
+ return "color";
12
+ };
13
+ var classifyBorderTokens = (value) => {
14
+ const parts = { ...BORDER_INITIAL };
15
+ for (const token of splitTokens(value)) parts[classifyBorderToken(token)] = token;
16
+ return parts;
17
+ };
18
+ var expandBorder = (key, value, out) => {
19
+ const sides = key === "border" ? SIDES : [key.slice(7)];
20
+ const parts = classifyBorderTokens(value);
21
+ for (const side of sides) for (const [kind, token] of Object.entries(parts)) out[`border-${side}-${kind}`] = token;
22
+ };
23
+ var expandBorderGroup = (suffix, value, out) => {
24
+ const values = expandTo4(splitTokens(value));
25
+ SIDES.forEach((side, index) => {
26
+ out[`border-${side}-${suffix}`] = values[index];
27
+ });
28
+ };
29
+ //#endregion
30
+ export { classifyBorderTokens, expandBorder, expandBorderGroup };
@@ -0,0 +1,31 @@
1
+ import { expandTo4, splitPair, splitTokens } from "./helpers.js";
2
+ //#region src/modules/mcp/catalogs/cssCatalog/box.ts
3
+ var CORNERS = [
4
+ "top-left",
5
+ "top-right",
6
+ "bottom-right",
7
+ "bottom-left"
8
+ ];
9
+ var expandBox = (key, value, out) => {
10
+ const [top, right, bottom, left] = expandTo4(splitTokens(value));
11
+ const prefix = key === "inset" ? "" : `${key}-`;
12
+ out[`${prefix}top`] = top;
13
+ out[`${prefix}right`] = right;
14
+ out[`${prefix}bottom`] = bottom;
15
+ out[`${prefix}left`] = left;
16
+ };
17
+ var expandBorderRadius = (value, out) => {
18
+ const [horizontal, vertical] = splitPair(value, "/");
19
+ const h = expandTo4(splitTokens(horizontal));
20
+ const v = vertical === void 0 ? void 0 : expandTo4(splitTokens(vertical));
21
+ CORNERS.forEach((corner, index) => {
22
+ out[`border-${corner}-radius`] = v ? `${h[index]} ${v[index]}` : h[index];
23
+ });
24
+ };
25
+ var expandGap = (value, out) => {
26
+ const [row, col = row] = splitTokens(value);
27
+ out["row-gap"] = row;
28
+ out["column-gap"] = col;
29
+ };
30
+ //#endregion
31
+ export { expandBorderRadius, expandBox, expandGap };
@@ -0,0 +1,185 @@
1
+ //#region src/modules/mcp/catalogs/cssCatalog/helpers.ts
2
+ var walkTopLevel = (value, onChar) => {
3
+ let depth = 0;
4
+ let quote = "";
5
+ for (const ch of value) {
6
+ if (quote) {
7
+ onChar(ch, false);
8
+ if (ch === quote) quote = "";
9
+ continue;
10
+ }
11
+ if (/["']/.test(ch)) {
12
+ quote = ch;
13
+ onChar(ch, false);
14
+ continue;
15
+ }
16
+ if (ch === "(") depth += 1;
17
+ else if (ch === ")") depth = Math.max(0, depth - 1);
18
+ onChar(ch, depth === 0);
19
+ }
20
+ };
21
+ /** Split a shorthand value into whitespace-separated tokens, keeping parenthesized and quoted runs whole. */
22
+ var splitTokens = (value) => {
23
+ const tokens = [];
24
+ let current = "";
25
+ walkTopLevel(value.trim(), (ch, topLevel) => {
26
+ if (topLevel && /\s/.test(ch)) {
27
+ if (current) {
28
+ tokens.push(current);
29
+ current = "";
30
+ }
31
+ } else current += ch;
32
+ });
33
+ if (current) tokens.push(current);
34
+ return tokens;
35
+ };
36
+ /** Split a value on a top-level separator. Used for the comma-separated layers of transition/animation/background
37
+ * and for the `/` of border-radius/grid-template/grid-row. */
38
+ var splitOn = (value, separator) => {
39
+ const parts = [];
40
+ let current = "";
41
+ walkTopLevel(value, (ch, topLevel) => {
42
+ if (topLevel && ch === separator) {
43
+ parts.push(current);
44
+ current = "";
45
+ } else current += ch;
46
+ });
47
+ parts.push(current);
48
+ return parts.map((part) => part.trim());
49
+ };
50
+ /** Split a value on its first top-level `/` — the `a / b` form of border-radius, grid-template, background and
51
+ * font. Returns the half after the slash as undefined when there is none, which is what tells those expanders the
52
+ * second half was not declared at all. */
53
+ var splitPair = (value, separator) => {
54
+ const [first, ...rest] = splitOn(value, separator);
55
+ return [first, rest.length > 0 ? rest.join(separator) : void 0];
56
+ };
57
+ var TIME_RE = /^-?[\d.]+(ms|s)$/;
58
+ var NUMBER_RE = /^-?[\d.]+$/;
59
+ /** A numeric value with an optional unit or `%` — matches both `12px` and `50%`. */
60
+ var LENGTH_RE = /^-?[\d.]+([a-z%]*)$/;
61
+ var QUOTE_RE = /^['"]/;
62
+ /** Resolve the 1–4 value syntax shared by padding/margin/inset (top/right/bottom/left) and border-radius
63
+ * (top-left/top-right/bottom-right/bottom-left): 1 value fills all, 2 pair up, 3 leave the 4th mirroring the 2nd. */
64
+ var expandTo4 = (tokens) => {
65
+ const [a, b = a, c = a, d = b] = tokens;
66
+ return [
67
+ a,
68
+ b,
69
+ c,
70
+ d
71
+ ];
72
+ };
73
+ var SIDES = [
74
+ "top",
75
+ "right",
76
+ "bottom",
77
+ "left"
78
+ ];
79
+ var FLEX_DIRECTIONS = /* @__PURE__ */ new Set([
80
+ "row",
81
+ "row-reverse",
82
+ "column",
83
+ "column-reverse"
84
+ ]);
85
+ var FLEX_WRAPS = /* @__PURE__ */ new Set([
86
+ "nowrap",
87
+ "wrap",
88
+ "wrap-reverse"
89
+ ]);
90
+ var LIST_STYLE_TYPES = /* @__PURE__ */ new Set([
91
+ "disc",
92
+ "circle",
93
+ "square",
94
+ "decimal",
95
+ "decimal-leading-zero",
96
+ "lower-roman",
97
+ "upper-roman",
98
+ "lower-alpha",
99
+ "upper-alpha",
100
+ "lower-greek",
101
+ "lower-latin",
102
+ "upper-latin",
103
+ "armenian",
104
+ "georgian",
105
+ "none"
106
+ ]);
107
+ var LIST_STYLE_POSITIONS = /* @__PURE__ */ new Set(["inside", "outside"]);
108
+ var TEXT_DECORATION_LINES = /* @__PURE__ */ new Set([
109
+ "underline",
110
+ "overline",
111
+ "line-through",
112
+ "blink",
113
+ "none"
114
+ ]);
115
+ var TEXT_DECORATION_STYLES = /* @__PURE__ */ new Set([
116
+ "solid",
117
+ "double",
118
+ "dotted",
119
+ "dashed",
120
+ "wavy"
121
+ ]);
122
+ var TIMING_FUNCTIONS = /* @__PURE__ */ new Set([
123
+ "ease",
124
+ "linear",
125
+ "ease-in",
126
+ "ease-out",
127
+ "ease-in-out",
128
+ "step-start",
129
+ "step-end"
130
+ ]);
131
+ /** A timing function may also be a function call — cubic-bezier(…) or steps(…). */
132
+ var isTimingFunction = (token) => TIMING_FUNCTIONS.has(token) || token.startsWith("cubic-bezier(") || token.startsWith("steps(");
133
+ var ANIMATION_DIRECTIONS = /* @__PURE__ */ new Set([
134
+ "normal",
135
+ "reverse",
136
+ "alternate",
137
+ "alternate-reverse"
138
+ ]);
139
+ var ANIMATION_FILL_MODES = /* @__PURE__ */ new Set([
140
+ "none",
141
+ "forwards",
142
+ "backwards",
143
+ "both"
144
+ ]);
145
+ var ANIMATION_PLAY_STATES = /* @__PURE__ */ new Set(["running", "paused"]);
146
+ var FONT_STYLE_KEYWORDS = /* @__PURE__ */ new Set([
147
+ "normal",
148
+ "italic",
149
+ "oblique"
150
+ ]);
151
+ var FONT_VARIANT_KEYWORDS = /* @__PURE__ */ new Set(["normal", "small-caps"]);
152
+ var FONT_WEIGHT_KEYWORDS = /* @__PURE__ */ new Set([
153
+ "normal",
154
+ "bold",
155
+ "bolder",
156
+ "lighter",
157
+ "100",
158
+ "200",
159
+ "300",
160
+ "400",
161
+ "500",
162
+ "600",
163
+ "700",
164
+ "800",
165
+ "900"
166
+ ]);
167
+ var BORDER_STYLES = /* @__PURE__ */ new Set([
168
+ "none",
169
+ "hidden",
170
+ "dotted",
171
+ "dashed",
172
+ "solid",
173
+ "double",
174
+ "groove",
175
+ "ridge",
176
+ "inset",
177
+ "outset"
178
+ ]);
179
+ var BORDER_WIDTH_KEYWORDS = /* @__PURE__ */ new Set([
180
+ "thin",
181
+ "medium",
182
+ "thick"
183
+ ]);
184
+ //#endregion
185
+ export { ANIMATION_DIRECTIONS, ANIMATION_FILL_MODES, ANIMATION_PLAY_STATES, BORDER_STYLES, BORDER_WIDTH_KEYWORDS, FLEX_DIRECTIONS, FLEX_WRAPS, FONT_STYLE_KEYWORDS, FONT_VARIANT_KEYWORDS, FONT_WEIGHT_KEYWORDS, LENGTH_RE, LIST_STYLE_POSITIONS, LIST_STYLE_TYPES, NUMBER_RE, QUOTE_RE, SIDES, TEXT_DECORATION_LINES, TEXT_DECORATION_STYLES, TIME_RE, expandTo4, isTimingFunction, splitOn, splitPair, splitTokens };
@@ -0,0 +1,131 @@
1
+ import { SIDES } from "./helpers.js";
2
+ import { expandBorder, expandBorderGroup } from "./border.js";
3
+ import { expandBorderRadius, expandBox, expandGap } from "./box.js";
4
+ import { expandColumns, expandFlex, expandFlexFlow, expandGridArea, expandGridLine, expandGridTemplate, expandOverflow, expandPlacePair } from "./layout.js";
5
+ import { expandAnimation, expandBackground, expandFont, expandListStyle, expandOutline, expandTextDecoration, expandTransition } from "./visual.js";
6
+ import styleConstants from "@plitzi/sdk-shared/style/styleConstants";
7
+ //#region src/modules/mcp/catalogs/cssCatalog/index.ts
8
+ /** Every kebab-case CSS property Plitzi's style engine understands. Values written to a definition
9
+ * must use these exact keys — camelCase or unknown keys are rejected by the validator. */
10
+ var cssProperties = Array.from(new Set(Object.values(styleConstants))).sort();
11
+ var cssPropertySet = new Set(cssProperties);
12
+ var isCssProperty = (key) => cssPropertySet.has(key);
13
+ var toKebab = (key) => key.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
14
+ /** If a camelCase key maps to a known kebab-case property, return it — used to teach the agent the correct key. */
15
+ var suggestCssProperty = (key) => {
16
+ const kebab = toKebab(key);
17
+ return cssPropertySet.has(kebab) ? kebab : void 0;
18
+ };
19
+ var EXPANDERS = /* @__PURE__ */ new Map([
20
+ ["padding", expandBox],
21
+ ["margin", expandBox],
22
+ ["inset", expandBox],
23
+ ["border-radius", (_key, value, out) => expandBorderRadius(value, out)],
24
+ ["gap", (_key, value, out) => expandGap(value, out)],
25
+ ["border-width", (key, value, out) => expandBorderGroup(key.slice(7), value, out)],
26
+ ["border-color", (key, value, out) => expandBorderGroup(key.slice(7), value, out)],
27
+ ["border-style", (key, value, out) => expandBorderGroup(key.slice(7), value, out)],
28
+ ["border", expandBorder],
29
+ ["overflow", (_key, value, out) => expandOverflow(value, out)],
30
+ ["flex", (_key, value, out) => expandFlex(value, out)],
31
+ ["flex-flow", (_key, value, out) => expandFlexFlow(value, out)],
32
+ ["place-content", (_key, value, out) => expandPlacePair("place-content", value, out)],
33
+ ["place-items", (_key, value, out) => expandPlacePair("place-items", value, out)],
34
+ ["place-self", (_key, value, out) => expandPlacePair("place-self", value, out)],
35
+ ["grid-row", (_key, value, out) => expandGridLine("grid-row", value, out)],
36
+ ["grid-column", (_key, value, out) => expandGridLine("grid-column", value, out)],
37
+ ["grid-area", (_key, value, out) => expandGridArea(value, out)],
38
+ ["grid", (_key, value, out) => expandGridTemplate(value, out)],
39
+ ["grid-template", (_key, value, out) => expandGridTemplate(value, out)],
40
+ ["columns", (_key, value, out) => expandColumns(value, out)],
41
+ ["outline", (_key, value, out) => expandOutline(value, out)],
42
+ ["list-style", (_key, value, out) => expandListStyle(value, out)],
43
+ ["text-decoration", (_key, value, out) => expandTextDecoration(value, out)],
44
+ ["transition", (_key, value, out) => expandTransition(value, out)],
45
+ ["animation", (_key, value, out) => expandAnimation(value, out)],
46
+ ["background", (_key, value, out) => expandBackground(value, out)],
47
+ ["font", (_key, value, out) => expandFont(value, out)]
48
+ ]);
49
+ for (const side of SIDES) EXPANDERS.set(`border-${side}`, expandBorder);
50
+ /** Every shorthand the MCP accepts and atomizes — advertised to the agent so it knows it may write plain CSS. */
51
+ var cssShorthands = Array.from(EXPANDERS.keys()).sort();
52
+ var expandOne = (key, raw, out) => {
53
+ const expand = EXPANDERS.get(key);
54
+ if (!expand) return false;
55
+ const value = String(raw).trim();
56
+ if (value !== "") expand(key, value, out);
57
+ return true;
58
+ };
59
+ /** Expand supported CSS shorthands to their longhand keys. Explicit longhands in the same map win over any
60
+ * expansion (so `{ padding: 8, padding-left: 0 }` keeps padding-left: 0). Unrecognized keys pass through. */
61
+ var expandShorthand = (css) => {
62
+ const expanded = {};
63
+ const direct = {};
64
+ for (const [key, value] of Object.entries(css)) if (!expandOne(key, value, expanded)) direct[key] = value;
65
+ return {
66
+ ...expanded,
67
+ ...direct
68
+ };
69
+ };
70
+ var REMOVAL_PROBE = new Map(Object.entries({
71
+ padding: "0",
72
+ margin: "0",
73
+ inset: "0",
74
+ "border-radius": "0 0 0 0 / 0 0 0 0",
75
+ gap: "0 0",
76
+ "border-width": "0 0 0 0",
77
+ "border-color": "red red red red",
78
+ "border-style": "solid solid solid solid",
79
+ border: "0 solid red",
80
+ overflow: "visible visible",
81
+ flex: "0 0 auto",
82
+ "flex-flow": "row nowrap",
83
+ "place-content": "start start",
84
+ "place-items": "start start",
85
+ "place-self": "start start",
86
+ "grid-row": "auto / auto",
87
+ "grid-column": "auto / auto",
88
+ "grid-area": "auto / auto / auto / auto",
89
+ grid: "\"a\" 0 / 0",
90
+ "grid-template": "\"a\" 0 / 0",
91
+ columns: "0 0",
92
+ outline: "0 solid red",
93
+ "list-style": "disc inside url(x)",
94
+ "text-decoration": "underline solid red",
95
+ transition: "all 0s ease 0s",
96
+ animation: "a 0s ease 0s 1 normal forwards running",
97
+ background: "red url(x) no-repeat scroll 0 0 / auto padding-box border-box",
98
+ font: "italic small-caps bold 0px/0 a"
99
+ }));
100
+ for (const side of SIDES) REMOVAL_PROBE.set(`border-${side}`, "0 solid red");
101
+ /** The longhand keys a shorthand controls — what a `null` patch value has to clear. */
102
+ var shorthandLonghands = (key) => {
103
+ const probe = REMOVAL_PROBE.get(key);
104
+ if (probe === void 0) return;
105
+ const out = {};
106
+ expandOne(key, probe, out);
107
+ return Object.keys(out);
108
+ };
109
+ /** Patch flavour of {@link expandShorthand}: a `null` value removes every longhand the key controls, so
110
+ * `{ padding: null }` clears all four sides rather than a `padding` key that was never stored. */
111
+ var expandShorthandPatch = (css) => {
112
+ const expanded = {};
113
+ const direct = {};
114
+ for (const [key, value] of Object.entries(css)) {
115
+ if (value === null) {
116
+ const longhands = shorthandLonghands(key);
117
+ if (longhands) for (const longhand of longhands) expanded[longhand] = null;
118
+ else direct[key] = null;
119
+ continue;
120
+ }
121
+ const props = {};
122
+ if (expandOne(key, value, props)) Object.assign(expanded, props);
123
+ else direct[key] = value;
124
+ }
125
+ return {
126
+ ...expanded,
127
+ ...direct
128
+ };
129
+ };
130
+ //#endregion
131
+ export { cssProperties, cssShorthands, expandShorthand, expandShorthandPatch, isCssProperty, shorthandLonghands, suggestCssProperty };