@render-policy/core 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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -0
  3. package/dist/binding.d.ts +28 -0
  4. package/dist/binding.d.ts.map +1 -0
  5. package/dist/binding.js +32 -0
  6. package/dist/binding.js.map +1 -0
  7. package/dist/data/sink-domains.d.ts +14 -0
  8. package/dist/data/sink-domains.d.ts.map +1 -0
  9. package/dist/data/sink-domains.js +91 -0
  10. package/dist/data/sink-domains.js.map +1 -0
  11. package/dist/decisions.d.ts +22 -0
  12. package/dist/decisions.d.ts.map +1 -0
  13. package/dist/decisions.js +2 -0
  14. package/dist/decisions.js.map +1 -0
  15. package/dist/dom.d.ts +13 -0
  16. package/dist/dom.d.ts.map +1 -0
  17. package/dist/dom.js +25 -0
  18. package/dist/dom.js.map +1 -0
  19. package/dist/errors.d.ts +3 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +5 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/index.d.ts +19 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +10 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/internal.d.ts +12 -0
  28. package/dist/internal.d.ts.map +1 -0
  29. package/dist/internal.js +10 -0
  30. package/dist/internal.js.map +1 -0
  31. package/dist/markdown.d.ts +15 -0
  32. package/dist/markdown.d.ts.map +1 -0
  33. package/dist/markdown.js +15 -0
  34. package/dist/markdown.js.map +1 -0
  35. package/dist/policy.d.ts +141 -0
  36. package/dist/policy.d.ts.map +1 -0
  37. package/dist/policy.js +110 -0
  38. package/dist/policy.js.map +1 -0
  39. package/dist/render.d.ts +79 -0
  40. package/dist/render.d.ts.map +1 -0
  41. package/dist/render.js +130 -0
  42. package/dist/render.js.map +1 -0
  43. package/dist/sanitize.d.ts +17 -0
  44. package/dist/sanitize.d.ts.map +1 -0
  45. package/dist/sanitize.js +321 -0
  46. package/dist/sanitize.js.map +1 -0
  47. package/dist/sinks.d.ts +16 -0
  48. package/dist/sinks.d.ts.map +1 -0
  49. package/dist/sinks.js +24 -0
  50. package/dist/sinks.js.map +1 -0
  51. package/dist/stream.d.ts +57 -0
  52. package/dist/stream.d.ts.map +1 -0
  53. package/dist/stream.js +180 -0
  54. package/dist/stream.js.map +1 -0
  55. package/dist/url.d.ts +48 -0
  56. package/dist/url.d.ts.map +1 -0
  57. package/dist/url.js +105 -0
  58. package/dist/url.js.map +1 -0
  59. package/dist/window.d.ts +15 -0
  60. package/dist/window.d.ts.map +1 -0
  61. package/dist/window.js +9 -0
  62. package/dist/window.js.map +1 -0
  63. package/package.json +62 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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"}
package/dist/url.d.ts ADDED
@@ -0,0 +1,48 @@
1
+ import type { CoreDecisionCode } from './decisions.js';
2
+ import type { UrlHeuristics, UrlPolicy } from './policy.js';
3
+ export interface ParsedUrl {
4
+ readonly raw: string;
5
+ /** The value after the same preprocessing browsers apply before parsing. */
6
+ readonly normalized: string;
7
+ /** Lower-case scheme the URL resolves to, as the browser would resolve it against the page. */
8
+ readonly scheme: string;
9
+ /** The resolved URL. For a relative URL without a known page base, the base is a placeholder origin. */
10
+ readonly url: URL;
11
+ /** True when the value resolves within the page's own origin without naming a scheme or host. */
12
+ readonly relative: boolean;
13
+ }
14
+ /** Why a URL was refused: a stable code for programs and a reason for people. */
15
+ export interface UrlProblem {
16
+ readonly code: CoreDecisionCode;
17
+ readonly reason: string;
18
+ }
19
+ export type UrlVerdict = {
20
+ readonly ok: true;
21
+ readonly parsed: ParsedUrl;
22
+ } | ({
23
+ readonly ok: false;
24
+ readonly normalized: string;
25
+ } & UrlProblem);
26
+ /**
27
+ * Browsers strip ASCII tab and newline anywhere in a URL, and leading/trailing
28
+ * C0 controls and spaces, before looking for a scheme. `java\tscript:` is `javascript:`.
29
+ */
30
+ export declare function normalizeUrl(raw: string): string;
31
+ /** A usable base for resolution: the page URL when it is http(s), else nothing. */
32
+ export declare function usableBase(href: string | undefined | null): string | undefined;
33
+ /**
34
+ * Scheme allowlist check, resolved the way the browser resolves the value against the page:
35
+ * `//host` takes the page's scheme, `http:path` on an http page stays on the page, and a
36
+ * declared scheme outside the allowlist is rejected before anything is parsed.
37
+ */
38
+ export declare function checkUrl(raw: string, policy: Pick<UrlPolicy, 'allowedSchemes' | 'allowRelativeUrls'>, base?: string): UrlVerdict;
39
+ /** Exact host match, or suffix match for `*.example.com` patterns when wildcards are allowed. */
40
+ export declare function hostMatches(host: string, patterns: readonly string[], allowWildcards: boolean): boolean;
41
+ /** Shannon entropy in bits per character. */
42
+ export declare function shannonEntropy(text: string): number;
43
+ /**
44
+ * Length and entropy heuristics against encoded payloads hidden in a URL
45
+ * (`/img/<base64 of the conversation>.png`). Returns the problem to block for, or null.
46
+ */
47
+ export declare function checkUrlHeuristics(url: URL, heuristics: UrlHeuristics): UrlProblem | null;
48
+ //# sourceMappingURL=url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE5D,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+FAA+F;IAC/F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wGAAwG;IACxG,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,iGAAiG;IACjG,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED,iFAAiF;AACjF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GACjD,CAAC;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,UAAU,CAAC,CAAC;AAMvE;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAE9E;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,gBAAgB,GAAG,mBAAmB,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,CAyBhI;AAED,iGAAiG;AACjG,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,cAAc,EAAE,OAAO,GAAG,OAAO,CAavG;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAUnD;AAKD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,aAAa,GAAG,UAAU,GAAG,IAAI,CAgBzF"}
package/dist/url.js ADDED
@@ -0,0 +1,105 @@
1
+ const SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
2
+ /** Stands in for the page when no base is known; anything that resolves elsewhere is not relative. */
3
+ const PLACEHOLDER_BASE = 'https://relative.invalid/';
4
+ /**
5
+ * Browsers strip ASCII tab and newline anywhere in a URL, and leading/trailing
6
+ * C0 controls and spaces, before looking for a scheme. `java\tscript:` is `javascript:`.
7
+ */
8
+ export function normalizeUrl(raw) {
9
+ return raw.replace(/[\t\n\r]/g, '').replace(/^[\u0000- ]+|[\u0000- ]+$/g, '');
10
+ }
11
+ /** A usable base for resolution: the page URL when it is http(s), else nothing. */
12
+ export function usableBase(href) {
13
+ return href && /^https?:\/\//i.test(href) ? href : undefined;
14
+ }
15
+ /**
16
+ * Scheme allowlist check, resolved the way the browser resolves the value against the page:
17
+ * `//host` takes the page's scheme, `http:path` on an http page stays on the page, and a
18
+ * declared scheme outside the allowlist is rejected before anything is parsed.
19
+ */
20
+ export function checkUrl(raw, policy, base) {
21
+ const normalized = normalizeUrl(raw);
22
+ const declared = SCHEME_RE.test(normalized) ? normalized.slice(0, normalized.indexOf(':')).toLowerCase() : null;
23
+ if (declared !== null && !policy.allowedSchemes.includes(declared)) {
24
+ return { ok: false, code: 'scheme-not-allowed', reason: `scheme "${declared}" is not allowed`, normalized };
25
+ }
26
+ const baseHref = base ?? PLACEHOLDER_BASE;
27
+ let baseOrigin;
28
+ let url;
29
+ try {
30
+ baseOrigin = new URL(baseHref).origin;
31
+ url = new URL(normalized, baseHref);
32
+ }
33
+ catch {
34
+ return { ok: false, code: 'url-unparsable', reason: 'URL does not parse', normalized };
35
+ }
36
+ const scheme = url.protocol.slice(0, -1).toLowerCase();
37
+ if (!policy.allowedSchemes.includes(scheme)) {
38
+ return { ok: false, code: 'scheme-not-allowed', reason: `resolves to scheme "${scheme}", which is not allowed`, normalized };
39
+ }
40
+ const relative = declared === null && url.origin === baseOrigin;
41
+ if (relative && !policy.allowRelativeUrls) {
42
+ return { ok: false, code: 'relative-url-not-allowed', reason: 'relative URLs are not allowed', normalized };
43
+ }
44
+ return { ok: true, parsed: { raw, normalized, scheme, url, relative } };
45
+ }
46
+ /** Exact host match, or suffix match for `*.example.com` patterns when wildcards are allowed. */
47
+ export function hostMatches(host, patterns, allowWildcards) {
48
+ const candidate = host.toLowerCase();
49
+ for (const raw of patterns) {
50
+ const pattern = raw.toLowerCase();
51
+ if (pattern.startsWith('*.')) {
52
+ if (!allowWildcards)
53
+ continue;
54
+ const suffix = pattern.slice(1);
55
+ if (candidate.endsWith(suffix) && candidate.length > suffix.length)
56
+ return true;
57
+ continue;
58
+ }
59
+ if (candidate === pattern)
60
+ return true;
61
+ }
62
+ return false;
63
+ }
64
+ /** Shannon entropy in bits per character. */
65
+ export function shannonEntropy(text) {
66
+ if (text.length === 0)
67
+ return 0;
68
+ const counts = new Map();
69
+ for (const ch of text)
70
+ counts.set(ch, (counts.get(ch) ?? 0) + 1);
71
+ let entropy = 0;
72
+ for (const count of counts.values()) {
73
+ const p = count / text.length;
74
+ entropy -= p * Math.log2(p);
75
+ }
76
+ return entropy;
77
+ }
78
+ const HEX_RE = /^[0-9a-f]+$/i;
79
+ const EXTENSION_RE = /\.[a-z0-9]{1,5}$/i;
80
+ /**
81
+ * Length and entropy heuristics against encoded payloads hidden in a URL
82
+ * (`/img/<base64 of the conversation>.png`). Returns the problem to block for, or null.
83
+ */
84
+ export function checkUrlHeuristics(url, heuristics) {
85
+ if (url.href.length > heuristics.maxLength) {
86
+ return { code: 'url-too-long', reason: `URL is longer than ${heuristics.maxLength} characters` };
87
+ }
88
+ const tokens = [];
89
+ for (const segment of url.pathname.split('/'))
90
+ tokens.push(segment);
91
+ for (const [key, value] of url.searchParams)
92
+ tokens.push(key, value);
93
+ if (url.hash.length > 1)
94
+ tokens.push(url.hash.slice(1));
95
+ for (const raw of tokens) {
96
+ const token = raw.replace(EXTENSION_RE, '');
97
+ if (token.length <= heuristics.maxTokenLength)
98
+ continue;
99
+ if (HEX_RE.test(token) || shannonEntropy(token) >= heuristics.minEntropy) {
100
+ return { code: 'url-encoded-payload', reason: `URL contains a ${token.length}-character token that looks like an encoded payload` };
101
+ }
102
+ }
103
+ return null;
104
+ }
105
+ //# sourceMappingURL=url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.js","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { TrustedTypePolicyFactory } from 'trusted-types/lib/index.js';
2
+ /**
3
+ * The part of a window the renderer needs: the document to create nodes in and the DOM
4
+ * constructors the HTML parser runs with. A browser window and a JSDOM window both fit.
5
+ * This is the library's own type on purpose: the sanitizer's dependency is an implementation
6
+ * detail, and its types never appear in the public API.
7
+ */
8
+ export type RenderWindow = Pick<typeof globalThis, 'DocumentFragment' | 'HTMLTemplateElement' | 'Node' | 'Element' | 'NodeFilter' | 'NamedNodeMap' | 'HTMLFormElement' | 'DOMParser'> & {
9
+ readonly document: Document;
10
+ readonly trustedTypes?: TrustedTypePolicyFactory;
11
+ readonly requestAnimationFrame?: (callback: () => void) => number;
12
+ };
13
+ /** The given window, else the global one, else a clear error naming the package that needs it. */
14
+ export declare function resolveWindow(win: RenderWindow | undefined, packageName?: string): RenderWindow;
15
+ //# sourceMappingURL=window.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"window.d.ts","sourceRoot":"","sources":["../src/window.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAE3E;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,CAC7B,OAAO,UAAU,EACjB,kBAAkB,GAAG,qBAAqB,GAAG,MAAM,GAAG,SAAS,GAAG,YAAY,GAAG,cAAc,GAAG,iBAAiB,GAAG,WAAW,CAClI,GAAG;IACF,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,wBAAwB,CAAC;IACjD,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,CAAC;CACnE,CAAC;AAEF,kGAAkG;AAClG,wBAAgB,aAAa,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,EAAE,WAAW,SAAwB,GAAG,YAAY,CAI9G"}
package/dist/window.js ADDED
@@ -0,0 +1,9 @@
1
+ /** The given window, else the global one, else a clear error naming the package that needs it. */
2
+ export function resolveWindow(win, packageName = '@render-policy/core') {
3
+ if (win)
4
+ return win;
5
+ if (typeof window !== 'undefined')
6
+ return window;
7
+ throw new Error(`${packageName}: no global window. Pass { window } (for example a JSDOM window) outside a browser.`);
8
+ }
9
+ //# sourceMappingURL=window.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"window.js","sourceRoot":"","sources":["../src/window.ts"],"names":[],"mappings":"AAiBA,kGAAkG;AAClG,MAAM,UAAU,aAAa,CAAC,GAA6B,EAAE,WAAW,GAAG,qBAAqB;IAC9F,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC;IACpB,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,MAAiC,CAAC;IAC5E,MAAM,IAAI,KAAK,CAAC,GAAG,WAAW,qFAAqF,CAAC,CAAC;AACvH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@render-policy/core",
3
+ "version": "0.1.0",
4
+ "description": "Render agent-generated Markdown/HTML safely: sanitize into a DocumentFragment, insert with replaceChildren (never innerHTML), enforce a URL/host policy, stay Trusted Types compatible, handle streaming.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./internal": {
16
+ "types": "./dist/internal.d.ts",
17
+ "import": "./dist/internal.js",
18
+ "default": "./dist/internal.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md"
24
+ ],
25
+ "sideEffects": false,
26
+ "scripts": {
27
+ "build": "tsc -p tsconfig.build.json",
28
+ "typecheck": "tsc -p tsconfig.json --noEmit",
29
+ "test": "vitest run"
30
+ },
31
+ "dependencies": {
32
+ "@types/trusted-types": "^2.0.7",
33
+ "dompurify": "^3.4.16",
34
+ "marked": "^18.0.14"
35
+ },
36
+ "keywords": [
37
+ "sanitize",
38
+ "xss",
39
+ "trusted-types",
40
+ "markdown",
41
+ "llm",
42
+ "agent",
43
+ "mcp",
44
+ "dompurify",
45
+ "security"
46
+ ],
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git+https://github.com/shteynu/render-policy.git",
50
+ "directory": "packages/core"
51
+ },
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "typesVersions": {
56
+ "*": {
57
+ "internal": [
58
+ "./dist/internal.d.ts"
59
+ ]
60
+ }
61
+ }
62
+ }