-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathwxt.config.ts
More file actions
132 lines (127 loc) · 4.5 KB
/
Copy pathwxt.config.ts
File metadata and controls
132 lines (127 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import { defineConfig } from 'wxt';
import tailwindcss from '@tailwindcss/vite';
type OutputChunk = { type: 'chunk'; code: string };
type OutputAsset = { type: 'asset' };
type OutputBundle = Record<string, OutputChunk | OutputAsset>;
type BundlePlugin = {
name: string;
enforce: 'post';
generateBundle: (_options: unknown, bundle: OutputBundle) => void;
};
// Chrome refuses to load extension scripts whose contents fail its strict
// `IsStringUTF8` check. That check rejects Unicode "non-characters"
// (U+FDD0–U+FDEF, U+FFFE, U+FFFF and their astral equivalents) and we also
// defensively strip the BOM/ZWNBSP (U+FEFF) and C0 control characters. These
// code points can legitimately appear inside dependency string/regex literals
// (e.g. Unicode-range regexes), so we re-emit them as equivalent `\uXXXX`
// escapes — byte-for-byte identical at runtime, but guaranteed ASCII-safe so
// the bundle always loads in Chrome.
const UNSAFE_CHARS =
/[\u0000-\u0008\u000B\u000C\u000E-\u001F\uFEFF\uFDD0-\uFDEF\uFFFE\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
function escapeUnsafeChars(code: string): string {
return code.replace(UNSAFE_CHARS, (match) => {
if (match.length === 2) {
// Surrogate pair: only escape genuine non-characters (U+nFFFE / U+nFFFF),
// leave ordinary astral characters (emoji, CJK ext, …) untouched.
const low = (match.codePointAt(0) as number) & 0xffff;
if (low !== 0xfffe && low !== 0xffff) return match;
return (
'\\u' + match.charCodeAt(0).toString(16).padStart(4, '0') +
'\\u' + match.charCodeAt(1).toString(16).padStart(4, '0')
);
}
return '\\u' + match.charCodeAt(0).toString(16).padStart(4, '0');
});
}
function asciiSafeOutput(): BundlePlugin {
return {
name: 'stemlm:ascii-safe-output',
enforce: 'post',
generateBundle(_options, bundle) {
for (const file of Object.values(bundle)) {
if (file.type === 'chunk') {
file.code = escapeUnsafeChars(file.code);
}
}
},
};
}
// stemLM WXT configuration.
// GA4 Measurement Protocol credentials are injected at build time via env vars
// (see .env.example). They are intentionally empty by default — the analytics
// module no-ops until the user fills them in.
export default defineConfig({
modules: ['@wxt-dev/module-react'],
srcDir: '.',
imports: false, // we use explicit imports for clarity / testability
zip: {
// Extension artifact zips are built from .output/ only; these patterns apply to
// Firefox source zips and any extra files WXT might bundle alongside the build.
exclude: ['**/*.md', 'docs/**', 'scripts/**'],
excludeSources: [
'docs/**',
'**/*.md',
'!src/protocol/*.md',
'scripts/**',
'vitest.config.ts',
'**/*.test.ts',
'**/*.test.tsx',
'pnpm-lock.yaml',
],
},
vite: () => ({
plugins: [tailwindcss(), asciiSafeOutput()],
define: {
__GA_MEASUREMENT_ID__: JSON.stringify(process.env.STEMLM_GA_MEASUREMENT_ID ?? ''),
__GA_API_SECRET__: JSON.stringify(process.env.STEMLM_GA_API_SECRET ?? ''),
},
}),
manifest: {
name: 'stemLM — Structured STEM Study Overlay',
short_name: 'stemLM',
description:
'Turn ChatGPT, Claude, Gemini, and Grok into a guided STEM study workspace: step-by-step solutions, step-synced diagrams, quick-checks, and clean PDF export.',
homepage_url: 'https://github.com/chayprabs/stemlm-app',
minimum_chrome_version: '116',
permissions: ['storage', 'tabs', 'downloads'],
host_permissions: [
'https://fonts.googleapis.com/*',
'https://fonts.gstatic.com/*',
'https://www.google-analytics.com/*',
'*://chatgpt.com/*',
'*://*.chatgpt.com/*',
'*://chat.openai.com/*',
'*://*.chat.openai.com/*',
'*://claude.ai/*',
'*://*.claude.ai/*',
'*://gemini.google.com/*',
'*://*.gemini.google.com/*',
'*://grok.com/*',
'*://*.grok.com/*',
],
action: {
default_title: 'stemLM — study overlay',
},
options_ui: {
open_in_tab: true,
},
web_accessible_resources: [
{
resources: ['icon/*.png'],
matches: [
'*://chatgpt.com/*',
'*://*.chatgpt.com/*',
'*://chat.openai.com/*',
'*://*.chat.openai.com/*',
'*://claude.ai/*',
'*://*.claude.ai/*',
'*://gemini.google.com/*',
'*://*.gemini.google.com/*',
'*://grok.com/*',
'*://*.grok.com/*',
],
use_dynamic_url: true,
},
],
},
});