@playpilot/tpi 6.10.7 → 7.0.0-beta.1

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 (37) hide show
  1. package/.env +1 -0
  2. package/build.html +18 -0
  3. package/dist/link-injections.js +2 -11
  4. package/dist/mount.js +12 -0
  5. package/eslint.config.js +1 -0
  6. package/package.json +3 -2
  7. package/src/lib/api/auth.ts +1 -5
  8. package/src/lib/api/externalPages.ts +2 -2
  9. package/src/lib/api/titles.ts +1 -1
  10. package/src/lib/data/translations.ts +25 -0
  11. package/src/lib/injection.ts +0 -91
  12. package/src/lib/injectionElements.ts +90 -0
  13. package/src/lib/language.ts +25 -0
  14. package/src/lib/localization.ts +1 -24
  15. package/src/lib/meta.ts +1 -1
  16. package/src/lib/tracking.ts +0 -1
  17. package/src/lib/types/config.d.ts +5 -0
  18. package/src/lib/types/global.d.ts +6 -3
  19. package/src/lib/types/playlink.d.ts +1 -1
  20. package/src/lib/types/script.d.ts +5 -3
  21. package/src/main.ts +22 -86
  22. package/src/mount.ts +29 -0
  23. package/src/routes/+page.svelte +10 -7
  24. package/src/routes/components/Debugger.svelte +3 -20
  25. package/src/routes/components/Editorial/EditorItem.svelte +2 -1
  26. package/src/routes/components/Editorial/ManualInjection.svelte +1 -1
  27. package/src/routes/components/Playlinks/Playlink.svelte +1 -0
  28. package/src/routes/components/Playlinks/Playlinks.svelte +62 -20
  29. package/src/routes/components/Rails/ParticipantsRail.svelte +1 -1
  30. package/src/tests/lib/{injections.test.js → injection.test.js} +3 -207
  31. package/src/tests/lib/injectionElements.test.js +235 -0
  32. package/src/tests/lib/language.test.js +56 -0
  33. package/src/tests/lib/localization.test.js +3 -55
  34. package/src/tests/routes/components/Playlinks/Playlinks.test.js +52 -1
  35. package/vite._main.config.js +27 -0
  36. package/vite._mount.config.js +54 -0
  37. package/vite.config.js +2 -34
@@ -0,0 +1,235 @@
1
+ import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'
2
+
3
+ import { getLinkInjectionElements, getLinkInjectionsParentElement, getPageText } from '$lib/injectionElements'
4
+
5
+ describe('injectionElements.ts', () => {
6
+ beforeEach(() => {
7
+ vi.resetAllMocks()
8
+
9
+ // @ts-ignore
10
+ window.PlayPilotLinkInjections = {}
11
+ })
12
+
13
+ afterEach(() => {
14
+ vi.useRealTimers()
15
+ })
16
+
17
+ describe('getLinkInjectionElements', () => {
18
+ it('Should return a list of elements inside the given parent', () => {
19
+ document.body.innerHTML = '<section><p>Some paragraph</p><div>Some div</div></section>'
20
+ const parent = /** @type {HTMLElement} */ (document.querySelector('section'))
21
+
22
+ expect(getLinkInjectionElements(parent)).toHaveLength(2)
23
+ })
24
+
25
+ it('Should ignore elements without text content', () => {
26
+ document.body.innerHTML = '<section><p>Some paragraph</p><div></div></section>'
27
+ const parent = /** @type {HTMLElement} */ (document.querySelector('section'))
28
+
29
+ expect(getLinkInjectionElements(parent)).toHaveLength(1)
30
+ })
31
+
32
+ it('Should ignore child elements that were already included in parent text', () => {
33
+ document.body.innerHTML = '<section><p>Some paragraph <div>Some div</div></p></section>'
34
+ const parent = /** @type {HTMLElement} */ (document.querySelector('section'))
35
+
36
+ expect(getLinkInjectionElements(parent)).toHaveLength(1)
37
+ })
38
+
39
+ it('Should return separate elements inside a parent if the parent has no direct text', () => {
40
+ document.body.innerHTML = '<section><div>Some text</div> <div>Some div</div></section>'
41
+ const parent = /** @type {HTMLElement} */ (document.querySelector('section'))
42
+
43
+ expect(getLinkInjectionElements(parent)).toHaveLength(2)
44
+ })
45
+
46
+ it('Should return separate elements when text content is deep', () => {
47
+ document.body.innerHTML = '<section><div><div><main><p>Some <div>text<div></p><p>Some other text</p></main></div></div></section>'
48
+ const parent = /** @type {HTMLElement} */ (document.querySelector('section'))
49
+
50
+ expect(getLinkInjectionElements(parent)).toHaveLength(2)
51
+ })
52
+
53
+ it('Should return a list as a single element', () => {
54
+ document.body.innerHTML = `<section>
55
+ <ul>
56
+ <li>Hey!</li>
57
+ <li>I</li>
58
+ <li>am</li>
59
+ <li>part</li>
60
+ <li>of</li>
61
+ <li>a</li>
62
+ <li>list.</li>
63
+ </ul>
64
+
65
+ <ol>
66
+ <li>Hey!</li>
67
+ <li>I</li>
68
+ <li>am</li>
69
+ <li>part</li>
70
+ <li>of</li>
71
+ <li>a</li>
72
+ <li>list.</li>
73
+ </ol>
74
+ </section>`
75
+ const parent = /** @type {HTMLElement} */ (document.querySelector('section'))
76
+
77
+ expect(getLinkInjectionElements(parent)).toHaveLength(2)
78
+ expect(getLinkInjectionElements(parent)[0].tagName).toBe('UL')
79
+ expect(getLinkInjectionElements(parent)[1].tagName).toBe('OL')
80
+ })
81
+
82
+ it('Should ignore links, buttons, script tags, style tags, iframes, h1, and more', () => {
83
+ document.body.innerHTML = `<section>
84
+ <h1>Some header</h1>
85
+
86
+ <a>I am a link</a>
87
+ <button>And I am a button</button>
88
+
89
+ <script>I am a script</script>
90
+ <style>I am styling</style>
91
+ <iframe>I am an iframe</iframe>
92
+ <noscript>I am noscript</noscript>
93
+ <figcaption>I am a figcaption</figcaption>
94
+ <time>I am time</time>
95
+ <label>I am a label</label>
96
+ <blockquote>I am a quote</blockquote>
97
+
98
+ <div>
99
+ <a>I am another link</a>
100
+ <h4>Some smaller header</h4>
101
+ <p>And finally, some text</p>
102
+ </div>
103
+ </section>`
104
+ const parent = /** @type {HTMLElement} */ (document.querySelector('section'))
105
+
106
+ expect(getLinkInjectionElements(parent)).toHaveLength(2) // The h4 tag and the paragraph tag
107
+ })
108
+
109
+ it('Should ignore links, buttons, and headers even when deeply nested', () => {
110
+ document.body.innerHTML = `<section>
111
+ <div>
112
+ <h2><button>Button inside header</button></h2>
113
+ <div>
114
+ <a><h3>Header inside link</h3></a>
115
+ <p>Some text</p>
116
+ </div>
117
+ </div>
118
+ </section>`
119
+ const parent = /** @type {HTMLElement} */ (document.querySelector('section'))
120
+
121
+ expect(getLinkInjectionElements(parent)).toHaveLength(1)
122
+ })
123
+
124
+ it('Should return an empty array if parent is empty', () => {
125
+ document.body.innerHTML = '<section></section>'
126
+ const parent = /** @type {HTMLElement} */ (document.querySelector('section'))
127
+
128
+ expect(getLinkInjectionElements(parent)).toEqual([])
129
+ })
130
+
131
+ it('Should ignore empty elements', () => {
132
+ document.body.innerHTML = '<section><div>&nbsp;</div><div> </div><div>\n</div><div>Some text</div></section>'
133
+ const parent = /** @type {HTMLElement} */ (document.querySelector('section'))
134
+
135
+ expect(getLinkInjectionElements(parent)).toHaveLength(1)
136
+ })
137
+
138
+ it('Should return elements in the same order they were given', () => {
139
+ document.body.innerHTML = `<section>
140
+ <div>
141
+ <div><span><strong>Some first text</strong></span></div>
142
+ <div>
143
+ <em>Some empasized</em>
144
+ <main><span><em><i>Some deeply nested text</i></em></span></main>
145
+ <div>Some text</div>
146
+ </div>
147
+ </div>
148
+ </section>`
149
+
150
+ const parent = /** @type {HTMLElement} */ (document.querySelector('section'))
151
+ const elements = getLinkInjectionElements(parent)
152
+
153
+ expect(elements).toHaveLength(4)
154
+ expect(elements[0].nodeName).toBe('STRONG')
155
+ expect(elements[1].nodeName).toBe('EM')
156
+ expect(elements[2].nodeName).toBe('I')
157
+ expect(elements[3].nodeName).toBe('DIV')
158
+ })
159
+
160
+ it('Should exclude elements that match or are in the given excludeElementsSelector attribute', () => {
161
+ document.body.innerHTML = `<section>
162
+ <p>I am a regular element</p>
163
+ <div data-exclude>I am to be excluded. <span>And so am I!</span></div>
164
+ </section>
165
+ `
166
+ const parent = /** @type {HTMLElement} */ (document.querySelector('section'))
167
+
168
+ const result = getLinkInjectionElements(parent, '[data-exclude]')
169
+ expect(result).toHaveLength(1)
170
+ expect(result[0].innerText).toBe('I am a regular element')
171
+ })
172
+
173
+ it('Should return paragraphs fully even if they contain no direct text nodes, skipping empty paragraphs', () => {
174
+ document.body.innerHTML = `<section>
175
+ <p>Some text</p>
176
+ <p><span>Some text</span> <span>broken up</span></p>
177
+ <p><span>Some text</span> <span>broken up</span> but also contains direct text</p>
178
+ <p></p>
179
+ </section>`
180
+
181
+ const parent = /** @type {HTMLElement} */ (document.querySelector('section'))
182
+ const elements = getLinkInjectionElements(parent)
183
+
184
+ expect(elements).toHaveLength(3)
185
+ })
186
+ })
187
+
188
+ describe('getLinkInjectionsParentElement', () => {
189
+ it('Should return based on their given importance if no selector is given', () => {
190
+ document.body.innerHTML = '<main><article></article></main>'
191
+ expect(getLinkInjectionsParentElement().nodeName).toBe('ARTICLE')
192
+
193
+ document.body.innerHTML = '<main><div></div></main>'
194
+ expect(getLinkInjectionsParentElement().nodeName).toBe('MAIN')
195
+
196
+ document.body.innerHTML = '<div></div>'
197
+ expect(getLinkInjectionsParentElement().nodeName).toBe('BODY')
198
+ })
199
+
200
+ it('Should return the element matching the given selector', () => {
201
+ // @ts-ignore
202
+ window.PlayPilotLinkInjections.selector = 'section'
203
+ document.body.innerHTML = '<div><section></section></div>'
204
+ expect(getLinkInjectionsParentElement().nodeName).toBe('SECTION')
205
+ })
206
+
207
+ it('Should fall back to fallback elements if selector was given but matching element was not found', () => {
208
+ // @ts-ignore
209
+ window.PlayPilotLinkInjections.selector = 'section'
210
+ document.body.innerHTML = '<div><article></article></div>'
211
+ expect(getLinkInjectionsParentElement().nodeName).toBe('ARTICLE')
212
+ })
213
+
214
+ it('Should escape selectors with :', () => {
215
+ // @ts-ignore
216
+ window.PlayPilotLinkInjections.selector = '.some:class'
217
+ document.body.innerHTML = '<div><section class="some:class"></section></div>'
218
+ expect(getLinkInjectionsParentElement().nodeName).toBe('SECTION')
219
+ })
220
+ })
221
+
222
+ describe('getPageText', () => {
223
+ it('Should return page text for all given elements separated by newlines', () => {
224
+ document.body.innerHTML = `<section>
225
+ <p>Some text</p>
226
+ <p>Some second text</p>
227
+ <p>Some third text</p>
228
+ </section>`
229
+
230
+ expect(getPageText(getLinkInjectionElements(/** @type {HTMLElement} */ (document.querySelector('section'))))).toBe(
231
+ 'Some text\n\nSome second text\n\nSome third text',
232
+ )
233
+ })
234
+ })
235
+ })
@@ -0,0 +1,56 @@
1
+ import { describe, it, expect, afterEach } from 'vitest'
2
+ import { getLanguage } from '$lib/language'
3
+
4
+ describe('language.ts', () => {
5
+ describe('getLanguage', () => {
6
+ afterEach(() => {
7
+ // @ts-expect-error
8
+ window.PlayPilotLinkInjections = {}
9
+ })
10
+
11
+ it('Should return the language given in config object before document language', () => {
12
+ // @ts-expect-error
13
+ window.PlayPilotLinkInjections = { language: 'sv-SE' }
14
+
15
+ const html = /** @type {HTMLElement} */ (document.querySelector('html'))
16
+ html.setAttribute('lang', 'en-US')
17
+
18
+ expect(getLanguage()).toBe('sv-SE')
19
+ })
20
+
21
+ it('Should return the language given as document language when config language is invalid', () => {
22
+ // @ts-expect-error
23
+ window.PlayPilotLinkInjections = { language: 'no' }
24
+
25
+ const html = /** @type {HTMLElement} */ (document.querySelector('html'))
26
+ html.setAttribute('lang', 'sv-SE')
27
+
28
+ expect(getLanguage()).toBe('sv-SE')
29
+ })
30
+
31
+ it('Should return the language given as document language when no config object is set', () => {
32
+ const html = /** @type {HTMLElement} */ (document.querySelector('html'))
33
+ html.setAttribute('lang', 'sv-SE')
34
+
35
+ expect(getLanguage()).toBe('sv-SE')
36
+ })
37
+
38
+ it('Should return the language given as document language even when using shorthand', () => {
39
+ const html = /** @type {HTMLElement} */ (document.querySelector('html'))
40
+ html.setAttribute('lang', 'sv')
41
+
42
+ expect(getLanguage()).toBe('sv-SE')
43
+ })
44
+
45
+ it('Should return the default language when document language is invalid', () => {
46
+ const html = /** @type {HTMLElement} */ (document.querySelector('html'))
47
+ html.setAttribute('lang', 'no')
48
+
49
+ expect(getLanguage()).toBe('en-US')
50
+ })
51
+
52
+ it('Should return the default language no document language or config language is given', () => {
53
+ expect(getLanguage()).toBe('en-US')
54
+ })
55
+ })
56
+ })
@@ -1,9 +1,9 @@
1
- import { describe, it, expect, afterEach } from 'vitest'
2
- import { getLanguage, t } from '$lib/localization'
1
+ import { describe, it, expect } from 'vitest'
2
+ import { t } from '$lib/localization'
3
3
  import { Language } from '$lib/enums/Language'
4
4
  import { translations } from '$lib/data/translations'
5
5
 
6
- describe('localization.js', () => {
6
+ describe('localization.ts', () => {
7
7
  describe('t', () => {
8
8
  it('Should return the value for the given language and key', () => {
9
9
  expect(t(Object.keys(translations)[0], Language.English)).toBe(Object.values(translations)[0][Language.English])
@@ -19,56 +19,4 @@ describe('localization.js', () => {
19
19
  expect(t(Object.keys(translations)[0], 'Some Invalid Language')).toBe(Object.keys(translations)[0])
20
20
  })
21
21
  })
22
-
23
- describe('getLanguage', () => {
24
- afterEach(() => {
25
- // @ts-expect-error
26
- window.PlayPilotLinkInjections = {}
27
- })
28
-
29
- it('Should return the language given in config object before document language', () => {
30
- // @ts-expect-error
31
- window.PlayPilotLinkInjections = { language: 'sv-SE' }
32
-
33
- const html = /** @type {HTMLElement} */ (document.querySelector('html'))
34
- html.setAttribute('lang', 'en-US')
35
-
36
- expect(getLanguage()).toBe('sv-SE')
37
- })
38
-
39
- it('Should return the language given as document language when config language is invalid', () => {
40
- // @ts-expect-error
41
- window.PlayPilotLinkInjections = { language: 'no' }
42
-
43
- const html = /** @type {HTMLElement} */ (document.querySelector('html'))
44
- html.setAttribute('lang', 'sv-SE')
45
-
46
- expect(getLanguage()).toBe('sv-SE')
47
- })
48
-
49
- it('Should return the language given as document language when no config object is set', () => {
50
- const html = /** @type {HTMLElement} */ (document.querySelector('html'))
51
- html.setAttribute('lang', 'sv-SE')
52
-
53
- expect(getLanguage()).toBe('sv-SE')
54
- })
55
-
56
- it('Should return the language given as document language even when using shorthand', () => {
57
- const html = /** @type {HTMLElement} */ (document.querySelector('html'))
58
- html.setAttribute('lang', 'sv')
59
-
60
- expect(getLanguage()).toBe('sv-SE')
61
- })
62
-
63
- it('Should return the default language when document language is invalid', () => {
64
- const html = /** @type {HTMLElement} */ (document.querySelector('html'))
65
- html.setAttribute('lang', 'no')
66
-
67
- expect(getLanguage()).toBe('en-US')
68
- })
69
-
70
- it('Should return the default language no document language or config language is given', () => {
71
- expect(getLanguage()).toBe('en-US')
72
- })
73
- })
74
22
  })
@@ -112,7 +112,7 @@ describe('Playlinks.svelte', () => {
112
112
  expect(getAllByText('Some playlink')).toHaveLength(1)
113
113
  })
114
114
 
115
- it('Should render as list when only one playlink is present', async () => {
115
+ it('Should render as list when only one playlink is present', () => {
116
116
  const playlinks = [
117
117
  { name: 'Some playlink', logo_url: 'logo', extra_info: { category: 'SVOD' } },
118
118
  ]
@@ -122,4 +122,55 @@ describe('Playlinks.svelte', () => {
122
122
  // @ts-ignore
123
123
  expect(container.querySelector('.playlinks').classList).toContain('list')
124
124
  })
125
+
126
+ it('Should categorize and sort playlinks if config option is given', () => {
127
+ // @ts-ignore
128
+ window.PlayPilotLinkInjections = {
129
+ config: { categorize_playlinks: true },
130
+ }
131
+
132
+ const playlinks = [
133
+ { name: 'Some svod playlink', logo_url: 'logo', extra_info: { category: 'SVOD' } },
134
+ { name: 'Some rent playlink', extra_info: { category: 'RENT' } },
135
+ { name: 'Some other rent playlink', logo_url: '', extra_info: { category: 'RENT' } },
136
+ { name: 'Some free playlink', logo_url: null, extra_info: { category: 'AVOD' } },
137
+ ]
138
+
139
+ // @ts-ignore
140
+ const { container, getByText } = render(Playlinks, { playlinks, title })
141
+
142
+ const elements = /** @type {HTMLElement[]} */ (Array.from(container.querySelectorAll('[data-playlink]')))
143
+
144
+ expect(elements[0].innerText).toContain(playlinks[3].name)
145
+ expect(elements[1].innerText).toContain(playlinks[0].name)
146
+ expect(elements[2].innerText).toContain(playlinks[1].name)
147
+ expect(elements[3].innerText).toContain(playlinks[2].name)
148
+
149
+ expect(getByText('Streaming services')).toBeTruthy()
150
+ expect(getByText('Rent it')).toBeTruthy()
151
+ expect(getByText('Stream for free')).toBeTruthy()
152
+ })
153
+
154
+ it('Should list uncategorized playlinks under "other" category', () => {
155
+ // @ts-ignore
156
+ window.PlayPilotLinkInjections = {
157
+ config: { categorize_playlinks: true },
158
+ }
159
+
160
+ const playlinks = [
161
+ { name: 'Some udef playlink', logo_url: 'logo', extra_info: { category: 'UDEF' } },
162
+ { name: 'Some empty playlink', extra_info: { category: '' } },
163
+ { name: 'Some svod playlink', logo_url: '', extra_info: { category: 'SVOD' } },
164
+ { name: 'Some tvod playlink', logo_url: null, extra_info: { category: 'TVOD' } },
165
+ ]
166
+
167
+ // @ts-ignore
168
+ const { getByTestId, getByText } = render(Playlinks, { playlinks, title })
169
+
170
+ expect(getByText('Other')).toBeTruthy()
171
+ expect(getByTestId('category-Other').querySelectorAll('[data-playlink]')).toHaveLength(3)
172
+
173
+ expect(getByText('Streaming services'))
174
+ expect(getByTestId('category-SVOD').querySelectorAll('[data-playlink]')).toHaveLength(1)
175
+ })
125
176
  })
@@ -0,0 +1,27 @@
1
+ import path from 'path'
2
+ import { defineConfig } from 'vitest/config'
3
+ import packageJson from './package.json'
4
+
5
+ export default defineConfig(() => ({
6
+ plugins: [],
7
+
8
+ build: {
9
+ rollupOptions: {
10
+ input: './src/main.ts',
11
+ output: {
12
+ name: 'PlayPilotLinkInjections',
13
+ entryFileNames: 'link-injections.js',
14
+ },
15
+ },
16
+ },
17
+
18
+ resolve: {
19
+ alias: {
20
+ '$lib': path.resolve(__dirname, './src/lib'),
21
+ },
22
+ },
23
+
24
+ define: {
25
+ __SCRIPT_VERSION__: JSON.stringify(packageJson.version),
26
+ },
27
+ }))
@@ -0,0 +1,54 @@
1
+ import path from 'path'
2
+ import * as dotenv from 'dotenv'
3
+ import { defineConfig } from 'vitest/config'
4
+ import { svelte } from '@sveltejs/vite-plugin-svelte'
5
+ import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
6
+ import packageJson from './package.json'
7
+
8
+ dotenv.config({ path: '.env' })
9
+
10
+ export default defineConfig(() => ({
11
+ plugins: [
12
+ svelte(),
13
+ cssInjectedByJsPlugin(),
14
+ injectEnvVariables,
15
+ ],
16
+
17
+ build: {
18
+ emptyOutDir: false,
19
+ rollupOptions: {
20
+ input: './src/mount.ts',
21
+ output: {
22
+ name: 'PlayPilotMount',
23
+ entryFileNames: 'mount.js',
24
+ },
25
+ },
26
+ },
27
+
28
+ resolve: {
29
+ alias: {
30
+ '$lib': path.resolve(__dirname, './src/lib'),
31
+ },
32
+ },
33
+
34
+ define: {
35
+ __SCRIPT_VERSION__: JSON.stringify(packageJson.version),
36
+ },
37
+ }))
38
+
39
+ const injectEnvVariables = {
40
+ name: 'resolve-env-variables',
41
+ /** @param {string} id */
42
+ resolveId(id) {
43
+ if (id === '$env/static/public') return '\0$env/static/public'
44
+ },
45
+ /** @param {string} id */
46
+ load(id) {
47
+ if (id === '\0$env/static/public') {
48
+ return Object.entries(process.env)
49
+ .filter(([key]) => key.startsWith('PUBLIC_'))
50
+ .map(([key, value]) => `export const ${key} = ${JSON.stringify(value)};`)
51
+ .join('\n')
52
+ }
53
+ },
54
+ }
package/vite.config.js CHANGED
@@ -2,30 +2,15 @@ import path from 'path'
2
2
  import * as dotenv from 'dotenv'
3
3
  import { defineConfig } from 'vitest/config'
4
4
  import { sveltekit } from '@sveltejs/kit/vite'
5
- import { svelte } from '@sveltejs/vite-plugin-svelte'
6
- import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'
7
5
  import packageJson from './package.json'
8
6
 
9
7
  dotenv.config({ path: '.env' })
10
8
 
11
- export default defineConfig(({ command }) => ({
9
+ export default defineConfig(() => ({
12
10
  plugins: [
13
- command === 'build' ? svelte() : sveltekit(),
14
- command === 'build' && cssInjectedByJsPlugin(),
15
- command === 'build' && injectEnvVariables,
11
+ sveltekit(),
16
12
  ],
17
13
 
18
- build: {
19
- rollupOptions: {
20
- input: './src/main.ts',
21
- output: {
22
- format: 'iife',
23
- name: 'PlayPilotLinkInjections',
24
- entryFileNames: 'link-injections.js',
25
- },
26
- },
27
- },
28
-
29
14
  server: {
30
15
  port: 3000,
31
16
  },
@@ -47,20 +32,3 @@ export default defineConfig(({ command }) => ({
47
32
  __SCRIPT_VERSION__: JSON.stringify(packageJson.version),
48
33
  },
49
34
  }))
50
-
51
- const injectEnvVariables = {
52
- name: 'resolve-env-variables',
53
- /** @param {string} id */
54
- resolveId(id) {
55
- if (id === '$env/static/public') return '\0$env/static/public'
56
- },
57
- /** @param {string} id */
58
- load(id) {
59
- if (id === '\0$env/static/public') {
60
- return Object.entries(process.env)
61
- .filter(([key]) => key.startsWith('PUBLIC_'))
62
- .map(([key, value]) => `export const ${key} = ${JSON.stringify(value)};`)
63
- .join('\n')
64
- }
65
- },
66
- }