@proappstore/compliance 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 (102) hide show
  1. package/README.md +27 -0
  2. package/dist/checks/brand-fonts.d.ts +10 -0
  3. package/dist/checks/brand-fonts.d.ts.map +1 -0
  4. package/dist/checks/brand-fonts.js +47 -0
  5. package/dist/checks/brand-fonts.js.map +1 -0
  6. package/dist/checks/brand-tokens.d.ts +22 -0
  7. package/dist/checks/brand-tokens.d.ts.map +1 -0
  8. package/dist/checks/brand-tokens.js +53 -0
  9. package/dist/checks/brand-tokens.js.map +1 -0
  10. package/dist/checks/bundle-size.d.ts +14 -0
  11. package/dist/checks/bundle-size.d.ts.map +1 -0
  12. package/dist/checks/bundle-size.js +84 -0
  13. package/dist/checks/bundle-size.js.map +1 -0
  14. package/dist/checks/claude-md-slim.d.ts +4 -0
  15. package/dist/checks/claude-md-slim.d.ts.map +1 -0
  16. package/dist/checks/claude-md-slim.js +89 -0
  17. package/dist/checks/claude-md-slim.js.map +1 -0
  18. package/dist/checks/dark-mode.d.ts +20 -0
  19. package/dist/checks/dark-mode.d.ts.map +1 -0
  20. package/dist/checks/dark-mode.js +56 -0
  21. package/dist/checks/dark-mode.js.map +1 -0
  22. package/dist/checks/html-meta.d.ts +16 -0
  23. package/dist/checks/html-meta.d.ts.map +1 -0
  24. package/dist/checks/html-meta.js +51 -0
  25. package/dist/checks/html-meta.js.map +1 -0
  26. package/dist/checks/license-mit.d.ts +13 -0
  27. package/dist/checks/license-mit.d.ts.map +1 -0
  28. package/dist/checks/license-mit.js +45 -0
  29. package/dist/checks/license-mit.js.map +1 -0
  30. package/dist/checks/manifest.d.ts +9 -0
  31. package/dist/checks/manifest.d.ts.map +1 -0
  32. package/dist/checks/manifest.js +43 -0
  33. package/dist/checks/manifest.js.map +1 -0
  34. package/dist/checks/no-brand-overrides.d.ts +25 -0
  35. package/dist/checks/no-brand-overrides.d.ts.map +1 -0
  36. package/dist/checks/no-brand-overrides.js +228 -0
  37. package/dist/checks/no-brand-overrides.js.map +1 -0
  38. package/dist/checks/no-env-production.d.ts +16 -0
  39. package/dist/checks/no-env-production.d.ts.map +1 -0
  40. package/dist/checks/no-env-production.js +37 -0
  41. package/dist/checks/no-env-production.js.map +1 -0
  42. package/dist/checks/no-placeholders.d.ts +10 -0
  43. package/dist/checks/no-placeholders.d.ts.map +1 -0
  44. package/dist/checks/no-placeholders.js +54 -0
  45. package/dist/checks/no-placeholders.js.map +1 -0
  46. package/dist/checks/no-scroll.d.ts +25 -0
  47. package/dist/checks/no-scroll.d.ts.map +1 -0
  48. package/dist/checks/no-scroll.js +109 -0
  49. package/dist/checks/no-scroll.js.map +1 -0
  50. package/dist/checks/no-tracking.d.ts +4 -0
  51. package/dist/checks/no-tracking.d.ts.map +1 -0
  52. package/dist/checks/no-tracking.js +104 -0
  53. package/dist/checks/no-tracking.js.map +1 -0
  54. package/dist/checks/pwa-meta.d.ts +19 -0
  55. package/dist/checks/pwa-meta.d.ts.map +1 -0
  56. package/dist/checks/pwa-meta.js +42 -0
  57. package/dist/checks/pwa-meta.js.map +1 -0
  58. package/dist/checks/pwa-offline.d.ts +40 -0
  59. package/dist/checks/pwa-offline.d.ts.map +1 -0
  60. package/dist/checks/pwa-offline.js +388 -0
  61. package/dist/checks/pwa-offline.js.map +1 -0
  62. package/dist/checks/store-link.d.ts +13 -0
  63. package/dist/checks/store-link.d.ts.map +1 -0
  64. package/dist/checks/store-link.js +30 -0
  65. package/dist/checks/store-link.js.map +1 -0
  66. package/dist/checks/unsafe-vh.d.ts +25 -0
  67. package/dist/checks/unsafe-vh.d.ts.map +1 -0
  68. package/dist/checks/unsafe-vh.js +120 -0
  69. package/dist/checks/unsafe-vh.js.map +1 -0
  70. package/dist/checks/viewport-support.d.ts +24 -0
  71. package/dist/checks/viewport-support.d.ts.map +1 -0
  72. package/dist/checks/viewport-support.js +92 -0
  73. package/dist/checks/viewport-support.js.map +1 -0
  74. package/dist/index.d.ts +38 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +63 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/lib/file-source.d.ts +52 -0
  79. package/dist/lib/file-source.d.ts.map +1 -0
  80. package/dist/lib/file-source.js +156 -0
  81. package/dist/lib/file-source.js.map +1 -0
  82. package/dist/lib/gzip.d.ts +8 -0
  83. package/dist/lib/gzip.d.ts.map +1 -0
  84. package/dist/lib/gzip.js +26 -0
  85. package/dist/lib/gzip.js.map +1 -0
  86. package/dist/lib/project-type.d.ts +18 -0
  87. package/dist/lib/project-type.d.ts.map +1 -0
  88. package/dist/lib/project-type.js +34 -0
  89. package/dist/lib/project-type.js.map +1 -0
  90. package/dist/lib/strip.d.ts +60 -0
  91. package/dist/lib/strip.d.ts.map +1 -0
  92. package/dist/lib/strip.js +169 -0
  93. package/dist/lib/strip.js.map +1 -0
  94. package/dist/live/index.d.ts +50 -0
  95. package/dist/live/index.d.ts.map +1 -0
  96. package/dist/live/index.js +317 -0
  97. package/dist/live/index.js.map +1 -0
  98. package/dist/types.d.ts +12 -0
  99. package/dist/types.d.ts.map +1 -0
  100. package/dist/types.js +2 -0
  101. package/dist/types.js.map +1 -0
  102. package/package.json +47 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-source.js","sourceRoot":"","sources":["../../src/lib/file-source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Gzip via the Web Streams API. Available in Node 18+ and Cloudflare
3
+ * Workers, so the same helper works in both the CLI's filesystem
4
+ * checks and the audit Worker's live checks. Avoids divergence
5
+ * between source-side and live measurements of bundle size.
6
+ */
7
+ export declare function gzipByteLength(input: Uint8Array): Promise<number>;
8
+ //# sourceMappingURL=gzip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gzip.d.ts","sourceRoot":"","sources":["../../src/lib/gzip.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBvE"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Gzip via the Web Streams API. Available in Node 18+ and Cloudflare
3
+ * Workers, so the same helper works in both the CLI's filesystem
4
+ * checks and the audit Worker's live checks. Avoids divergence
5
+ * between source-side and live measurements of bundle size.
6
+ */
7
+ export async function gzipByteLength(input) {
8
+ const readable = new ReadableStream({
9
+ start(controller) {
10
+ controller.enqueue(input);
11
+ controller.close();
12
+ },
13
+ });
14
+ const compressed = readable.pipeThrough(new CompressionStream('gzip'));
15
+ const reader = compressed.getReader();
16
+ let total = 0;
17
+ for (;;) {
18
+ const { value, done } = await reader.read();
19
+ if (done)
20
+ break;
21
+ if (value)
22
+ total += value.byteLength;
23
+ }
24
+ return total;
25
+ }
26
+ //# sourceMappingURL=gzip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gzip.js","sourceRoot":"","sources":["../../src/lib/gzip.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAiB;IACpD,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAa;QAC9C,KAAK,CAAC,UAAU;YACd,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC1B,UAAU,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;KACF,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,CAAC,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;IACtC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,SAAS,CAAC;QACR,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,IAAI;YAAE,MAAM;QAChB,IAAI,KAAK;YAAE,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC;IACvC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { FileSource } from './file-source.js';
2
+ /**
3
+ * "Is this a game project?" — used by checks that diverge between apps
4
+ * (ProAppStore) and games (ProAppStore (games)). Apps run inside a sidebar+
5
+ * scrolling Shell; games run inside a viewport-locked GameShell with
6
+ * different brand tokens. Several rules need to know which they're
7
+ * looking at.
8
+ *
9
+ * Detection signals (any one is sufficient):
10
+ * - `@proappstore/games` listed in any package.json
11
+ * - A TS/JS source file imports from `@proappstore/games`
12
+ *
13
+ * Both signals exist because workspace hoisting can put the dep in the
14
+ * root package.json (where a per-app scan would miss it) and template
15
+ * scaffolds put the import in app source.
16
+ */
17
+ export declare function isGameProject(source: FileSource): Promise<boolean>;
18
+ //# sourceMappingURL=project-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-type.d.ts","sourceRoot":"","sources":["../../src/lib/project-type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAaxE"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * "Is this a game project?" — used by checks that diverge between apps
3
+ * (ProAppStore) and games (ProAppStore (games)). Apps run inside a sidebar+
4
+ * scrolling Shell; games run inside a viewport-locked GameShell with
5
+ * different brand tokens. Several rules need to know which they're
6
+ * looking at.
7
+ *
8
+ * Detection signals (any one is sufficient):
9
+ * - `@proappstore/games` listed in any package.json
10
+ * - A TS/JS source file imports from `@proappstore/games`
11
+ *
12
+ * Both signals exist because workspace hoisting can put the dep in the
13
+ * root package.json (where a per-app scan would miss it) and template
14
+ * scaffolds put the import in app source.
15
+ */
16
+ export async function isGameProject(source) {
17
+ for await (const path of source.list()) {
18
+ const base = path.split('/').pop() ?? '';
19
+ if (base !== 'package.json')
20
+ continue;
21
+ const content = await source.read(path);
22
+ if (content && /@proappstore\/games/.test(content))
23
+ return true;
24
+ }
25
+ for await (const path of source.list()) {
26
+ if (!path.endsWith('.ts') && !path.endsWith('.tsx'))
27
+ continue;
28
+ const content = await source.read(path);
29
+ if (content && /from\s+['"]@proappstore\/games['"]/.test(content))
30
+ return true;
31
+ }
32
+ return false;
33
+ }
34
+ //# sourceMappingURL=project-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-type.js","sourceRoot":"","sources":["../../src/lib/project-type.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAkB;IACpD,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QACzC,IAAI,IAAI,KAAK,cAAc;YAAE,SAAS;QACtC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,OAAO,IAAI,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;IAClE,CAAC;IACD,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,SAAS;QAC9D,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,OAAO,IAAI,oCAAoC,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;IACjF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Source-stripping helpers shared by checks that run regex against raw
3
+ * source files. The whole class of bugs these prevent: a regex matches
4
+ * a token (like `<meta name="viewport">`, `new Audio(`, `100vh`,
5
+ * `@amplitude`) that lives inside a comment or a string literal —
6
+ * never actually evaluated, but the static check fires anyway.
7
+ *
8
+ * Two design rules:
9
+ * 1. All strippers preserve character positions — they replace
10
+ * removed bytes with spaces (newlines kept), so any `regex.index`
11
+ * result still refers to the same line/column in the real source.
12
+ * 2. The strippers don't try to be a full tokenizer. They handle the
13
+ * common cases (escapes inside strings, nested comment-like text
14
+ * inside strings) and accept that pathological constructs
15
+ * (template-literal `${...}` containing braces, regex literals
16
+ * with asymmetric braces) need a real parser. In practice the
17
+ * compliance fixtures don't hit these.
18
+ */
19
+ /** Replace `<!-- ... -->` comment bodies with spaces. */
20
+ export declare function stripHtmlComments(src: string): string;
21
+ /**
22
+ * Replace JS/TS line + block comment bodies AND string-literal
23
+ * contents with spaces. Use this when a regex against the source
24
+ * shouldn't match documentation strings or commented-out code (the
25
+ * common pattern: matching SDK names, API calls, CSS unit tokens).
26
+ *
27
+ * Handles single, double, and backtick strings with `\` escapes.
28
+ * Doesn't track template-literal `${...}` interpolation contents and
29
+ * doesn't recognise regex literals — both edge cases would need a
30
+ * tokenizer.
31
+ */
32
+ export declare function stripCommentsAndStrings(src: string): string;
33
+ /**
34
+ * Like `stripCommentsAndStrings` but preserves string contents.
35
+ * Use when the regex needs to see string values — e.g. inspecting
36
+ * `font-family: "Comic Sans"` inside JSX, where the string value IS
37
+ * the thing being audited.
38
+ */
39
+ export declare function stripCommentsOnly(src: string): string;
40
+ /**
41
+ * Replace `/* ... *​/` comment bodies with spaces. CSS doesn't have
42
+ * `//` line comments at the language level (some preprocessors add
43
+ * them, but plain CSS doesn't), so this is the simpler variant.
44
+ */
45
+ export declare function stripCssComments(src: string): string;
46
+ /**
47
+ * Dispatch to the right stripper based on file extension. For unknown
48
+ * extensions, falls back to `stripCommentsAndStrings` (JS-style) —
49
+ * conservative because most source files compliance checks touch are
50
+ * JS-flavoured.
51
+ */
52
+ export declare function stripForExt(src: string, ext: string): string;
53
+ /**
54
+ * Like `stripForExt` but preserves string-literal contents — useful
55
+ * when the regex needs to match tokens that legitimately appear inside
56
+ * strings (e.g. `@amplitude/` inside an `import from "@amplitude/..."`,
57
+ * which is the literal package-name string we want to catch).
58
+ */
59
+ export declare function stripCommentsForExt(src: string, ext: string): string;
60
+ //# sourceMappingURL=strip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strip.d.ts","sourceRoot":"","sources":["../../src/lib/strip.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,yDAAyD;AACzD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAwBrD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAepD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAa5D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAapE"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Source-stripping helpers shared by checks that run regex against raw
3
+ * source files. The whole class of bugs these prevent: a regex matches
4
+ * a token (like `<meta name="viewport">`, `new Audio(`, `100vh`,
5
+ * `@amplitude`) that lives inside a comment or a string literal —
6
+ * never actually evaluated, but the static check fires anyway.
7
+ *
8
+ * Two design rules:
9
+ * 1. All strippers preserve character positions — they replace
10
+ * removed bytes with spaces (newlines kept), so any `regex.index`
11
+ * result still refers to the same line/column in the real source.
12
+ * 2. The strippers don't try to be a full tokenizer. They handle the
13
+ * common cases (escapes inside strings, nested comment-like text
14
+ * inside strings) and accept that pathological constructs
15
+ * (template-literal `${...}` containing braces, regex literals
16
+ * with asymmetric braces) need a real parser. In practice the
17
+ * compliance fixtures don't hit these.
18
+ */
19
+ /** Replace `<!-- ... -->` comment bodies with spaces. */
20
+ export function stripHtmlComments(src) {
21
+ const out = src.split('');
22
+ let i = 0;
23
+ while (i < src.length) {
24
+ if (src[i] === '<' &&
25
+ src[i + 1] === '!' &&
26
+ src[i + 2] === '-' &&
27
+ src[i + 3] === '-') {
28
+ const start = i;
29
+ i += 4;
30
+ while (i < src.length &&
31
+ !(src[i] === '-' && src[i + 1] === '-' && src[i + 2] === '>'))
32
+ i++;
33
+ i = Math.min(src.length, i + 3);
34
+ blank(out, start, i);
35
+ continue;
36
+ }
37
+ i++;
38
+ }
39
+ return out.join('');
40
+ }
41
+ /**
42
+ * Replace JS/TS line + block comment bodies AND string-literal
43
+ * contents with spaces. Use this when a regex against the source
44
+ * shouldn't match documentation strings or commented-out code (the
45
+ * common pattern: matching SDK names, API calls, CSS unit tokens).
46
+ *
47
+ * Handles single, double, and backtick strings with `\` escapes.
48
+ * Doesn't track template-literal `${...}` interpolation contents and
49
+ * doesn't recognise regex literals — both edge cases would need a
50
+ * tokenizer.
51
+ */
52
+ export function stripCommentsAndStrings(src) {
53
+ return stripCode(src, { strings: true });
54
+ }
55
+ /**
56
+ * Like `stripCommentsAndStrings` but preserves string contents.
57
+ * Use when the regex needs to see string values — e.g. inspecting
58
+ * `font-family: "Comic Sans"` inside JSX, where the string value IS
59
+ * the thing being audited.
60
+ */
61
+ export function stripCommentsOnly(src) {
62
+ return stripCode(src, { strings: false });
63
+ }
64
+ /**
65
+ * Replace `/* ... *​/` comment bodies with spaces. CSS doesn't have
66
+ * `//` line comments at the language level (some preprocessors add
67
+ * them, but plain CSS doesn't), so this is the simpler variant.
68
+ */
69
+ export function stripCssComments(src) {
70
+ const out = src.split('');
71
+ let i = 0;
72
+ while (i < src.length) {
73
+ if (src[i] === '/' && src[i + 1] === '*') {
74
+ const start = i;
75
+ i += 2;
76
+ while (i < src.length && !(src[i] === '*' && src[i + 1] === '/'))
77
+ i++;
78
+ i = Math.min(src.length, i + 2);
79
+ blank(out, start, i);
80
+ continue;
81
+ }
82
+ i++;
83
+ }
84
+ return out.join('');
85
+ }
86
+ /**
87
+ * Dispatch to the right stripper based on file extension. For unknown
88
+ * extensions, falls back to `stripCommentsAndStrings` (JS-style) —
89
+ * conservative because most source files compliance checks touch are
90
+ * JS-flavoured.
91
+ */
92
+ export function stripForExt(src, ext) {
93
+ switch (ext.toLowerCase()) {
94
+ case '.html':
95
+ case '.htm':
96
+ return stripHtmlComments(src);
97
+ case '.css':
98
+ case '.scss':
99
+ return stripCssComments(src);
100
+ case '.json':
101
+ return src; // JSON has no comments
102
+ default:
103
+ return stripCommentsAndStrings(src);
104
+ }
105
+ }
106
+ /**
107
+ * Like `stripForExt` but preserves string-literal contents — useful
108
+ * when the regex needs to match tokens that legitimately appear inside
109
+ * strings (e.g. `@amplitude/` inside an `import from "@amplitude/..."`,
110
+ * which is the literal package-name string we want to catch).
111
+ */
112
+ export function stripCommentsForExt(src, ext) {
113
+ switch (ext.toLowerCase()) {
114
+ case '.html':
115
+ case '.htm':
116
+ return stripHtmlComments(src);
117
+ case '.css':
118
+ case '.scss':
119
+ return stripCssComments(src);
120
+ case '.json':
121
+ return src;
122
+ default:
123
+ return stripCommentsOnly(src);
124
+ }
125
+ }
126
+ function stripCode(src, opts) {
127
+ const out = src.split('');
128
+ let i = 0;
129
+ while (i < src.length) {
130
+ const c = src[i];
131
+ if (c === '/' && src[i + 1] === '/') {
132
+ const start = i;
133
+ while (i < src.length && src[i] !== '\n')
134
+ i++;
135
+ blank(out, start, i);
136
+ continue;
137
+ }
138
+ if (c === '/' && src[i + 1] === '*') {
139
+ const start = i;
140
+ i += 2;
141
+ while (i < src.length && !(src[i] === '*' && src[i + 1] === '/'))
142
+ i++;
143
+ i = Math.min(src.length, i + 2);
144
+ blank(out, start, i);
145
+ continue;
146
+ }
147
+ if (opts.strings && (c === '"' || c === "'" || c === '`')) {
148
+ const quote = c;
149
+ const start = i + 1; // keep the opening quote in place
150
+ i++;
151
+ while (i < src.length && src[i] !== quote) {
152
+ if (src[i] === '\\' && i + 1 < src.length)
153
+ i++;
154
+ i++;
155
+ }
156
+ blank(out, start, i);
157
+ i++; // skip closing quote
158
+ continue;
159
+ }
160
+ i++;
161
+ }
162
+ return out.join('');
163
+ }
164
+ function blank(out, from, to) {
165
+ for (let k = from; k < to; k++)
166
+ if (out[k] !== '\n')
167
+ out[k] = ' ';
168
+ }
169
+ //# sourceMappingURL=strip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strip.js","sourceRoot":"","sources":["../../src/lib/strip.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Live-URL audit checks. Unlike the file-walking checks in ../checks/,
3
+ * these run inside a Cloudflare Worker (no filesystem) against published
4
+ * apps' live URLs to catch post-publish drift.
5
+ *
6
+ * What we can check from a live URL:
7
+ * - Tracking SDK injection (script src, inline scripts, fetched JS)
8
+ * - Brand fonts presence (link href to fonts.googleapis.com)
9
+ * - PWA manifest reachable + valid
10
+ * - Main bundle size (HEAD request)
11
+ *
12
+ * What we CAN'T check post-publish:
13
+ * - APPNAME placeholders (build erases these)
14
+ * - Brand-override CSS variables (sourcemaps not always shipped)
15
+ *
16
+ * The audit Worker runs these on a weekly cron and stores per-app
17
+ * results in D1 so creators (or platform admins) can see drift over
18
+ * time without leaving the storefront.
19
+ */
20
+ import type { CheckResult } from '../types.js';
21
+ export interface LiveAuditInput {
22
+ appId: string;
23
+ liveUrl: string;
24
+ }
25
+ export interface LiveAuditReport {
26
+ appId: string;
27
+ liveUrl: string;
28
+ checkedAt: number;
29
+ reachable: boolean;
30
+ results: CheckResult[];
31
+ }
32
+ export declare function auditLive(input: LiveAuditInput): Promise<LiveAuditReport>;
33
+ export declare function checkNoTrackingLive(html: string): CheckResult;
34
+ export declare function checkBrandFontsLive(html: string): CheckResult;
35
+ export declare function checkManifestLive(html: string, liveUrl: string): Promise<CheckResult>;
36
+ export declare function checkBundleSizeLive(html: string, liveUrl: string): Promise<CheckResult>;
37
+ /**
38
+ * Live counterpart to checkUnsafeVh. Fetches the first bundled
39
+ * stylesheet linked from the HTML and scans it for `100vh` (the
40
+ * unit, not the Tailwind class — by build time those have been
41
+ * compiled to CSS). Catches whiteboard-class iOS Safari URL-bar
42
+ * scroll bugs in apps that have already shipped.
43
+ *
44
+ * Cost: one extra subrequest per app. The audit Worker runs near the
45
+ * free-plan subrequest cap; on cap errors we degrade to `warn`
46
+ * (re-run needed) rather than `fail` (app broken) — the app isn't
47
+ * actually broken, the audit just couldn't check.
48
+ */
49
+ export declare function checkUnsafeVhLive(html: string, liveUrl: string): Promise<CheckResult>;
50
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/live/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAc/C,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AA2BD,wBAAsB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CA2D/E;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAa7D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAe7D;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA8C3F;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAoD7F;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAoD3F"}