@omg-dev/protocol 0.6.91 → 0.6.92

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.
@@ -0,0 +1,5 @@
1
+ export type ArtifactTheme = "light" | "dark";
2
+ /** Preserve the server's artifact sandbox and bridge the host theme into srcDoc. */
3
+ export declare function secureArtifactDocument(html: string, theme?: ArtifactTheme): string;
4
+ export declare function artifactRequestPath(path: string, query?: Record<string, string | number | undefined>): string;
5
+ //# sourceMappingURL=artifact-document.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-document.d.ts","sourceRoot":"","sources":["../src/artifact-document.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;AAkF7C,oFAAoF;AACpF,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,aAAuB,GAC7B,MAAM,CAoBR;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAM,GACtD,MAAM,CAQR"}
@@ -0,0 +1,108 @@
1
+ const ARTIFACT_CSP = "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data:; base-uri 'none'; form-action 'none'";
2
+ const CSP_META = `<meta http-equiv="Content-Security-Policy" content="${ARTIFACT_CSP}">`;
3
+ const ARTIFACT_PALETTES = {
4
+ light: {
5
+ background: "#f2f2f7",
6
+ surface: "#ffffff",
7
+ foreground: "#000000",
8
+ muted: "#f9f9fb",
9
+ "muted-foreground": "rgba(60, 60, 67, 0.6)",
10
+ border: "rgba(60, 60, 67, 0.12)",
11
+ accent: "#007aff",
12
+ "accent-foreground": "#ffffff",
13
+ "code-background": "rgba(120, 120, 128, 0.08)",
14
+ },
15
+ dark: {
16
+ background: "#000000",
17
+ surface: "#1c1c1e",
18
+ foreground: "#ffffff",
19
+ muted: "#2c2c2e",
20
+ "muted-foreground": "rgba(235, 235, 245, 0.6)",
21
+ border: "rgba(84, 84, 88, 0.35)",
22
+ accent: "#0a84ff",
23
+ "accent-foreground": "#ffffff",
24
+ "code-background": "rgba(118, 118, 128, 0.16)",
25
+ },
26
+ };
27
+ /**
28
+ * Shorthands for the three tokens artifacts reach for most, published alongside
29
+ * the canonical names.
30
+ *
31
+ * An artifact that guesses `--omg-artifact-bg` gets nothing back and silently
32
+ * falls through to its own hardcoded fallback — which is how a card ends up
33
+ * with OMG's dark surfaces and the artifact's light text. Answering the common
34
+ * guess costs three declarations. `muted-fg` is here because the near miss is
35
+ * the expensive one: `--omg-artifact-muted` exists but is a *surface*, so text
36
+ * painted with it disappears into its own background.
37
+ */
38
+ const ARTIFACT_ALIASES = {
39
+ bg: "background",
40
+ fg: "foreground",
41
+ "muted-fg": "muted-foreground",
42
+ };
43
+ // Token prefixes, new first. Artifacts published before the OMG rename hardcode
44
+ // `--lfg-artifact-*` and are still served from disk by this same bridge, so both
45
+ // prefixes are emitted with identical values — an old card must not lose its
46
+ // theming because the brand changed. New artifacts are told about `--omg-*` only.
47
+ const ARTIFACT_TOKEN_PREFIXES = ["--omg-artifact-", "--lfg-artifact-"];
48
+ /**
49
+ * Theme bridge for scripted artifacts.
50
+ *
51
+ * Static artifacts inherit these values through their shadow host. A sandboxed
52
+ * frame has its own document, so it receives the same semantic palette as
53
+ * literal custom properties. This stylesheet is inserted before authored CSS:
54
+ * an artifact's intentional colors still win, while unstyled/theme-aware
55
+ * documents follow OMG automatically.
56
+ */
57
+ function artifactThemeBridge(theme) {
58
+ const palette = ARTIFACT_PALETTES[theme];
59
+ const variables = ARTIFACT_TOKEN_PREFIXES.flatMap((prefix) => [
60
+ ...Object.entries(palette).map(([name, value]) => `${prefix}${name}:${value}`),
61
+ ...Object.entries(ARTIFACT_ALIASES).map(([alias, name]) => `${prefix}${alias}:${palette[name]}`),
62
+ ]).join(";");
63
+ return `<style id="omg-artifact-theme">:root{color-scheme:${theme};${variables}}html,body{background:var(--omg-artifact-surface);color:var(--omg-artifact-foreground)}a{color:var(--omg-artifact-accent)}</style>`;
64
+ }
65
+ /**
66
+ * Stamp the card's theme where CSS can select on it.
67
+ *
68
+ * A card is themed by LFG, not by the desktop, so `prefers-color-scheme` inside
69
+ * the frame answers the wrong question: a dark card on a light machine renders
70
+ * the artifact's light branch over dark surfaces. `data-theme` is the marker
71
+ * artifacts can key on instead, and it matches what the native renderer already
72
+ * rewrites `:root[data-theme=…]` into for the shadow path.
73
+ */
74
+ function withThemeAttribute(tag, theme) {
75
+ if (/\sdata-theme\s*=/i.test(tag))
76
+ return tag;
77
+ return `${tag.replace(/\s*\/?>$/, "")} data-theme="${theme}">`;
78
+ }
79
+ /** Preserve the server's artifact sandbox and bridge the host theme into srcDoc. */
80
+ export function secureArtifactDocument(html, theme = "light") {
81
+ const headContent = `${CSP_META}${artifactThemeBridge(theme)}`;
82
+ const root = html.match(/<html(?:\s[^>]*)?>/i);
83
+ const themed = root?.index !== undefined
84
+ ? `${html.slice(0, root.index)}${withThemeAttribute(root[0], theme)}${html.slice(root.index + root[0].length)}`
85
+ : html;
86
+ const head = themed.match(/<head(?:\s[^>]*)?>/i);
87
+ if (head?.index !== undefined) {
88
+ const insertAt = head.index + head[0].length;
89
+ return `${themed.slice(0, insertAt)}${headContent}${themed.slice(insertAt)}`;
90
+ }
91
+ const themedRoot = themed.match(/<html(?:\s[^>]*)?>/i);
92
+ if (themedRoot?.index !== undefined) {
93
+ const insertAt = themedRoot.index + themedRoot[0].length;
94
+ return `${themed.slice(0, insertAt)}<head>${headContent}</head>${themed.slice(insertAt)}`;
95
+ }
96
+ return `<!doctype html><html data-theme="${theme}"><head>${headContent}</head><body>${themed}</body></html>`;
97
+ }
98
+ export function artifactRequestPath(path, query = {}) {
99
+ const [base, rawQuery = ""] = path.split("?", 2);
100
+ const params = new URLSearchParams(rawQuery);
101
+ for (const [key, value] of Object.entries(query)) {
102
+ if (value !== undefined)
103
+ params.set(key, String(value));
104
+ }
105
+ const suffix = params.toString();
106
+ return suffix ? `${base}?${suffix}` : base;
107
+ }
108
+ //# sourceMappingURL=artifact-document.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-document.js","sourceRoot":"","sources":["../src/artifact-document.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omg-dev/protocol",
3
- "version": "0.6.91",
3
+ "version": "0.6.92",
4
4
  "description": "Typed public protocol for OMG sessions and live streams.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://omg.dev",