1
1
import { logger } from '../../lib/logger'
2
- import { createWorkerBox , WorkerBoxAPI } from '../../lib/workerbox'
3
2
import { resolvers } from './arg-resolvers'
4
3
import { AnalyticsRuntimePublicApi , ProcessSignal } from '../../types'
5
4
import { replaceBaseUrl } from '../../lib/replace-base-url'
@@ -129,33 +128,6 @@ class AnalyticsRuntime implements AnalyticsRuntimePublicApi {
129
128
}
130
129
}
131
130
132
- interface CodeSandbox {
133
- run : ( fn : string , scope : Record < string , any > ) => Promise < any >
134
- destroy : ( ) => Promise < void >
135
- }
136
-
137
- class JavascriptSandbox implements CodeSandbox {
138
- private workerbox : Promise < WorkerBoxAPI >
139
- constructor ( ) {
140
- this . workerbox = createWorkerBox ( )
141
- }
142
- async run ( fn : string , scope : Record < string , any > ) {
143
- try {
144
- const wb = await this . workerbox
145
- await wb . run ( fn , scope )
146
- } catch ( err ) {
147
- console . error ( 'processSignal() error in sandbox' , err , {
148
- fn,
149
- } )
150
- }
151
- }
152
-
153
- async destroy ( ) : Promise < void > {
154
- const wb = await this . workerbox
155
- await wb . destroy ( )
156
- }
157
- }
158
-
159
131
export const normalizeEdgeFunctionURL = (
160
132
functionHost : string | undefined ,
161
133
edgeFnDownloadURL : string | undefined
@@ -185,39 +157,6 @@ const PROCESS_SIGNAL_UNDEFINED =
185
157
186
158
const consoleWarnProcessSignal = ( ) => console . warn ( PROCESS_SIGNAL_UNDEFINED )
187
159
188
- export class IframeWorkerSandboxSettings {
189
- /**
190
- * Should look like:
191
- * ```js
192
- * function processSignal(signal) {
193
- * ...
194
- * }
195
- * ```
196
- */
197
- processSignal : Promise < string >
198
- constructor ( settings : IframeSandboxSettingsConfig ) {
199
- const fetch = settings . edgeFnFetchClient ?? globalThis . fetch
200
-
201
- let processSignalNormalized = Promise . resolve (
202
- `globalThis.processSignal = function() {}`
203
- )
204
-
205
- if ( settings . processSignal ) {
206
- processSignalNormalized = Promise . resolve ( settings . processSignal ) . then (
207
- ( str ) => `globalThis.processSignal = ${ str } `
208
- )
209
- } else if ( settings . edgeFnDownloadURL ) {
210
- processSignalNormalized = fetch ( settings . edgeFnDownloadURL ! ) . then ( ( res ) =>
211
- res . text ( )
212
- )
213
- } else {
214
- consoleWarnProcessSignal ( )
215
- }
216
-
217
- this . processSignal = processSignalNormalized
218
- }
219
- }
220
-
221
160
export interface SignalSandbox {
222
161
execute (
223
162
signal : Signal ,
@@ -226,43 +165,6 @@ export interface SignalSandbox {
226
165
destroy ( ) : void | Promise < void >
227
166
}
228
167
229
- export class WorkerSandbox implements SignalSandbox {
230
- settings : IframeWorkerSandboxSettings
231
- jsSandbox : CodeSandbox
232
-
233
- constructor ( settings : IframeWorkerSandboxSettings ) {
234
- this . settings = settings
235
- this . jsSandbox = new JavascriptSandbox ( )
236
- }
237
-
238
- async execute (
239
- signal : Signal ,
240
- signals : Signal [ ]
241
- ) : Promise < AnalyticsMethodCalls > {
242
- const analytics = new AnalyticsRuntime ( )
243
- const scope = {
244
- analytics,
245
- }
246
- logger . debug ( 'processing signal' , { signal, scope, signals } )
247
- const code = [
248
- polyfills ,
249
- await this . settings . processSignal ,
250
- getRuntimeCode ( ) ,
251
- `signals.signalBuffer = ${ JSON . stringify ( signals ) } ;` ,
252
- 'try { processSignal(' +
253
- JSON . stringify ( signal ) +
254
- ', { analytics, signals, SignalType, EventType, NavigationAction }); } catch(err) { console.error("Process signal failed.", err); }' ,
255
- ] . join ( '\n' )
256
- await this . jsSandbox . run ( code , scope )
257
-
258
- const calls = analytics . getCalls ( )
259
- return calls
260
- }
261
- destroy ( ) : void {
262
- void this . jsSandbox . destroy ( )
263
- }
264
- }
265
-
266
168
// ProcessSignal unfortunately uses globals. This should change.
267
169
// For now, we are setting up the globals between each invocation
268
170
const processWithGlobalScopeExecutionEnv = (
@@ -373,13 +275,14 @@ const noramizeMethodCallsWithArgResolver = (
373
275
} )
374
276
return normalizedRuntime . getCalls ( )
375
277
}
278
+
376
279
export class IframeSandbox implements SignalSandbox {
377
280
private iframe : HTMLIFrameElement
378
281
private iframeReady : Promise < void >
379
282
private _resolveReady ! : ( ) => void
380
283
edgeFnUrl : string
381
284
382
- constructor ( edgeFnUrl : string ) {
285
+ constructor ( edgeFnUrl : string , processSignalFn ?: string ) {
383
286
this . edgeFnUrl = edgeFnUrl
384
287
this . iframe = document . createElement ( 'iframe' )
385
288
this . iframe . id = 'segment-signals-sandbox'
@@ -405,16 +308,32 @@ export class IframeSandbox implements SignalSandbox {
405
308
const doc = this . iframe . contentDocument !
406
309
doc . open ( )
407
310
doc . write (
408
- `<!DOCTYPE html><html><head><script id="edge-fn" src=${ this . edgeFnUrl } ></script></head><body></body></html>`
311
+ [
312
+ `<!DOCTYPE html>` ,
313
+ `<html>` ,
314
+ `<head>` ,
315
+ processSignalFn
316
+ ? ''
317
+ : `<script id="edge-fn" src=${ this . edgeFnUrl } ></script>` ,
318
+ `</head>` ,
319
+ `<body></body>
320
+ </html>` ,
321
+ ] . join ( ',' )
409
322
)
410
323
doc . close ( )
411
324
412
325
// External signal processor script
413
326
// Inject runtime via Blob (CSP-safe)
414
327
const runtimeJs = `
328
+ ${ processSignalFn ? `window.processSignal = ${ processSignalFn } ` : '' }
329
+
415
330
const signalsScript = document.getElementById('edge-fn')
416
- signalsScript.onload = () => {
417
- window.parent.postMessage('iframe_ready', '*')
331
+ if (typeof processSignal === 'undefined') {
332
+ signalsScript.onload = () => {
333
+ window.parent.postMessage('iframe_ready', '*')
334
+ }
335
+ } else {
336
+ window.parent.postMessage('iframe_ready', '*')
418
337
}
419
338
420
339
class AnalyticsRuntimeProxy {
0 commit comments