@@ -3,9 +3,14 @@ import { createWorkerBox, WorkerBoxAPI } from '../../lib/workerbox'
33import { resolvers } from './arg-resolvers'
44import { AnalyticsRuntimePublicApi } from '../../types'
55import { replaceBaseUrl } from '../../lib/replace-base-url'
6- import { Signal } from '@segment/analytics-signals-runtime'
6+ import {
7+ Signal ,
8+ WebRuntimeConstants ,
9+ WebSignalsRuntime ,
10+ } from '@segment/analytics-signals-runtime'
711import { getRuntimeCode } from '@segment/analytics-signals-runtime'
812import { polyfills } from './polyfills'
13+ import { loadScript } from '../../lib/load-script'
914
1015export type MethodName =
1116 | 'page'
@@ -151,14 +156,30 @@ class JavascriptSandbox implements CodeSandbox {
151156 }
152157}
153158
159+ export const normalizeEdgeFunctionURL = (
160+ functionHost : string | undefined ,
161+ edgeFnDownloadURL : string | undefined
162+ ) => {
163+ if ( functionHost && edgeFnDownloadURL ) {
164+ replaceBaseUrl ( edgeFnDownloadURL , `https://${ functionHost } ` )
165+ } else {
166+ return edgeFnDownloadURL
167+ }
168+ }
169+
154170export type SandboxSettingsConfig = {
155171 functionHost : string | undefined
156172 processSignal : string | undefined
157173 edgeFnDownloadURL : string | undefined
158174 edgeFnFetchClient ?: typeof fetch
159175}
160176
161- export class SandboxSettings {
177+ export type WorkerboxSettingsConfig = Pick <
178+ SandboxSettingsConfig ,
179+ 'processSignal' | 'edgeFnFetchClient' | 'edgeFnDownloadURL'
180+ >
181+
182+ export class WorkerSandboxSettings {
162183 /**
163184 * Should look like:
164185 * ```js
@@ -168,48 +189,42 @@ export class SandboxSettings {
168189 * ```
169190 */
170191 processSignal : Promise < string >
171- constructor ( settings : SandboxSettingsConfig ) {
172- const edgeFnDownloadURLNormalized =
173- settings . functionHost && settings . edgeFnDownloadURL
174- ? replaceBaseUrl (
175- settings . edgeFnDownloadURL ,
176- `https://${ settings . functionHost } `
177- )
178- : settings . edgeFnDownloadURL
179-
180- if ( ! edgeFnDownloadURLNormalized && ! settings . processSignal ) {
181- // user may be onboarding and not have written a signal -- so do a noop so we can collect signals
182- this . processSignal = Promise . resolve (
183- `globalThis.processSignal = function processSignal() {}`
184- )
185- console . warn (
186- `No processSignal function found. Have you written a processSignal function on app.segment.com?`
187- )
188- return
189- }
190-
192+ constructor ( settings : WorkerboxSettingsConfig ) {
191193 const fetch = settings . edgeFnFetchClient ?? globalThis . fetch
192194
193195 const processSignalNormalized = settings . processSignal
194196 ? Promise . resolve ( settings . processSignal ) . then (
195197 ( str ) => `globalThis.processSignal = ${ str } `
196198 )
197- : fetch ( edgeFnDownloadURLNormalized ! ) . then ( ( res ) => res . text ( ) )
199+ : fetch ( settings . edgeFnDownloadURL ! ) . then ( ( res ) => res . text ( ) )
198200
199201 this . processSignal = processSignalNormalized
200202 }
201203}
202204
203- export class Sandbox {
204- settings : SandboxSettings
205+ export interface SignalSandbox {
206+ isLoaded ( ) : Promise < void >
207+ execute (
208+ signal : Signal ,
209+ signals : Signal [ ]
210+ ) : Promise < AnalyticsMethodCalls | undefined >
211+ destroy ( ) : void | Promise < void >
212+ }
213+
214+ export class WorkerSandbox implements SignalSandbox {
215+ settings : WorkerSandboxSettings
205216 jsSandbox : CodeSandbox
206217
207- constructor ( settings : SandboxSettings ) {
218+ constructor ( settings : WorkerSandboxSettings ) {
208219 this . settings = settings
209220 this . jsSandbox = new JavascriptSandbox ( )
210221 }
211222
212- async process (
223+ isLoaded ( ) : Promise < any > {
224+ return Promise . resolve ( ) // TODO
225+ }
226+
227+ async execute (
213228 signal : Signal ,
214229 signals : Signal [ ]
215230 ) : Promise < AnalyticsMethodCalls > {
@@ -232,4 +247,64 @@ export class Sandbox {
232247 const calls = analytics . getCalls ( )
233248 return calls
234249 }
250+ destroy ( ) : void {
251+ void this . jsSandbox . destroy ( )
252+ }
253+ }
254+
255+ // This is not ideal -- but processSignal currently depends on
256+
257+ const processWithGlobals = (
258+ signalBuffer : Signal [ ]
259+ ) : AnalyticsMethodCalls | undefined => {
260+ const g = globalThis as any
261+ // Load all constants into the global scope
262+ Object . entries ( WebRuntimeConstants ) . forEach ( ( [ key , value ] ) => {
263+ g [ key ] = value
264+ } )
265+
266+ // processSignal expects a global called `signals` -- of course, there can local variable naming conflict on the client, which is why globals were a bad idea.
267+ g [ 'signals' ] = new WebSignalsRuntime ( signalBuffer )
268+
269+ // expect analytics to be instantiated -- this will conflict in the global scope TODO
270+ g [ 'analytics' ] = new AnalyticsRuntime ( )
271+
272+ // another possible namespace conflict?
273+ // @ts -ignore
274+ if ( typeof processSignal != 'undefined' ) {
275+ g [ 'processSignal' ] ( signalBuffer [ 0 ] )
276+ } else {
277+ console . warn ( 'no processSignal function is defined in the global scope' )
278+ }
279+
280+ return g [ 'analytics' ] . getCalls ( )
281+ }
282+
283+ interface GlobalScopeSandboxSettings {
284+ edgeFnDownloadURL : string
285+ }
286+ export class GlobalScopeSandbox implements SignalSandbox {
287+ script : Promise < HTMLScriptElement >
288+ async isLoaded ( ) : Promise < void > {
289+ await this . script
290+ }
291+ constructor ( settings : GlobalScopeSandboxSettings ) {
292+ this . script = loadScript ( settings . edgeFnDownloadURL )
293+ }
294+
295+ // eslint-disable-next-line @typescript-eslint/require-await
296+ async execute ( _signal : Signal , signals : Signal [ ] ) {
297+ return processWithGlobals ( signals )
298+ }
299+ destroy ( ) : void { }
300+ }
301+
302+ export class NoopSandbox implements SignalSandbox {
303+ async isLoaded ( ) : Promise < void > { }
304+ execute ( _signal : Signal , _signals : Signal [ ] ) {
305+ return Promise . resolve ( undefined )
306+ }
307+ destroy ( ) : void | Promise < void > {
308+ return
309+ }
235310}
0 commit comments