@playpilot/tpi 8.10.4-beta.1 → 8.10.4-beta.3
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.
- package/dist/editorial.mount.js +8 -8
- package/dist/link-injections.js +2 -2
- package/dist/mount.js +6 -6
- package/package.json +1 -1
- package/src/lib/api/externalPages.ts +18 -15
- package/src/lib/api/session.ts +5 -7
- package/src/lib/injectionElements.ts +1 -1
- package/src/main.ts +1 -4
- package/src/routes/+page.svelte +4 -12
- package/src/routes/components/Editorial/Editor.svelte +3 -4
- package/src/routes/components/Editorial/ManualInjection.svelte +4 -3
- package/src/routes/components/Editorial/Session.svelte +2 -4
- package/src/routes/components/Explore/ExploreLayout.svelte +1 -0
- package/src/tests/lib/api/externalPages.test.js +44 -22
- package/src/tests/main.test.js +0 -1
- package/src/tests/routes/+page.test.js +4 -4
package/package.json
CHANGED
|
@@ -6,6 +6,7 @@ import type { LinkInjectionResponse, LinkInjection } from '../types/injection'
|
|
|
6
6
|
import { getFullUrlPath } from '../url'
|
|
7
7
|
import { api } from './api'
|
|
8
8
|
import { getApiToken } from '$lib/token'
|
|
9
|
+
import { getPageTextAndElements } from '$lib/injectionElements'
|
|
9
10
|
|
|
10
11
|
let pollTimeout: ReturnType<typeof setTimeout> | null = null
|
|
11
12
|
|
|
@@ -13,9 +14,8 @@ let pollTimeout: ReturnType<typeof setTimeout> | null = null
|
|
|
13
14
|
* Fetch link injections for a URL. This will be either a POST or a GET request depending on whether on not the AI should run.
|
|
14
15
|
*/
|
|
15
16
|
export async function fetchLinkInjections(
|
|
16
|
-
|
|
17
|
-
{ url
|
|
18
|
-
{ url?: string, hash?: string, params?: Record<string, any>, method?: 'GET' | 'POST' } = {},
|
|
17
|
+
{ url = getFullUrlPath(), params = {}, method = 'GET' }:
|
|
18
|
+
{ url?: string, params?: Record<string, any>, method?: 'GET' | 'POST' } = {},
|
|
19
19
|
): Promise<LinkInjectionResponse> {
|
|
20
20
|
const apiToken = getApiToken()
|
|
21
21
|
const isEditorialMode = isEditorialModeEnabled() ? await authorize() : false
|
|
@@ -26,13 +26,13 @@ export async function fetchLinkInjections(
|
|
|
26
26
|
const apiUrl = `/external-pages/?api-token=${apiToken}&include_title_details=true${isEditorialMode ? '&editorial_mode_enabled=true' : ''}&language=${language}`
|
|
27
27
|
let response: LinkInjectionResponse
|
|
28
28
|
|
|
29
|
-
console.log('page text in fetchLinkInjections', { pageText })
|
|
30
|
-
|
|
31
29
|
// We use separate requests when running the AI or setting the editor session vs when only getting the results.
|
|
32
30
|
// For regular requests we use a GET endpoint, but when saving data we POST to the same url.
|
|
33
31
|
if (method === 'POST') {
|
|
32
|
+
const { pageText } = getPageTextAndElements()
|
|
33
|
+
|
|
34
34
|
if (params.run_ai) {
|
|
35
|
-
params.hash =
|
|
35
|
+
params.hash = stringToHash(pageText || '')
|
|
36
36
|
params.page_text = pageText
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -62,7 +62,6 @@ export async function fetchLinkInjections(
|
|
|
62
62
|
* The results return `injections_ready=false` while the injections are not yet ready.
|
|
63
63
|
*/
|
|
64
64
|
export async function pollLinkInjections(
|
|
65
|
-
pageText: string,
|
|
66
65
|
{ requireCompletedResult = false, runAiWhenRelevant = false, pollInterval = 3000, maxTries = 600, onpoll = () => null }:
|
|
67
66
|
{ requireCompletedResult?: boolean, runAiWhenRelevant?: boolean, pollInterval?: number, maxTries?: number, onpoll?: (_response: LinkInjectionResponse) => void } = {},
|
|
68
67
|
): Promise<LinkInjectionResponse> {
|
|
@@ -72,8 +71,6 @@ export async function pollLinkInjections(
|
|
|
72
71
|
// This is mostly handy during HMR, but also during navigation changes
|
|
73
72
|
if (pollTimeout) clearTimeout(pollTimeout)
|
|
74
73
|
|
|
75
|
-
console.log('page text in pollLinkInjections', { pageText })
|
|
76
|
-
|
|
77
74
|
const poll = async (resolve: Function, reject: Function): Promise<void> => {
|
|
78
75
|
let response
|
|
79
76
|
try {
|
|
@@ -81,19 +78,25 @@ export async function pollLinkInjections(
|
|
|
81
78
|
// if it does. We're still interested in handling the response from here and don't want it to short circuit
|
|
82
79
|
// just because the fetch failed.
|
|
83
80
|
try {
|
|
84
|
-
response = await fetchLinkInjections(
|
|
81
|
+
response = await fetchLinkInjections()
|
|
85
82
|
} catch(error: any) {
|
|
83
|
+
console.error(error)
|
|
86
84
|
if (error?.status === 404) {
|
|
87
85
|
// If the GET endpoint returns a 404 no article has been generated yet and we can safely generate
|
|
88
86
|
// a new article. We can safely throw here (meaning we poll again) as nothing will be returned.
|
|
89
87
|
// The first POST indexes the article, the second runs the AI if needed.
|
|
90
|
-
response = await fetchLinkInjections(
|
|
91
|
-
if (response.ai_enabled) response = await fetchLinkInjections(
|
|
88
|
+
response = await fetchLinkInjections({ method: 'POST' })
|
|
89
|
+
if (response.ai_enabled) response = await fetchLinkInjections({ params: { run_ai: true }, method: 'POST' })
|
|
92
90
|
}
|
|
93
91
|
|
|
94
92
|
throw new Error
|
|
95
93
|
}
|
|
96
94
|
|
|
95
|
+
const { pageText } = getPageTextAndElements()
|
|
96
|
+
|
|
97
|
+
console.log(pageText)
|
|
98
|
+
console.log(document.querySelector('#content')?.innerText)
|
|
99
|
+
|
|
97
100
|
if (response && runAiWhenRelevant) response = await runAiBasedOnResponse(pageText, response)
|
|
98
101
|
if (requireCompletedResult && (response.ai_enabled && response.ai_running)) throw new Error
|
|
99
102
|
|
|
@@ -137,10 +140,10 @@ export async function runAiBasedOnResponse(pageText: string, response: LinkInjec
|
|
|
137
140
|
if (response.ai_last_run && isCurrentTimeEqualToResponseTime) return response
|
|
138
141
|
if (new Date(currentModifiedTime || 0) <= new Date(responseModifiedTime || 0)) return response
|
|
139
142
|
|
|
140
|
-
return await fetchLinkInjections(
|
|
143
|
+
return await fetchLinkInjections({ params: { run_ai: true }, method: 'POST' })
|
|
141
144
|
}
|
|
142
145
|
|
|
143
|
-
export async function saveLinkInjections(linkInjections: LinkInjection[]
|
|
146
|
+
export async function saveLinkInjections(linkInjections: LinkInjection[]): Promise<LinkInjection[]> {
|
|
144
147
|
const selector = window.PlayPilotLinkInjections?.selector
|
|
145
148
|
|
|
146
149
|
// Only save manual injections, AI injections should be left intact and can't be saved over
|
|
@@ -160,7 +163,7 @@ export async function saveLinkInjections(linkInjections: LinkInjection[], pageTe
|
|
|
160
163
|
removed: !!linkInjection.removed,
|
|
161
164
|
}))
|
|
162
165
|
|
|
163
|
-
const response = await fetchLinkInjections(
|
|
166
|
+
const response = await fetchLinkInjections({
|
|
164
167
|
method: 'POST',
|
|
165
168
|
params: {
|
|
166
169
|
private_token: getAuthToken(),
|
package/src/lib/api/session.ts
CHANGED
|
@@ -11,10 +11,9 @@ export const sessionPeriodMilliseconds = sessionPollPeriodMilliseconds * 2
|
|
|
11
11
|
* where we save the session.
|
|
12
12
|
* Along with that, we also return ai_enabled and injections_enabled as they are used to update the state of
|
|
13
13
|
* the current editing session.
|
|
14
|
-
* @param pageText Despite not being used, the request still requires a valid pageText string
|
|
15
14
|
*/
|
|
16
|
-
export async function fetchAsSession(
|
|
17
|
-
const { ai_enabled, injections_enabled, ai_last_run, session_id, session_last_ping } = await fetchLinkInjections(
|
|
15
|
+
export async function fetchAsSession(): Promise<SessionResponse> {
|
|
16
|
+
const { ai_enabled, injections_enabled, ai_last_run, session_id, session_last_ping } = await fetchLinkInjections()
|
|
18
17
|
|
|
19
18
|
const isCurrentlyAllowToEdit = isAllowedToEdit(session_id || null, session_last_ping || null)
|
|
20
19
|
|
|
@@ -28,15 +27,14 @@ export async function fetchAsSession(pageText: string): Promise<SessionResponse>
|
|
|
28
27
|
|
|
29
28
|
if (!isCurrentlyAllowToEdit) return response
|
|
30
29
|
|
|
31
|
-
return await saveCurrentSession(
|
|
30
|
+
return await saveCurrentSession()
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
/**
|
|
35
34
|
* Save the current users session id as the currently active session. This is always completed regardless of if the user
|
|
36
35
|
* is the current owner of the session, so check that first if necessary!
|
|
37
|
-
* @param pageText Despite not being used, the request still requires a valid pageText string
|
|
38
36
|
*/
|
|
39
|
-
export async function saveCurrentSession(
|
|
37
|
+
export async function saveCurrentSession(): Promise<SessionResponse> {
|
|
40
38
|
const sessionId = getSessionId()
|
|
41
39
|
const now = new Date(Date.now()).toISOString()
|
|
42
40
|
|
|
@@ -45,7 +43,7 @@ export async function saveCurrentSession(pageText: string): Promise<SessionRespo
|
|
|
45
43
|
session_last_ping: now.toString(),
|
|
46
44
|
}
|
|
47
45
|
|
|
48
|
-
const { ai_enabled, injections_enabled, ai_last_run } = await fetchLinkInjections(
|
|
46
|
+
const { ai_enabled, injections_enabled, ai_last_run } = await fetchLinkInjections({ params })
|
|
49
47
|
|
|
50
48
|
return {
|
|
51
49
|
ai_enabled,
|
|
@@ -91,7 +91,7 @@ export function getPageText(elements: HTMLElement[]): string {
|
|
|
91
91
|
return elements.map(element => element.innerText).join('\n\n')
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
export function getPageTextAndElements(config: ConfigResponse | null): { parentElement: HTMLElement, elements: HTMLElement[], pageText: string } {
|
|
94
|
+
export function getPageTextAndElements(config: ConfigResponse | null = window.PlayPilotLinkInjections?.config || null): { parentElement: HTMLElement, elements: HTMLElement[], pageText: string } {
|
|
95
95
|
const parentElement = getLinkInjectionsParentElement()
|
|
96
96
|
const elements = getLinkInjectionElements(parentElement, config?.exclude_elements_selector || '')
|
|
97
97
|
const pageText = getPageText(elements)
|
package/src/main.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { fetchConfig } from '$lib/api/config'
|
|
|
3
3
|
import { pollLinkInjections } from '$lib/api/externalPages'
|
|
4
4
|
import { setConsent } from '$lib/consent'
|
|
5
5
|
import { isCrawler } from '$lib/crawler'
|
|
6
|
-
import { getPageTextAndElements } from '$lib/injectionElements'
|
|
7
6
|
import { isUrlExcludedViaConfig } from '$lib/url'
|
|
8
7
|
|
|
9
8
|
window.PlayPilotLinkInjections ||= {
|
|
@@ -70,9 +69,7 @@ window.PlayPilotLinkInjections ||= {
|
|
|
70
69
|
|
|
71
70
|
if (isUrlExcludedViaConfig(this.config)) return
|
|
72
71
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
this.initial_link_injections_promise = pollLinkInjections(pageText, { maxTries: 1, runAiWhenRelevant: !isCrawler() })
|
|
72
|
+
this.initial_link_injections_promise = pollLinkInjections({ maxTries: 1, runAiWhenRelevant: !isCrawler() })
|
|
76
73
|
|
|
77
74
|
this.mount()
|
|
78
75
|
},
|
package/src/routes/+page.svelte
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { onDestroy } from 'svelte'
|
|
3
3
|
import { pollLinkInjections } from '$lib/api/externalPages'
|
|
4
4
|
import { clearLinkInjections, injectLinksInDocument, separateLinkInjectionTypes } from '$lib/injection'
|
|
5
|
-
import { getPageText, getPageTextAndElements } from '$lib/injectionElements'
|
|
6
5
|
import { fireQueuedTrackingEvents, setTrackingSids, track } from '$lib/tracking'
|
|
7
6
|
import { isUrlExcludedViaConfig } from '$lib/url'
|
|
8
7
|
import { isCrawler } from '$lib/crawler'
|
|
@@ -11,6 +10,7 @@
|
|
|
11
10
|
import { fetchConfig } from '$lib/api/config'
|
|
12
11
|
import { insertExplore, insertExploreIntoNavigation } from '$lib/explore'
|
|
13
12
|
import { authorize, getAuthToken, isEditorialModeEnabled, removeAuthCookie, setEditorialParamInUrl } from '$lib/api/auth'
|
|
13
|
+
import { getPageTextAndElements } from '$lib/injectionElements'
|
|
14
14
|
import type { LinkInjectionResponse, LinkInjection, LinkInjectionTypes } from '$lib/types/injection'
|
|
15
15
|
import Editor from './components/Editorial/Editor.svelte'
|
|
16
16
|
import EditorTrigger from './components/Editorial/EditorTrigger.svelte'
|
|
@@ -22,8 +22,6 @@
|
|
|
22
22
|
import PostersScrollReveal from './components/PostersScrollReveal.svelte'
|
|
23
23
|
import TrackingPixelsForTitleDataPerLink from './components/TrackingPixelsForTitleDataPerLink.svelte'
|
|
24
24
|
|
|
25
|
-
let elements: HTMLElement[] = $state([])
|
|
26
|
-
|
|
27
25
|
let response: LinkInjectionResponse | null = $state(null)
|
|
28
26
|
let isEditorialMode = $state(isEditorialModeEnabled())
|
|
29
27
|
let hasAuthToken = $state(!!getAuthToken())
|
|
@@ -35,10 +33,6 @@
|
|
|
35
33
|
// @ts-ignore It's ok if the response is empty
|
|
36
34
|
const { ai_injections: aiInjections = [], manual_injections: manualInjections = [] } = $derived(response || {})
|
|
37
35
|
|
|
38
|
-
const pageText = $derived(getPageText(elements))
|
|
39
|
-
|
|
40
|
-
$inspect({ thing: 'pageText in page.svelte', pageText })
|
|
41
|
-
|
|
42
36
|
const initializePromise = initialize()
|
|
43
37
|
|
|
44
38
|
$effect(() => {
|
|
@@ -88,8 +82,6 @@
|
|
|
88
82
|
if (isUrlExcluded) return
|
|
89
83
|
|
|
90
84
|
if (config?.html_selector) window.PlayPilotLinkInjections.selector = config?.html_selector
|
|
91
|
-
|
|
92
|
-
elements = getPageTextAndElements(window.PlayPilotLinkInjections.config).elements
|
|
93
85
|
} catch(error) {
|
|
94
86
|
// We return if the config did not get fetched properly, as we can't determine what should and should
|
|
95
87
|
// get injected without it.
|
|
@@ -100,7 +92,7 @@
|
|
|
100
92
|
|
|
101
93
|
try {
|
|
102
94
|
response = await window.PlayPilotLinkInjections.initial_link_injections_promise || null
|
|
103
|
-
response ||= await pollLinkInjections(
|
|
95
|
+
response ||= await pollLinkInjections({ maxTries: 1, runAiWhenRelevant: !isCrawler() })
|
|
104
96
|
|
|
105
97
|
loading = false
|
|
106
98
|
|
|
@@ -116,7 +108,7 @@
|
|
|
116
108
|
|
|
117
109
|
if (!isEditorialMode || isCrawler()) return
|
|
118
110
|
|
|
119
|
-
response = await pollLinkInjections(
|
|
111
|
+
response = await pollLinkInjections({ requireCompletedResult: true, onpoll: (update) => response = update })
|
|
120
112
|
inject({ aiInjections, manualInjections })
|
|
121
113
|
} catch(error: unknown) {
|
|
122
114
|
console.error(error)
|
|
@@ -138,6 +130,7 @@
|
|
|
138
130
|
}
|
|
139
131
|
|
|
140
132
|
function inject(injections: LinkInjectionTypes = { aiInjections, manualInjections }): void {
|
|
133
|
+
const { elements } = getPageTextAndElements()
|
|
141
134
|
const filteredInjections = injectLinksInDocument(elements, injections)
|
|
142
135
|
|
|
143
136
|
if (JSON.stringify(filteredInjections) !== JSON.stringify(linkInjections)) {
|
|
@@ -208,7 +201,6 @@
|
|
|
208
201
|
<svelte:boundary onerror={(error) => track(TrackingEvent.EditorError, null, { message: (error as Error).message })}>
|
|
209
202
|
<Editor
|
|
210
203
|
bind:linkInjections
|
|
211
|
-
{pageText}
|
|
212
204
|
{loading}
|
|
213
205
|
onreinitialize={reinitializeEditor}
|
|
214
206
|
injectionsEnabled={response?.injections_enabled}
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
|
|
34
34
|
let {
|
|
35
35
|
linkInjections = $bindable(),
|
|
36
|
-
pageText = '',
|
|
37
36
|
loading = false,
|
|
38
37
|
injectionsEnabled = false,
|
|
39
38
|
aiStatus = {},
|
|
@@ -46,6 +45,8 @@
|
|
|
46
45
|
const position: Position = JSON.parse(localStorage.getItem(editorPositionKey) || '{ "x": 0, "y": 0 }')
|
|
47
46
|
const height: number = parseInt(localStorage.getItem(editorHeightKey) || '0')
|
|
48
47
|
|
|
48
|
+
|
|
49
|
+
|
|
49
50
|
let editorElement: HTMLElement | null = $state(null)
|
|
50
51
|
let manualInjectionActive = $state(false)
|
|
51
52
|
let saving = $state(false)
|
|
@@ -85,7 +86,7 @@
|
|
|
85
86
|
saving = true
|
|
86
87
|
hasError = false
|
|
87
88
|
|
|
88
|
-
linkInjections = await saveLinkInjections(linkInjections
|
|
89
|
+
linkInjections = await saveLinkInjections(linkInjections)
|
|
89
90
|
initialStateString = linkInjectionsString
|
|
90
91
|
} catch {
|
|
91
92
|
hasError = true
|
|
@@ -177,7 +178,6 @@
|
|
|
177
178
|
|
|
178
179
|
{#if !loading}
|
|
179
180
|
<Session
|
|
180
|
-
{pageText}
|
|
181
181
|
onallow={() => allowEditing = true}
|
|
182
182
|
ondisallow={() => allowEditing = false}
|
|
183
183
|
ontakeover={onreinitialize}
|
|
@@ -231,7 +231,6 @@
|
|
|
231
231
|
style:top="{scrollDistance}px"
|
|
232
232
|
transition:fly={{ x: Math.min(window.innerWidth, 320), duration: 200, opacity: 1 }}>
|
|
233
233
|
<ManualInjection
|
|
234
|
-
{pageText}
|
|
235
234
|
onclose={() => manualInjectionActive = false}
|
|
236
235
|
onsave={(linkInjection) => linkInjections.push(linkInjection)} />
|
|
237
236
|
</div>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { onMount } from 'svelte'
|
|
5
5
|
import { playPilotBaseUrl } from '$lib/constants'
|
|
6
6
|
import { generateInjectionKey } from '$lib/api/externalPages'
|
|
7
|
-
import { getLinkInjectionsParentElement } from '$lib/injectionElements'
|
|
7
|
+
import { getLinkInjectionsParentElement, getPageTextAndElements } from '$lib/injectionElements'
|
|
8
8
|
import { heading } from '$lib/actions/heading'
|
|
9
9
|
import { findSurroundingPhrases, cleanPhrase } from '$lib/text'
|
|
10
10
|
import { getIndexOfSelection } from '$lib/selection'
|
|
@@ -15,12 +15,13 @@
|
|
|
15
15
|
import TitleSearch from './Search/TitleSearch.svelte'
|
|
16
16
|
|
|
17
17
|
interface Props {
|
|
18
|
-
pageText: string
|
|
19
18
|
onsave: (linkInjection: LinkInjection) => void
|
|
20
19
|
onclose?: () => void
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
const {
|
|
22
|
+
const { onsave, onclose = () => null }: Props = $props()
|
|
23
|
+
|
|
24
|
+
const { pageText } = getPageTextAndElements()
|
|
24
25
|
|
|
25
26
|
let currentSelection = $state('')
|
|
26
27
|
let selectionSentence = $state('')
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
import Alert from './Alert.svelte'
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
7
|
-
pageText?: string,
|
|
8
7
|
onpoll?: ({ injectionsEnabled, aiEnabled }: { injectionsEnabled: boolean, aiEnabled: boolean }) => void,
|
|
9
8
|
onallow?: () => void,
|
|
10
9
|
ondisallow?: () => void,
|
|
@@ -12,7 +11,6 @@
|
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
const {
|
|
15
|
-
pageText = '',
|
|
16
14
|
onpoll = () => null,
|
|
17
15
|
onallow = () => null,
|
|
18
16
|
ondisallow = () => null,
|
|
@@ -36,7 +34,7 @@
|
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
async function setSession(): Promise<void> {
|
|
39
|
-
const result = await fetchAsSession(
|
|
37
|
+
const result = await fetchAsSession()
|
|
40
38
|
|
|
41
39
|
if (!result) return
|
|
42
40
|
|
|
@@ -49,7 +47,7 @@
|
|
|
49
47
|
}
|
|
50
48
|
|
|
51
49
|
function takeOverEditing(): void {
|
|
52
|
-
saveCurrentSession(
|
|
50
|
+
saveCurrentSession()
|
|
53
51
|
ontakeover()
|
|
54
52
|
}
|
|
55
53
|
</script>
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
let { navigate = () => null, searchQuery = $bindable(''), filter = $bindable({}), children }: Props = $props()
|
|
23
23
|
|
|
24
|
+
// svelte-ignore non_reactive_update
|
|
24
25
|
let element: HTMLElement | null = null
|
|
25
26
|
let height: string | null = $state(null)
|
|
26
27
|
let clientWidth: number = $state(window.innerWidth)
|
|
@@ -36,7 +36,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
36
36
|
it('Should call api with GET method with given url', async () => {
|
|
37
37
|
vi.mocked(api).mockResolvedValueOnce('Some response')
|
|
38
38
|
|
|
39
|
-
const response = await fetchLinkInjections(
|
|
39
|
+
const response = await fetchLinkInjections({ url: 'https://some-url' })
|
|
40
40
|
|
|
41
41
|
expect(response).toBe('Some response')
|
|
42
42
|
expect(api).toHaveBeenCalledWith(
|
|
@@ -50,7 +50,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
50
50
|
it('Should call api with POST method and full details when fetching with method set to POST', async () => {
|
|
51
51
|
vi.mocked(api).mockResolvedValueOnce('Some response')
|
|
52
52
|
|
|
53
|
-
const response = await fetchLinkInjections(
|
|
53
|
+
const response = await fetchLinkInjections({ url: 'https://some-url', params: { key: 'value' }, method: 'POST' })
|
|
54
54
|
|
|
55
55
|
expect(response).toBe('Some response')
|
|
56
56
|
expect(api).toHaveBeenCalledWith(
|
|
@@ -69,14 +69,14 @@ describe('$lib/api/externalPages', () => {
|
|
|
69
69
|
it('Should call api with full details when fetching with run_ai as true and method is set to POST', async () => {
|
|
70
70
|
vi.mocked(api).mockResolvedValueOnce('Some response')
|
|
71
71
|
|
|
72
|
-
const response = await fetchLinkInjections(
|
|
72
|
+
const response = await fetchLinkInjections({ url: 'https://some-url', params: { run_ai: true }, method: 'POST' })
|
|
73
73
|
|
|
74
74
|
expect(response).toBe('Some response')
|
|
75
75
|
expect(api).toHaveBeenCalledWith(
|
|
76
76
|
expect.stringContaining('api-token'),
|
|
77
77
|
expect.objectContaining({
|
|
78
78
|
body: {
|
|
79
|
-
hash:
|
|
79
|
+
hash: expect.any(String),
|
|
80
80
|
url: 'https://some-url',
|
|
81
81
|
run_ai: true,
|
|
82
82
|
metadata: {
|
|
@@ -84,7 +84,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
84
84
|
content_modified_time: null,
|
|
85
85
|
content_published_time: null,
|
|
86
86
|
},
|
|
87
|
-
page_text:
|
|
87
|
+
page_text: expect.any(String),
|
|
88
88
|
},
|
|
89
89
|
method: 'POST',
|
|
90
90
|
}),
|
|
@@ -95,13 +95,13 @@ describe('$lib/api/externalPages', () => {
|
|
|
95
95
|
// @ts-ignore
|
|
96
96
|
window.PlayPilotLinkInjections = null
|
|
97
97
|
|
|
98
|
-
await expect(async () => await fetchLinkInjections(
|
|
98
|
+
await expect(async () => await fetchLinkInjections()).rejects.toThrowError('No token was provided')
|
|
99
99
|
})
|
|
100
100
|
|
|
101
101
|
it('Should throw when response was incorrect', async () => {
|
|
102
102
|
vi.mocked(api).mockRejectedValueOnce({ ok: false })
|
|
103
103
|
|
|
104
|
-
await expect(async () => await fetchLinkInjections(
|
|
104
|
+
await expect(async () => await fetchLinkInjections()).rejects.toThrowError()
|
|
105
105
|
})
|
|
106
106
|
|
|
107
107
|
it('Should use given api token', async () => {
|
|
@@ -110,7 +110,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
110
110
|
// @ts-ignore
|
|
111
111
|
window.PlayPilotLinkInjections = { token: 'token' }
|
|
112
112
|
|
|
113
|
-
await fetchLinkInjections(
|
|
113
|
+
await fetchLinkInjections()
|
|
114
114
|
|
|
115
115
|
expect(api).toHaveBeenCalledWith(
|
|
116
116
|
expect.stringContaining('api-token=token'),
|
|
@@ -124,7 +124,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
124
124
|
// @ts-ignore
|
|
125
125
|
window.PlayPilotLinkInjections = null
|
|
126
126
|
|
|
127
|
-
await expect(async () => await fetchLinkInjections(
|
|
127
|
+
await expect(async () => await fetchLinkInjections()).rejects.toThrowError()
|
|
128
128
|
expect(api).not.toHaveBeenCalled()
|
|
129
129
|
})
|
|
130
130
|
|
|
@@ -134,7 +134,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
134
134
|
vi.mocked(authorize).mockResolvedValueOnce(true)
|
|
135
135
|
vi.mocked(isEditorialModeEnabled).mockResolvedValueOnce(true)
|
|
136
136
|
|
|
137
|
-
const response = await fetchLinkInjections(
|
|
137
|
+
const response = await fetchLinkInjections()
|
|
138
138
|
|
|
139
139
|
expect(response).toBe('Some response')
|
|
140
140
|
expect(api).toHaveBeenCalledWith(
|
|
@@ -146,7 +146,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
146
146
|
it('Should call api with given language', async () => {
|
|
147
147
|
vi.mocked(api).mockResolvedValueOnce('Some response')
|
|
148
148
|
|
|
149
|
-
await fetchLinkInjections(
|
|
149
|
+
await fetchLinkInjections()
|
|
150
150
|
|
|
151
151
|
expect(api).toHaveBeenCalledWith(
|
|
152
152
|
expect.stringContaining(`&language=${Language.English}`),
|
|
@@ -156,7 +156,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
156
156
|
// @ts-ignore
|
|
157
157
|
window.PlayPilotLinkInjections = { token: 'token', language: Language.Swedish }
|
|
158
158
|
|
|
159
|
-
await fetchLinkInjections(
|
|
159
|
+
await fetchLinkInjections()
|
|
160
160
|
|
|
161
161
|
expect(api).toHaveBeenCalledWith(
|
|
162
162
|
expect.stringContaining(`&language=${Language.Swedish}`),
|
|
@@ -169,7 +169,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
169
169
|
it('Should poll endpoint while results are not yet ready when requireCompletedResults is true', async () => {
|
|
170
170
|
vi.mocked(api).mockResolvedValueOnce({ ai_enabled: true, ai_running: true })
|
|
171
171
|
|
|
172
|
-
pollLinkInjections(
|
|
172
|
+
pollLinkInjections({ requireCompletedResult: true, pollInterval: 500 })
|
|
173
173
|
|
|
174
174
|
expect(api).toHaveBeenCalled()
|
|
175
175
|
|
|
@@ -184,7 +184,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
184
184
|
vi.mocked(api).mockResolvedValue({ ai_enabled: true, ai_running: true })
|
|
185
185
|
|
|
186
186
|
const onpoll = vi.fn()
|
|
187
|
-
pollLinkInjections(
|
|
187
|
+
pollLinkInjections({ requireCompletedResult: true, pollInterval: 500, onpoll })
|
|
188
188
|
|
|
189
189
|
await waitFor(() => {
|
|
190
190
|
expect(onpoll).toHaveBeenCalledTimes(1)
|
|
@@ -201,7 +201,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
201
201
|
const response = { ai_enabled: true, ai_running: false, manual_injections: [{ title: 'value' }] }
|
|
202
202
|
vi.mocked(api).mockResolvedValueOnce(response)
|
|
203
203
|
|
|
204
|
-
const result = await pollLinkInjections(
|
|
204
|
+
const result = await pollLinkInjections({ requireCompletedResult: true, pollInterval: 500 })
|
|
205
205
|
|
|
206
206
|
expect(api).toHaveBeenCalled()
|
|
207
207
|
expect(result).toEqual(response)
|
|
@@ -213,7 +213,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
213
213
|
it('Should stop polling if max limit was exceeded', async () => {
|
|
214
214
|
vi.mocked(api).mockResolvedValueOnce({ ai_enabled: true, ai_running: true })
|
|
215
215
|
|
|
216
|
-
await pollLinkInjections(
|
|
216
|
+
await pollLinkInjections({ requireCompletedResult: true, pollInterval: 200, maxTries: 2 })
|
|
217
217
|
|
|
218
218
|
await new Promise(res => setTimeout(res, 1000)) // Wait for a potential poll
|
|
219
219
|
expect(api).toHaveBeenCalledTimes(2)
|
|
@@ -222,7 +222,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
222
222
|
it('Should continue polling if endpoint throws error', async () => {
|
|
223
223
|
vi.mocked(api).mockRejectedValueOnce({ ok: false })
|
|
224
224
|
|
|
225
|
-
pollLinkInjections(
|
|
225
|
+
pollLinkInjections({ pollInterval: 500 })
|
|
226
226
|
|
|
227
227
|
expect(api).toHaveBeenCalled()
|
|
228
228
|
|
|
@@ -233,16 +233,16 @@ describe('$lib/api/externalPages', () => {
|
|
|
233
233
|
it('Should return empty array if manual_injections are null', async () => {
|
|
234
234
|
vi.mocked(api).mockResolvedValueOnce({ ai_enabled: null, ai_running: null })
|
|
235
235
|
|
|
236
|
-
const result = await pollLinkInjections(
|
|
236
|
+
const result = await pollLinkInjections()
|
|
237
237
|
expect(result).toEqual(expect.objectContaining({ manual_injections: [], ai_injections: [] }))
|
|
238
238
|
})
|
|
239
239
|
|
|
240
240
|
it('Should call api twice if runAiWhenRelevant is true and results expects new run', async () => {
|
|
241
|
-
document.body.innerHTML = '<meta content="2025-04-20T00:00:00Z" property="article:modified_time">'
|
|
241
|
+
document.body.innerHTML = '<main>Some text</main> <meta content="2025-04-20T00:00:00Z" property="article:modified_time">'
|
|
242
242
|
|
|
243
243
|
vi.mocked(api).mockResolvedValueOnce({ ai_enabled: true })
|
|
244
244
|
|
|
245
|
-
await pollLinkInjections(
|
|
245
|
+
await pollLinkInjections({ runAiWhenRelevant: true, maxTries: 1 })
|
|
246
246
|
|
|
247
247
|
expect(api).toHaveBeenCalledTimes(2)
|
|
248
248
|
})
|
|
@@ -250,7 +250,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
250
250
|
it('Should call api twice if initial response returns 404', async () => {
|
|
251
251
|
vi.mocked(api).mockRejectedValueOnce({ status: 404 })
|
|
252
252
|
|
|
253
|
-
await pollLinkInjections(
|
|
253
|
+
await pollLinkInjections({ maxTries: 1 })
|
|
254
254
|
|
|
255
255
|
expect(api).toHaveBeenCalledTimes(2)
|
|
256
256
|
expect(api).toHaveBeenCalledWith(
|
|
@@ -266,7 +266,7 @@ describe('$lib/api/externalPages', () => {
|
|
|
266
266
|
it('Should call api three times if initial response returns 404 and second response returns ai_enabled set to true', async () => {
|
|
267
267
|
vi.mocked(api).mockRejectedValueOnce({ status: 404 }).mockResolvedValueOnce({ ai_enabled: true })
|
|
268
268
|
|
|
269
|
-
await pollLinkInjections(
|
|
269
|
+
await pollLinkInjections({ maxTries: 1 })
|
|
270
270
|
|
|
271
271
|
expect(api).toHaveBeenCalledTimes(3)
|
|
272
272
|
expect(api).toHaveBeenCalledWith(
|
|
@@ -287,6 +287,28 @@ describe('$lib/api/externalPages', () => {
|
|
|
287
287
|
}),
|
|
288
288
|
)
|
|
289
289
|
})
|
|
290
|
+
|
|
291
|
+
it('Should use the given selector when present', async () => {
|
|
292
|
+
vi.mocked(api).mockRejectedValueOnce({ status: 404 }).mockResolvedValueOnce({ ai_enabled: true })
|
|
293
|
+
|
|
294
|
+
document.body.innerHTML = '<div class="some-element"><p>Here</p></div> <p>Not here</p>'
|
|
295
|
+
|
|
296
|
+
// @ts-ignore
|
|
297
|
+
window.PlayPilotLinkInjections = { token: 'token', selector: '.some-element' }
|
|
298
|
+
|
|
299
|
+
await pollLinkInjections({ runAiWhenRelevant: true, maxTries: 1 })
|
|
300
|
+
|
|
301
|
+
await waitFor(() => {
|
|
302
|
+
expect(api).toHaveBeenCalledWith(
|
|
303
|
+
expect.any(String),
|
|
304
|
+
expect.objectContaining({
|
|
305
|
+
body: expect.objectContaining({
|
|
306
|
+
page_text: 'Here',
|
|
307
|
+
}),
|
|
308
|
+
}),
|
|
309
|
+
)
|
|
310
|
+
})
|
|
311
|
+
})
|
|
290
312
|
})
|
|
291
313
|
|
|
292
314
|
describe('runAiBasedOnResponse', () => {
|
package/src/tests/main.test.js
CHANGED
|
@@ -51,7 +51,6 @@ describe('main.ts', () => {
|
|
|
51
51
|
describe('initialize', () => {
|
|
52
52
|
it('Should not call setConsent when only a token is passed', () => {
|
|
53
53
|
window.PlayPilotLinkInjections.initialize({ token: 'a' })
|
|
54
|
-
console.log(window.PlayPilotLinkInjections)
|
|
55
54
|
|
|
56
55
|
expect(setConsent).not.toHaveBeenCalled()
|
|
57
56
|
|
|
@@ -134,8 +134,8 @@ describe('$routes/+page.svelte', () => {
|
|
|
134
134
|
render(page)
|
|
135
135
|
|
|
136
136
|
await waitFor(() => {
|
|
137
|
-
expect(pollLinkInjections).toHaveBeenCalledWith(
|
|
138
|
-
expect(pollLinkInjections).toHaveBeenCalledWith(
|
|
137
|
+
expect(pollLinkInjections).toHaveBeenCalledWith({ maxTries: 1, runAiWhenRelevant: true })
|
|
138
|
+
expect(pollLinkInjections).toHaveBeenCalledWith({ requireCompletedResult: true, onpoll: expect.any(Function) })
|
|
139
139
|
})
|
|
140
140
|
})
|
|
141
141
|
|
|
@@ -158,7 +158,7 @@ describe('$routes/+page.svelte', () => {
|
|
|
158
158
|
})
|
|
159
159
|
|
|
160
160
|
await waitFor(() => {
|
|
161
|
-
expect(pollLinkInjections).toHaveBeenCalledWith(
|
|
161
|
+
expect(pollLinkInjections).toHaveBeenCalledWith({ requireCompletedResult: true, onpoll: expect.any(Function) })
|
|
162
162
|
})
|
|
163
163
|
|
|
164
164
|
expect(pollLinkInjections).toHaveBeenCalledTimes(2)
|
|
@@ -221,7 +221,7 @@ describe('$routes/+page.svelte', () => {
|
|
|
221
221
|
render(page)
|
|
222
222
|
|
|
223
223
|
await waitFor(() => {
|
|
224
|
-
expect(pollLinkInjections).toHaveBeenCalledWith(
|
|
224
|
+
expect(pollLinkInjections).toHaveBeenCalledWith({ maxTries: 1, runAiWhenRelevant: true })
|
|
225
225
|
})
|
|
226
226
|
})
|
|
227
227
|
|