@monetizationos/proxy 1.0.3 → 1.1.0
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/README.md +1 -0
- package/dist/MOSProxyBuilder.d.ts +1 -0
- package/dist/MOSProxyBuilder.js +1 -0
- package/dist/MOSProxyBuilder.js.map +1 -1
- package/dist/apiRequestHeaders.d.ts +1 -1
- package/dist/apiRequestHeaders.js +1 -1
- package/dist/apiRequestHeaders.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/stages/fetchSurfaceDecisions.js +10 -3
- package/dist/stages/fetchSurfaceDecisions.js.map +1 -1
- package/dist/stages/surfaceDecisions.js +18 -9
- package/dist/stages/surfaceDecisions.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,6 +29,7 @@ const proxy = new MOSProxyBuilder()
|
|
|
29
29
|
mosEndpointsPrefix: "/mos-endpoints/",
|
|
30
30
|
anonymousSessionCookieName: "anon-session-id",
|
|
31
31
|
authenticatedUserJwtCookieName: "__session",
|
|
32
|
+
createAnonymousIdentifierFallback: true,
|
|
32
33
|
injectScriptUrl: "https://assets.monetizationos.com/web-components-latest.js",
|
|
33
34
|
originRequestHeaders: { "X-Api-Key": process.env.ORIGIN_API_KEY! },
|
|
34
35
|
})
|
|
@@ -28,6 +28,7 @@ import type { MOSConfigInput } from './types';
|
|
|
28
28
|
* injectScriptUrl: 'https://assets.monetizationos.com/web-components-latest.js',
|
|
29
29
|
* surfaceDecisionsIgnorePaths: '',
|
|
30
30
|
* originRequestHeaders: { 'X-Api-Key': process.env.ORIGIN_API_KEY! },
|
|
31
|
+
* createAnonymousIdentifierFallback: true,
|
|
31
32
|
* })
|
|
32
33
|
* .withHtmlRewriter(myHtmlRewriterAdapter)
|
|
33
34
|
* .build()
|
package/dist/MOSProxyBuilder.js
CHANGED
|
@@ -23,6 +23,7 @@ import { MOSProxy } from './MOSProxy';
|
|
|
23
23
|
* injectScriptUrl: 'https://assets.monetizationos.com/web-components-latest.js',
|
|
24
24
|
* surfaceDecisionsIgnorePaths: '',
|
|
25
25
|
* originRequestHeaders: { 'X-Api-Key': process.env.ORIGIN_API_KEY! },
|
|
26
|
+
* createAnonymousIdentifierFallback: true,
|
|
26
27
|
* })
|
|
27
28
|
* .withHtmlRewriter(myHtmlRewriterAdapter)
|
|
28
29
|
* .build()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MOSProxyBuilder.js","sourceRoot":"","sources":["../src/MOSProxyBuilder.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAA+D,MAAM,YAAY,CAAA;AAGlG
|
|
1
|
+
{"version":3,"file":"MOSProxyBuilder.js","sourceRoot":"","sources":["../src/MOSProxyBuilder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ClientMetadataProvider } from './adapters/ClientMetadataProvider'\nimport type { Fetcher } from './adapters/Fetcher'\nimport type { HtmlRewriterAdapter } from './adapters/HtmlRewriterAdapter'\nimport type { MOSProxyLogger } from './logger'\nimport { MOSProxy, type MOSProxyHtmlPipelineErrorHandler, type MOSProxyOptions } from './MOSProxy'\nimport type { MOSConfigInput } from './types'\n\n/**\n * Fluent builder for `MOSProxy`. Provide configuration and platform adapters, then `build()`.\n *\n * Defaults:\n * - custom endpoint routing: enabled\n * - link rewriting: enabled\n * - surface decisions: enabled\n * - HTML transformation: enabled (auto-skipped per request for non-HTML responses)\n * - origin/API fetcher: `globalThis.fetch` (override on runtimes that need a backend binding, e.g. Fastly)\n *\n * @example\n * ```ts\n * const proxy = new MOSProxyBuilder()\n * .withConfig({\n * originUrl: 'https://news.example.com',\n * surfaceSlug: 'web',\n * mosHost: 'https://api.monetizationos.com',\n * mosSecretKey: process.env.MONETIZATION_OS_SECRET_KEY!,\n * mosEndpointsPrefix: '/mos-endpoints/',\n * anonymousSessionCookieName: 'anon-session-id',\n * authenticatedUserJwtCookieName: '__session',\n * injectScriptUrl: 'https://assets.monetizationos.com/web-components-latest.js',\n * surfaceDecisionsIgnorePaths: '',\n * originRequestHeaders: { 'X-Api-Key': process.env.ORIGIN_API_KEY! },\n * createAnonymousIdentifierFallback: true,\n * })\n * .withHtmlRewriter(myHtmlRewriterAdapter)\n * .build()\n *\n * export default { fetch: (request: Request) => proxy.handle(request) }\n * ```\n */\nexport class MOSProxyBuilder {\n private _config: MOSConfigInput | null = null\n private _originFetcher: Fetcher = globalThis.fetch\n private _apiFetcher: Fetcher = globalThis.fetch\n private _htmlRewriter: HtmlRewriterAdapter | null = null\n private _clientMetadataProvider: ClientMetadataProvider | null = null\n private _logger: MOSProxyLogger | null = null\n private _onHtmlPipelineError: MOSProxyHtmlPipelineErrorHandler | null = null\n private _customEndpoints = true\n private _linkRewriting = true\n private _surfaceDecisions = true\n private _htmlTransformation = true\n\n withConfig(config: MOSConfigInput): this {\n this._config = config\n return this\n }\n\n withOriginFetcher(fetcher: Fetcher): this {\n this._originFetcher = fetcher\n return this\n }\n\n withApiFetcher(fetcher: Fetcher): this {\n this._apiFetcher = fetcher\n return this\n }\n\n withHtmlRewriter(rewriter: HtmlRewriterAdapter): this {\n this._htmlRewriter = rewriter\n return this\n }\n\n withClientMetadata(provider: ClientMetadataProvider): this {\n this._clientMetadataProvider = provider\n return this\n }\n\n withLogger(logger: MOSProxyLogger): this {\n this._logger = logger\n return this\n }\n\n /**\n * Register a callback to handle HTML pipeline errors. The proxy fails open by default and\n * returns the last safe (unconsumed) response — provide this if you want to shape that\n * response yourself (e.g. render a custom error page, return a 503, or re-throw so your\n * platform's error middleware handles it). If the callback throws or returns a non-Response\n * value, the proxy logs a warning and falls back to the last safe response.\n */\n withHtmlPipelineErrorHandler(handler: MOSProxyHtmlPipelineErrorHandler): this {\n this._onHtmlPipelineError = handler\n return this\n }\n\n withoutCustomEndpoints(): this {\n this._customEndpoints = false\n return this\n }\n\n withoutLinkRewriting(): this {\n this._linkRewriting = false\n return this\n }\n\n withoutSurfaceDecisions(): this {\n this._surfaceDecisions = false\n return this\n }\n\n /**\n * Disable the HTML transformation pipeline entirely (stages 3–6).\n *\n * Use for API-only proxies: neither an HTML rewriter adapter nor an API fetcher is required\n * if custom endpoints and surface decisions are both disabled alongside this.\n */\n withoutHtmlTransformation(): this {\n this._htmlTransformation = false\n return this\n }\n\n build(): MOSProxy {\n if (!this._config) {\n throw new Error('MOSProxyBuilder: withConfig(...) is required')\n }\n\n const needsHtmlRewriter = this._htmlTransformation && this._surfaceDecisions\n if (needsHtmlRewriter && !this._htmlRewriter) {\n throw new Error(\n 'MOSProxyBuilder: withHtmlRewriter(...) is required when surface decisions is enabled; call withoutSurfaceDecisions() or withoutHtmlTransformation() if you do not need it',\n )\n }\n\n const opts: MOSProxyOptions = {\n config: this._config,\n originFetcher: this._originFetcher,\n apiFetcher: this._apiFetcher,\n htmlRewriter: this._htmlRewriter,\n clientMetadataProvider: this._clientMetadataProvider,\n logger: this._logger ?? undefined,\n onHtmlPipelineError: this._onHtmlPipelineError ?? undefined,\n customEndpointsEnabled: this._customEndpoints,\n linkRewritingEnabled: this._linkRewriting,\n surfaceDecisionsEnabled: this._surfaceDecisions,\n htmlTransformationEnabled: this._htmlTransformation,\n }\n return new MOSProxy(opts)\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const MOS_PROXY_VERSION_HEADER = "X-MOS-Proxy-Version";
|
|
2
2
|
export declare const MOS_PROXY_CLIENT_HEADER = "X-MOS-Proxy-Client";
|
|
3
|
-
export declare const MOS_PROXY_PACKAGE_VERSION = "1.0
|
|
3
|
+
export declare const MOS_PROXY_PACKAGE_VERSION = "1.1.0";
|
|
4
4
|
export declare const setMosProxyHeaders: (headers: Headers) => void;
|
|
5
5
|
export declare const withMosProxyHeaders: (headers?: HeadersInit) => Headers;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { formatClientRuntimeHeader } from './clientRuntime';
|
|
2
2
|
export const MOS_PROXY_VERSION_HEADER = 'X-MOS-Proxy-Version';
|
|
3
3
|
export const MOS_PROXY_CLIENT_HEADER = 'X-MOS-Proxy-Client';
|
|
4
|
-
export const MOS_PROXY_PACKAGE_VERSION = '1.0
|
|
4
|
+
export const MOS_PROXY_PACKAGE_VERSION = '1.1.0';
|
|
5
5
|
export const setMosProxyHeaders = (headers) => {
|
|
6
6
|
headers.set(MOS_PROXY_VERSION_HEADER, MOS_PROXY_PACKAGE_VERSION);
|
|
7
7
|
headers.set(MOS_PROXY_CLIENT_HEADER, formatClientRuntimeHeader());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apiRequestHeaders.js","sourceRoot":"","sources":["../src/apiRequestHeaders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAA;AAE3D,MAAM,CAAC,MAAM,wBAAwB,GAAG,qBAAqB,CAAA;AAC7D,MAAM,CAAC,MAAM,uBAAuB,GAAG,oBAAoB,CAAA;AAC3D,MAAM,CAAC,MAAM,yBAAyB,GAAG,OAAO,CAAA;AAEhD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,OAAgB,EAAQ,EAAE;IACzD,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,yBAAyB,CAAC,CAAA;IAChE,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,yBAAyB,EAAE,CAAC,CAAA;AACrE,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,OAAqB,EAAW,EAAE;IAClE,MAAM,IAAI,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;IACjC,kBAAkB,CAAC,IAAI,CAAC,CAAA;IACxB,OAAO,IAAI,CAAA;AACf,CAAC,CAAA","sourcesContent":["import { formatClientRuntimeHeader } from './clientRuntime'\n\nexport const MOS_PROXY_VERSION_HEADER = 'X-MOS-Proxy-Version'\nexport const MOS_PROXY_CLIENT_HEADER = 'X-MOS-Proxy-Client'\nexport const MOS_PROXY_PACKAGE_VERSION = '1.0
|
|
1
|
+
{"version":3,"file":"apiRequestHeaders.js","sourceRoot":"","sources":["../src/apiRequestHeaders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAA;AAE3D,MAAM,CAAC,MAAM,wBAAwB,GAAG,qBAAqB,CAAA;AAC7D,MAAM,CAAC,MAAM,uBAAuB,GAAG,oBAAoB,CAAA;AAC3D,MAAM,CAAC,MAAM,yBAAyB,GAAG,OAAO,CAAA;AAEhD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,OAAgB,EAAQ,EAAE;IACzD,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,yBAAyB,CAAC,CAAA;IAChE,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,yBAAyB,EAAE,CAAC,CAAA;AACrE,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,OAAqB,EAAW,EAAE;IAClE,MAAM,IAAI,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;IACjC,kBAAkB,CAAC,IAAI,CAAC,CAAA;IACxB,OAAO,IAAI,CAAA;AACf,CAAC,CAAA","sourcesContent":["import { formatClientRuntimeHeader } from './clientRuntime'\n\nexport const MOS_PROXY_VERSION_HEADER = 'X-MOS-Proxy-Version'\nexport const MOS_PROXY_CLIENT_HEADER = 'X-MOS-Proxy-Client'\nexport const MOS_PROXY_PACKAGE_VERSION = '1.1.0'\n\nexport const setMosProxyHeaders = (headers: Headers): void => {\n headers.set(MOS_PROXY_VERSION_HEADER, MOS_PROXY_PACKAGE_VERSION)\n headers.set(MOS_PROXY_CLIENT_HEADER, formatClientRuntimeHeader())\n}\n\nexport const withMosProxyHeaders = (headers?: HeadersInit): Headers => {\n const next = new Headers(headers)\n setMosProxyHeaders(next)\n return next\n}\n"]}
|
package/dist/config.d.ts
CHANGED
|
@@ -12,5 +12,6 @@ export interface MOSConfig {
|
|
|
12
12
|
injectScriptUrl: string | undefined;
|
|
13
13
|
surfaceDecisionsIgnorePathPatterns: RegExp[];
|
|
14
14
|
originRequestHeaders: Record<string, string>;
|
|
15
|
+
createAnonymousIdentifierFallback: boolean;
|
|
15
16
|
}
|
|
16
17
|
export declare function normalizeMOSConfig(config: MOSConfigInput, logger?: MOSProxyLogger): MOSConfig;
|
package/dist/config.js
CHANGED
|
@@ -34,6 +34,7 @@ export function normalizeMOSConfig(config, logger = consoleLogger) {
|
|
|
34
34
|
injectScriptUrl: config.injectScriptUrl,
|
|
35
35
|
surfaceDecisionsIgnorePathPatterns: ignorePathPatterns,
|
|
36
36
|
originRequestHeaders: { ...(config.originRequestHeaders ?? {}) },
|
|
37
|
+
createAnonymousIdentifierFallback: config.createAnonymousIdentifierFallback !== false,
|
|
37
38
|
};
|
|
38
39
|
}
|
|
39
40
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAuB,MAAM,UAAU,CAAA;AAG7D,MAAM,wBAAwB,GAAG,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAuB,MAAM,UAAU,CAAA;AAG7D,MAAM,wBAAwB,GAAG,iBAAiB,CAAA;AAiBlD,MAAM,UAAU,kBAAkB,CAAC,MAAsB,EAAE,SAAyB,aAAa;IAC7F,MAAM,kBAAkB,GAAa,EAAE,CAAA;IACvC,IAAI,MAAM,CAAC,2BAA2B,EAAE,CAAC;QACrC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,2BAA2B,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9D,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;YAC1B,IAAI,CAAC,OAAO;gBAAE,SAAQ;YACtB,IAAI,CAAC;gBACD,kBAAkB,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAA;YAChD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,MAAM,CAAC,GAAG,CAAC;oBACP,KAAK,EAAE,MAAM;oBACb,IAAI,EAAE,6BAA6B;oBACnC,OAAO,EAAE,sDAAsD,OAAO,EAAE;oBACxE,OAAO,EAAE,EAAE,OAAO,EAAE;oBACpB,KAAK;iBACR,CAAC,CAAA;YACN,CAAC;QACL,CAAC;IACL,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAErD,OAAO;QACH,SAAS,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;QACpC,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,OAAO,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;QAChC,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,cAAc,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,cAAc,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE;QACvE,kBAAkB,EAAE,MAAM,CAAC,kBAAkB,IAAI,wBAAwB;QACzE,0BAA0B,EAAE,MAAM,CAAC,0BAA0B;QAC7D,8BAA8B,EAAE,MAAM,CAAC,8BAA8B;QACrE,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,kCAAkC,EAAE,kBAAkB;QACtD,oBAAoB,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,oBAAoB,IAAI,EAAE,CAAC,EAAE;QAChE,iCAAiC,EAAE,MAAM,CAAC,iCAAiC,KAAK,KAAK;KACxF,CAAA;AACL,CAAC","sourcesContent":["import { consoleLogger, type MOSProxyLogger } from './logger'\nimport type { MOSConfigInput } from './types'\n\nconst DEFAULT_ENDPOINTS_PREFIX = '/mos-endpoints/'\n\nexport interface MOSConfig {\n originUrl: URL\n surfaceSlug: string\n mosHost: URL\n mosSecretKey: string\n mosEnvironment: string\n mosEndpointsPrefix: string\n anonymousSessionCookieName: string\n authenticatedUserJwtCookieName: string\n injectScriptUrl: string | undefined\n surfaceDecisionsIgnorePathPatterns: RegExp[]\n originRequestHeaders: Record<string, string>\n createAnonymousIdentifierFallback: boolean\n}\n\nexport function normalizeMOSConfig(config: MOSConfigInput, logger: MOSProxyLogger = consoleLogger): MOSConfig {\n const ignorePathPatterns: RegExp[] = []\n if (config.surfaceDecisionsIgnorePaths) {\n for (const raw of config.surfaceDecisionsIgnorePaths.split(',')) {\n const pattern = raw.trim()\n if (!pattern) continue\n try {\n ignorePathPatterns.push(new RegExp(pattern))\n } catch (error) {\n logger.log({\n level: 'warn',\n code: 'invalid-ignore-path-pattern',\n message: `Invalid surfaceDecisionsIgnorePaths regex pattern: ${pattern}`,\n context: { pattern },\n error,\n })\n }\n }\n }\n\n const secretKeyParts = config.mosSecretKey.split('_')\n\n return {\n originUrl: new URL(config.originUrl),\n surfaceSlug: config.surfaceSlug,\n mosHost: new URL(config.mosHost),\n mosSecretKey: config.mosSecretKey,\n mosEnvironment: `${secretKeyParts[1] ?? ''}_${secretKeyParts[2] ?? ''}`,\n mosEndpointsPrefix: config.mosEndpointsPrefix || DEFAULT_ENDPOINTS_PREFIX,\n anonymousSessionCookieName: config.anonymousSessionCookieName,\n authenticatedUserJwtCookieName: config.authenticatedUserJwtCookieName,\n injectScriptUrl: config.injectScriptUrl,\n surfaceDecisionsIgnorePathPatterns: ignorePathPatterns,\n originRequestHeaders: { ...(config.originRequestHeaders ?? {}) },\n createAnonymousIdentifierFallback: config.createAnonymousIdentifierFallback !== false,\n }\n}\n"]}
|
|
@@ -4,7 +4,11 @@ export default async function fetchSurfaceDecisions(ctx, { anonymousIdentifier,
|
|
|
4
4
|
const body = JSON.stringify({
|
|
5
5
|
...clientMetadata,
|
|
6
6
|
surfaceSlug: config.surfaceSlug,
|
|
7
|
-
identity: buildIdentity({
|
|
7
|
+
identity: buildIdentity({
|
|
8
|
+
anonymousIdentifier,
|
|
9
|
+
userJwt,
|
|
10
|
+
createAnonymousIdentifierFallback: config.createAnonymousIdentifierFallback,
|
|
11
|
+
}),
|
|
8
12
|
resource: {
|
|
9
13
|
id: path,
|
|
10
14
|
meta: pageMetadata,
|
|
@@ -67,11 +71,14 @@ export default async function fetchSurfaceDecisions(ctx, { anonymousIdentifier,
|
|
|
67
71
|
return { ok: true, data };
|
|
68
72
|
}
|
|
69
73
|
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
70
|
-
const buildIdentity = ({ anonymousIdentifier, userJwt }) => {
|
|
74
|
+
const buildIdentity = ({ anonymousIdentifier, userJwt, createAnonymousIdentifierFallback, }) => {
|
|
71
75
|
if (!anonymousIdentifier && !userJwt) {
|
|
72
76
|
return { createAnonymousIdentifier: true };
|
|
73
77
|
}
|
|
74
|
-
|
|
78
|
+
if (userJwt) {
|
|
79
|
+
return createAnonymousIdentifierFallback ? { userJwt, createAnonymousIdentifierFallback: true } : { userJwt };
|
|
80
|
+
}
|
|
81
|
+
return { anonymousIdentifier };
|
|
75
82
|
};
|
|
76
83
|
const isSurfaceDecisionError = (value) => isRecord(value) && value.status === 'error' && typeof value.message === 'string' && typeof value.statusCode === 'number';
|
|
77
84
|
const isSurfaceDecisionResponse = (value) => isRecord(value) &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchSurfaceDecisions.js","sourceRoot":"","sources":["../../src/stages/fetchSurfaceDecisions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AA8B1D,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,qBAAqB,CAC/C,GAAoB,EACpB,EAAE,mBAAmB,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,cAAc,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAA6B,EAC7H,UAAmB;IAEnB,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAA;IACtB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;QACxB,GAAG,cAAc;QACjB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,QAAQ,EAAE,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"fetchSurfaceDecisions.js","sourceRoot":"","sources":["../../src/stages/fetchSurfaceDecisions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Fetcher } from '../adapters/Fetcher'\nimport { withMosProxyHeaders } from '../apiRequestHeaders'\nimport type { PipelineContext } from '../context'\nimport type { PageMetadata, SurfaceDecisionError, SurfaceDecisionResponse } from '../types'\n\nexport type FetchSurfaceDecisionsArgs = {\n anonymousIdentifier?: string | undefined\n userJwt?: string | undefined\n path: string\n url: string\n clientMetadata: Record<string, unknown>\n pageMetadata?: PageMetadata\n userAgent?: string | undefined\n originStatus: number\n}\n\nexport type FetchSurfaceDecisionsFailureReason = 'request-failed' | 'invalid-json' | 'api-error' | 'http-error' | 'invalid-response'\n\nexport type FetchSurfaceDecisionsResult =\n | {\n ok: true\n data: SurfaceDecisionResponse\n }\n | {\n ok: false\n reason: FetchSurfaceDecisionsFailureReason\n error: unknown\n status?: number\n statusCode?: number\n }\n\nexport default async function fetchSurfaceDecisions(\n ctx: PipelineContext,\n { anonymousIdentifier, userJwt, path, url, clientMetadata, pageMetadata, userAgent, originStatus }: FetchSurfaceDecisionsArgs,\n apiFetcher: Fetcher,\n): Promise<FetchSurfaceDecisionsResult> {\n const { config } = ctx\n const body = JSON.stringify({\n ...clientMetadata,\n surfaceSlug: config.surfaceSlug,\n identity: buildIdentity({\n anonymousIdentifier,\n userJwt,\n createAnonymousIdentifierFallback: config.createAnonymousIdentifierFallback,\n }),\n resource: {\n id: path,\n meta: pageMetadata,\n },\n http: {\n url,\n userAgent,\n proxyOrigin: {\n status: originStatus,\n },\n },\n })\n\n const request = new Request(new URL('/api/v1/surface-decisions', config.mosHost), {\n method: 'POST',\n body,\n headers: withMosProxyHeaders({\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.mosSecretKey}`,\n }),\n })\n\n let response: Response\n try {\n response = await apiFetcher(request)\n } catch (error) {\n return { ok: false, reason: 'request-failed', error }\n }\n\n let data: unknown\n try {\n data = await response.json()\n } catch (error) {\n return { ok: false, reason: 'invalid-json', error, status: response.status }\n }\n\n if (isSurfaceDecisionError(data)) {\n return {\n ok: false,\n reason: 'api-error',\n error: new Error(data.message),\n status: response.status,\n statusCode: data.statusCode,\n }\n }\n\n if (!response.ok) {\n return {\n ok: false,\n reason: 'http-error',\n error: new Error(`Surface decisions API returned HTTP ${response.status}`),\n status: response.status,\n }\n }\n\n if (!isSurfaceDecisionResponse(data)) {\n return {\n ok: false,\n reason: 'invalid-response',\n error: new Error('Surface decisions API returned an invalid response shape'),\n status: response.status,\n }\n }\n\n return { ok: true, data }\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null\n\nconst buildIdentity = ({\n anonymousIdentifier,\n userJwt,\n createAnonymousIdentifierFallback,\n}: Pick<FetchSurfaceDecisionsArgs, 'anonymousIdentifier' | 'userJwt'> & {\n createAnonymousIdentifierFallback: boolean\n}) => {\n if (!anonymousIdentifier && !userJwt) {\n return { createAnonymousIdentifier: true }\n }\n if (userJwt) {\n return createAnonymousIdentifierFallback ? { userJwt, createAnonymousIdentifierFallback: true } : { userJwt }\n }\n return { anonymousIdentifier }\n}\n\nconst isSurfaceDecisionError = (value: unknown): value is SurfaceDecisionError =>\n isRecord(value) && value.status === 'error' && typeof value.message === 'string' && typeof value.statusCode === 'number'\n\nconst isSurfaceDecisionResponse = (value: unknown): value is SurfaceDecisionResponse =>\n isRecord(value) &&\n value.status === 'success' &&\n isRecord(value.identity) &&\n isRecord(value.features) &&\n isRecord(value.customer) &&\n isRecord(value.surfaceBehavior) &&\n typeof value.componentsSkipped === 'boolean' &&\n isRecord(value.componentBehaviors)\n"]}
|
|
@@ -33,17 +33,26 @@ export default async function getSurfaceDecisions(ctx, request, response, apiFet
|
|
|
33
33
|
return [modifiedResponse, null];
|
|
34
34
|
}
|
|
35
35
|
const surfaceDecisions = result.data;
|
|
36
|
-
|
|
37
|
-
const headers = new Headers(modifiedResponse.headers);
|
|
38
|
-
headers.append('Set-Cookie', `${config.anonymousSessionCookieName}=${surfaceDecisions.identity.identifier}; Path=/`);
|
|
39
|
-
modifiedResponse = new Response(modifiedResponse.body, {
|
|
40
|
-
status: modifiedResponse.status,
|
|
41
|
-
statusText: modifiedResponse.statusText,
|
|
42
|
-
headers,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
36
|
+
modifiedResponse = applyIdentityCookies(modifiedResponse, config, { anonymousIdentifier, userJwt }, surfaceDecisions);
|
|
45
37
|
return [modifiedResponse, surfaceDecisions];
|
|
46
38
|
}
|
|
39
|
+
const applyIdentityCookies = (response, config, identity, surfaceDecisions) => {
|
|
40
|
+
const jwtFallbackToAnonymous = config.createAnonymousIdentifierFallback &&
|
|
41
|
+
Boolean(identity.userJwt) &&
|
|
42
|
+
Boolean(surfaceDecisions.identity?.identifier) &&
|
|
43
|
+
!surfaceDecisions.identity.isAuthenticated;
|
|
44
|
+
const shouldSetAnonymousCookie = Boolean(surfaceDecisions.identity?.identifier) && !identity.anonymousIdentifier && (!identity.userJwt || jwtFallbackToAnonymous);
|
|
45
|
+
if (!shouldSetAnonymousCookie) {
|
|
46
|
+
return response;
|
|
47
|
+
}
|
|
48
|
+
const headers = new Headers(response.headers);
|
|
49
|
+
headers.append('Set-Cookie', `${config.anonymousSessionCookieName}=${surfaceDecisions.identity.identifier}; Path=/`);
|
|
50
|
+
return new Response(response.body, {
|
|
51
|
+
status: response.status,
|
|
52
|
+
statusText: response.statusText,
|
|
53
|
+
headers,
|
|
54
|
+
});
|
|
55
|
+
};
|
|
47
56
|
const getExistingCookies = (request, originResponse, config) => {
|
|
48
57
|
const setCookies = originResponse.headers.getSetCookie().map((header) => parseSetCookie(header));
|
|
49
58
|
const originAnonymousCookie = setCookies.find((s) => s.name === config.anonymousSessionCookieName);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surfaceDecisions.js","sourceRoot":"","sources":["../../src/stages/surfaceDecisions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAO9C,OAAO,qBAAqB,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,mBAAmB,CAC7C,GAAoB,EACpB,OAAgB,EAChB,QAAkB,EAClB,UAAmB,EACnB,QAAoC,EACpC,sBAAqD;IAErD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAA;IAC9B,MAAM,EAAE,mBAAmB,EAAE,OAAO,EAAE,GAAG,kBAAkB,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;IAEtF,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAChF,MAAM,YAAY,GAAG,cAAc,IAAI,QAAQ,CAAC,CAAC,CAAC,MAAM,iBAAiB,CAAC,GAAG,EAAE,IAAI,QAAQ,CAAC,cAAc,EAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACrI,IAAI,gBAAgB,GAAG,iBAAiB,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAA;IAE/F,MAAM,cAAc,GAAG,sBAAsB,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;IAEnE,MAAM,MAAM,GAAG,MAAM,qBAAqB,CACtC,GAAG,EACH;QACI,mBAAmB;QACnB,OAAO;QACP,IAAI,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ;QACnC,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,cAAc;QACd,YAAY;QACZ,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,SAAS;QACzD,YAAY,EAAE,QAAQ,CAAC,MAAM;KAChC,EACD,UAAU,CACb,CAAA;IAED,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,CAAC;YACP,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,8BAA8B;YACpC,OAAO,EAAE,oEAAoE;YAC7E,OAAO,EAAE;gBACL,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,UAAU,EAAE,MAAM,CAAC,UAAU;aAChC;YACD,KAAK,EAAE,MAAM,CAAC,KAAK;SACtB,CAAC,CAAA;QACF,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAA;IACnC,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAA;IAEpC,
|
|
1
|
+
{"version":3,"file":"surfaceDecisions.js","sourceRoot":"","sources":["../../src/stages/surfaceDecisions.ts"],"names":[],"mappings":"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","sourcesContent":["import { parse, parseSetCookie } from 'cookie'\nimport type { ClientMetadataProvider } from '../adapters/ClientMetadataProvider'\nimport type { Fetcher } from '../adapters/Fetcher'\nimport type { HtmlRewriterAdapter } from '../adapters/HtmlRewriterAdapter'\nimport type { MOSConfig } from '../config'\nimport type { PipelineContext } from '../context'\nimport type { SurfaceDecisionResponse } from '../types'\nimport fetchSurfaceDecisions from './fetchSurfaceDecisions'\nimport { parsePageMetadata } from './pageMetadata'\n\nexport default async function getSurfaceDecisions(\n ctx: PipelineContext,\n request: Request,\n response: Response,\n apiFetcher: Fetcher,\n rewriter: HtmlRewriterAdapter | null,\n clientMetadataProvider: ClientMetadataProvider | null,\n): Promise<[Response, SurfaceDecisionResponse | null]> {\n const { config, logger } = ctx\n const { anonymousIdentifier, userJwt } = getExistingCookies(request, response, config)\n\n const [metadataStream, passThroughStream] = response.body?.tee() ?? [null, null]\n const pageMetadata = metadataStream && rewriter ? await parsePageMetadata(ctx, new Response(metadataStream, response), rewriter) : {}\n let modifiedResponse = passThroughStream ? new Response(passThroughStream, response) : response\n\n const clientMetadata = clientMetadataProvider?.build(request) ?? {}\n\n const result = await fetchSurfaceDecisions(\n ctx,\n {\n anonymousIdentifier,\n userJwt,\n path: new URL(request.url).pathname,\n url: request.url,\n clientMetadata,\n pageMetadata,\n userAgent: request.headers.get('User-Agent') ?? undefined,\n originStatus: response.status,\n },\n apiFetcher,\n )\n\n if (!result.ok) {\n logger.log({\n level: 'warn',\n code: 'surface-decisions-api-failed',\n message: 'Surface decisions API failed; continuing with the origin response.',\n context: {\n reason: result.reason,\n status: result.status,\n statusCode: result.statusCode,\n },\n error: result.error,\n })\n return [modifiedResponse, null]\n }\n\n const surfaceDecisions = result.data\n\n modifiedResponse = applyIdentityCookies(modifiedResponse, config, { anonymousIdentifier, userJwt }, surfaceDecisions)\n\n return [modifiedResponse, surfaceDecisions]\n}\n\nconst applyIdentityCookies = (\n response: Response,\n config: MOSConfig,\n identity: { anonymousIdentifier?: string | undefined; userJwt?: string | undefined },\n surfaceDecisions: SurfaceDecisionResponse,\n): Response => {\n const jwtFallbackToAnonymous =\n config.createAnonymousIdentifierFallback &&\n Boolean(identity.userJwt) &&\n Boolean(surfaceDecisions.identity?.identifier) &&\n !surfaceDecisions.identity.isAuthenticated\n\n const shouldSetAnonymousCookie =\n Boolean(surfaceDecisions.identity?.identifier) && !identity.anonymousIdentifier && (!identity.userJwt || jwtFallbackToAnonymous)\n\n if (!shouldSetAnonymousCookie) {\n return response\n }\n\n const headers = new Headers(response.headers)\n headers.append('Set-Cookie', `${config.anonymousSessionCookieName}=${surfaceDecisions.identity.identifier}; Path=/`)\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n })\n}\n\nconst getExistingCookies = (request: Request, originResponse: Response, config: MOSConfig) => {\n const setCookies = originResponse.headers.getSetCookie().map((header) => parseSetCookie(header))\n const originAnonymousCookie = setCookies.find((s) => s.name === config.anonymousSessionCookieName)\n const originUserJwtCookie = setCookies.find((s) => s.name === config.authenticatedUserJwtCookieName)\n if (originAnonymousCookie || originUserJwtCookie) {\n return { anonymousIdentifier: originAnonymousCookie?.value, userJwt: originUserJwtCookie?.value }\n }\n\n const cookies = parse(request.headers.get('Cookie') || '')\n const anonymousIdentifier = cookies[config.anonymousSessionCookieName]\n const userJwt = cookies[config.authenticatedUserJwtCookieName]\n return { anonymousIdentifier, userJwt }\n}\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -113,4 +113,10 @@ export interface MOSConfigInput {
|
|
|
113
113
|
surfaceDecisionsIgnorePaths?: string;
|
|
114
114
|
/** Optional headers added to or replacing client headers on every origin request. */
|
|
115
115
|
originRequestHeaders?: Record<string, string>;
|
|
116
|
+
/**
|
|
117
|
+
* When true (default), JWT surface-decision requests include `createAnonymousIdentifierFallback: true`
|
|
118
|
+
* so MonetizationOS can mint an anonymous identifier if JWT authentication fails.
|
|
119
|
+
* Set to `false` to opt out.
|
|
120
|
+
*/
|
|
121
|
+
createAnonymousIdentifierFallback?: boolean;
|
|
116
122
|
}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type PageMetadata = Record<string, string>\n\nexport interface FeatureMeterableProperty {\n type: 'meterable'\n hasAccess: boolean\n remainingUnits?: number\n}\n\nexport interface FeatureNumberProperty {\n type: 'number'\n value: number\n}\n\nexport interface Feature {\n featureSlug: string\n properties: Record<string, FeatureMeterableProperty | FeatureNumberProperty>\n sideEffects: unknown[]\n}\n\nexport interface SubSurfaceMetadataApi {\n cssSelector?: string | null\n}\n\nexport type SetHttpResponse = {\n headers?: Record<string, string>\n cookies?: string[]\n status: number\n statusText?: string\n body: string | null\n}\n\nexport type ModifyHttpResponse = {\n addHeaders?: { name: string; value: string }[]\n removeHeaders?: string[]\n addCookies?: string[]\n status?: number\n statusText?: string\n body?: string | null\n}\n\nexport type SurfaceBehaviorApi = {\n http?: ModifyHttpResponse | SetHttpResponse\n properties?: Record<string, unknown>\n} & Record<string, unknown>\n\nexport type WebComponentElement<T = Record<string, unknown>> = {\n schema: string\n props: T\n}\n\nexport type WebElement =\n | {\n type: 'html'\n content: string\n }\n | {\n type: 'text'\n content: string\n }\n | ({\n type: 'element'\n } & WebComponentElement)\n | ({\n type: 'custom'\n } & Record<string, unknown>)\n\nexport type WebComponentRangeReplacement = {\n fromMarker?: string\n toMarker?: string\n replaceWith?: WebElement[] | null\n}\n\nexport type WebContentSurfaceBehavior = {\n before?: WebElement[]\n prepend?: WebElement[]\n remove?: boolean\n replaceRange?: WebComponentRangeReplacement | null\n append?: WebElement[]\n after?: WebElement[]\n}\n\nexport type SubSurfaceBehaviorApi = {\n content?: WebContentSurfaceBehavior\n properties?: Record<string, unknown>\n metadata: SubSurfaceMetadataApi\n} & Record<string, unknown>\n\nexport interface SurfaceDecisionResponse {\n status: 'success'\n identity: {\n identifier: string\n isAuthenticated: boolean\n authType: string\n jwtClaims: Record<string, unknown>\n }\n features: Record<string, Feature>\n customer: {\n hasProducts: boolean\n }\n surfaceBehavior: SurfaceBehaviorApi\n componentsSkipped: boolean\n componentBehaviors: Record<string, SubSurfaceBehaviorApi>\n}\n\nexport interface SurfaceDecisionError {\n message: string\n status: 'error'\n statusCode: number\n}\n\nexport interface MOSConfigInput {\n /** Origin website base URL, e.g. `https://news.example.com`. */\n originUrl: string\n /** Surface slug identifying the MonetizationOS surface. */\n surfaceSlug: string\n /** MonetizationOS API base URL. */\n mosHost: string\n /** MonetizationOS secret key; expected format `sk_<env>_<suffix>` */\n mosSecretKey: string\n /** Path prefix routed to the MonetizationOS endpoint proxy. Default: `/mos-endpoints/`. */\n mosEndpointsPrefix?: string\n /** Cookie name storing the anonymous session id. */\n anonymousSessionCookieName: string\n /** Cookie name storing the authenticated user JWT. */\n authenticatedUserJwtCookieName: string\n /** Optional script URL injected into the `<head>` of HTML responses. */\n injectScriptUrl?: string\n /** Comma-separated regex patterns; matching pathnames skip surface decisions. */\n surfaceDecisionsIgnorePaths?: string\n /** Optional headers added to or replacing client headers on every origin request. */\n originRequestHeaders?: Record<string, string>\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type PageMetadata = Record<string, string>\n\nexport interface FeatureMeterableProperty {\n type: 'meterable'\n hasAccess: boolean\n remainingUnits?: number\n}\n\nexport interface FeatureNumberProperty {\n type: 'number'\n value: number\n}\n\nexport interface Feature {\n featureSlug: string\n properties: Record<string, FeatureMeterableProperty | FeatureNumberProperty>\n sideEffects: unknown[]\n}\n\nexport interface SubSurfaceMetadataApi {\n cssSelector?: string | null\n}\n\nexport type SetHttpResponse = {\n headers?: Record<string, string>\n cookies?: string[]\n status: number\n statusText?: string\n body: string | null\n}\n\nexport type ModifyHttpResponse = {\n addHeaders?: { name: string; value: string }[]\n removeHeaders?: string[]\n addCookies?: string[]\n status?: number\n statusText?: string\n body?: string | null\n}\n\nexport type SurfaceBehaviorApi = {\n http?: ModifyHttpResponse | SetHttpResponse\n properties?: Record<string, unknown>\n} & Record<string, unknown>\n\nexport type WebComponentElement<T = Record<string, unknown>> = {\n schema: string\n props: T\n}\n\nexport type WebElement =\n | {\n type: 'html'\n content: string\n }\n | {\n type: 'text'\n content: string\n }\n | ({\n type: 'element'\n } & WebComponentElement)\n | ({\n type: 'custom'\n } & Record<string, unknown>)\n\nexport type WebComponentRangeReplacement = {\n fromMarker?: string\n toMarker?: string\n replaceWith?: WebElement[] | null\n}\n\nexport type WebContentSurfaceBehavior = {\n before?: WebElement[]\n prepend?: WebElement[]\n remove?: boolean\n replaceRange?: WebComponentRangeReplacement | null\n append?: WebElement[]\n after?: WebElement[]\n}\n\nexport type SubSurfaceBehaviorApi = {\n content?: WebContentSurfaceBehavior\n properties?: Record<string, unknown>\n metadata: SubSurfaceMetadataApi\n} & Record<string, unknown>\n\nexport interface SurfaceDecisionResponse {\n status: 'success'\n identity: {\n identifier: string\n isAuthenticated: boolean\n authType: string\n jwtClaims: Record<string, unknown>\n }\n features: Record<string, Feature>\n customer: {\n hasProducts: boolean\n }\n surfaceBehavior: SurfaceBehaviorApi\n componentsSkipped: boolean\n componentBehaviors: Record<string, SubSurfaceBehaviorApi>\n}\n\nexport interface SurfaceDecisionError {\n message: string\n status: 'error'\n statusCode: number\n}\n\nexport interface MOSConfigInput {\n /** Origin website base URL, e.g. `https://news.example.com`. */\n originUrl: string\n /** Surface slug identifying the MonetizationOS surface. */\n surfaceSlug: string\n /** MonetizationOS API base URL. */\n mosHost: string\n /** MonetizationOS secret key; expected format `sk_<env>_<suffix>` */\n mosSecretKey: string\n /** Path prefix routed to the MonetizationOS endpoint proxy. Default: `/mos-endpoints/`. */\n mosEndpointsPrefix?: string\n /** Cookie name storing the anonymous session id. */\n anonymousSessionCookieName: string\n /** Cookie name storing the authenticated user JWT. */\n authenticatedUserJwtCookieName: string\n /** Optional script URL injected into the `<head>` of HTML responses. */\n injectScriptUrl?: string\n /** Comma-separated regex patterns; matching pathnames skip surface decisions. */\n surfaceDecisionsIgnorePaths?: string\n /** Optional headers added to or replacing client headers on every origin request. */\n originRequestHeaders?: Record<string, string>\n /**\n * When true (default), JWT surface-decision requests include `createAnonymousIdentifierFallback: true`\n * so MonetizationOS can mint an anonymous identifier if JWT authentication fails.\n * Set to `false` to opt out.\n */\n createAnonymousIdentifierFallback?: boolean\n}\n"]}
|