@monetizationos/proxy 1.2.0 → 1.4.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/dist/MOSProxy.d.ts +4 -1
- package/dist/MOSProxy.js +9 -3
- package/dist/MOSProxy.js.map +1 -1
- package/dist/MOSProxyBuilder.d.ts +17 -1
- package/dist/MOSProxyBuilder.js +30 -0
- package/dist/MOSProxyBuilder.js.map +1 -1
- package/dist/adapters/IdentityProvider.d.ts +1 -1
- package/dist/adapters/IdentityProvider.js +1 -1
- package/dist/adapters/IdentityProvider.js.map +1 -1
- package/dist/adapters/ResourceProvider.d.ts +26 -0
- package/dist/adapters/ResourceProvider.js +2 -0
- package/dist/adapters/ResourceProvider.js.map +1 -0
- package/dist/adapters/index.d.ts +1 -0
- package/dist/adapters/index.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/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/stages/fetchSurfaceDecisions.d.ts +4 -4
- package/dist/stages/fetchSurfaceDecisions.js +2 -5
- package/dist/stages/fetchSurfaceDecisions.js.map +1 -1
- package/dist/stages/mosAuthenticatedApi.d.ts +4 -0
- package/dist/stages/mosAuthenticatedApi.js +36 -0
- package/dist/stages/mosAuthenticatedApi.js.map +1 -0
- package/dist/stages/surfaceDecisions.d.ts +2 -1
- package/dist/stages/surfaceDecisions.js +3 -3
- package/dist/stages/surfaceDecisions.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/dist/MOSProxy.d.ts
CHANGED
|
@@ -2,8 +2,9 @@ import type { ClientMetadataProvider } from './adapters/ClientMetadataProvider';
|
|
|
2
2
|
import type { Fetcher } from './adapters/Fetcher';
|
|
3
3
|
import type { HtmlRewriterAdapter } from './adapters/HtmlRewriterAdapter';
|
|
4
4
|
import type { IdentityProvider } from './adapters/IdentityProvider';
|
|
5
|
+
import type { ResourceProvider } from './adapters/ResourceProvider';
|
|
5
6
|
import { type MOSProxyLogger } from './logger';
|
|
6
|
-
import type { MOSConfigInput } from './types';
|
|
7
|
+
import type { MOSConfigInput, MosAuthenticatedApiRoute } from './types';
|
|
7
8
|
export type MOSProxyHtmlPipelineStage = 'origin-response' | 'link-rewriting' | 'surface-decisions' | 'surface-behavior' | 'surface-components';
|
|
8
9
|
export interface MOSProxyHtmlPipelineErrorContext {
|
|
9
10
|
error: unknown;
|
|
@@ -26,12 +27,14 @@ export interface MOSProxyOptions {
|
|
|
26
27
|
htmlRewriter: HtmlRewriterAdapter | null;
|
|
27
28
|
clientMetadataProvider: ClientMetadataProvider | null;
|
|
28
29
|
identityProvider: IdentityProvider | null;
|
|
30
|
+
resourceProvider: ResourceProvider | null;
|
|
29
31
|
logger?: MOSProxyLogger;
|
|
30
32
|
onHtmlPipelineError?: MOSProxyHtmlPipelineErrorHandler;
|
|
31
33
|
customEndpointsEnabled: boolean;
|
|
32
34
|
linkRewritingEnabled: boolean;
|
|
33
35
|
surfaceDecisionsEnabled: boolean;
|
|
34
36
|
htmlTransformationEnabled: boolean;
|
|
37
|
+
mosAuthenticatedApiRoutes?: MosAuthenticatedApiRoute[];
|
|
35
38
|
}
|
|
36
39
|
/**
|
|
37
40
|
* Platform-agnostic MonetizationOS proxy. Build one with `MOSProxyBuilder`, then call
|
package/dist/MOSProxy.js
CHANGED
|
@@ -3,6 +3,7 @@ import { consoleLogger } from './logger';
|
|
|
3
3
|
import customEndpointRequest from './stages/customEndpoint';
|
|
4
4
|
import isRedirectResponse from './stages/isRedirectResponse';
|
|
5
5
|
import rewriteOriginResponse from './stages/linkRewriting';
|
|
6
|
+
import { handleMosAuthenticatedApiRoutes } from './stages/mosAuthenticatedApi';
|
|
6
7
|
import performOriginRequest from './stages/originRequest';
|
|
7
8
|
import shouldIgnorePath from './stages/shouldIgnorePath';
|
|
8
9
|
import handleSurfaceBehavior from './stages/surfaceBehavior';
|
|
@@ -20,7 +21,7 @@ export class MOSProxy {
|
|
|
20
21
|
this.config = normalizeMOSConfig(opts.config, opts.logger ?? consoleLogger);
|
|
21
22
|
}
|
|
22
23
|
async handle(request) {
|
|
23
|
-
const { originFetcher, apiFetcher, htmlRewriter, clientMetadataProvider, identityProvider, onHtmlPipelineError } = this.opts;
|
|
24
|
+
const { originFetcher, apiFetcher, htmlRewriter, clientMetadataProvider, identityProvider, resourceProvider, onHtmlPipelineError } = this.opts;
|
|
24
25
|
const logger = this.opts.logger ?? consoleLogger;
|
|
25
26
|
const ctx = { config: this.config, logger };
|
|
26
27
|
// Stage 1a: custom endpoint routing
|
|
@@ -33,7 +34,12 @@ export class MOSProxy {
|
|
|
33
34
|
return customEndpointResponse;
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
|
-
// Stage 1b:
|
|
37
|
+
// Stage 1b: authenticated API routing
|
|
38
|
+
const authenticatedApiResult = await handleMosAuthenticatedApiRoutes(request, this.opts.mosAuthenticatedApiRoutes ?? [], ctx, identityProvider, clientMetadataProvider, apiFetcher);
|
|
39
|
+
if (authenticatedApiResult) {
|
|
40
|
+
return authenticatedApiResult;
|
|
41
|
+
}
|
|
42
|
+
// Stage 1c: origin fetch
|
|
37
43
|
const originResponse = await performOriginRequest(ctx, request, originFetcher);
|
|
38
44
|
// Auto-skip HTML pipeline for non-HTML content, or when HTML transformation is disabled entirely
|
|
39
45
|
const isHtml = originResponse.headers.get('Content-Type')?.startsWith('text/html') ?? false;
|
|
@@ -61,7 +67,7 @@ export class MOSProxy {
|
|
|
61
67
|
throw new Error('MOSProxy: surfaceDecisions is enabled but no API fetcher is configured');
|
|
62
68
|
}
|
|
63
69
|
stage = 'surface-decisions';
|
|
64
|
-
const [modifiedResponse, surfaceDecisions] = await getSurfaceDecisions(ctx, request, rewrittenResponse, apiFetcher, htmlRewriter, clientMetadataProvider, identityProvider);
|
|
70
|
+
const [modifiedResponse, surfaceDecisions] = await getSurfaceDecisions(ctx, request, rewrittenResponse, apiFetcher, htmlRewriter, clientMetadataProvider, identityProvider, resourceProvider);
|
|
65
71
|
if (!surfaceDecisions) {
|
|
66
72
|
return modifiedResponse;
|
|
67
73
|
}
|
package/dist/MOSProxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MOSProxy.js","sourceRoot":"","sources":["../src/MOSProxy.ts"],"names":[],"mappings":"AAIA,OAAO,EAAkB,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAE7D,OAAO,EAAE,aAAa,EAAuB,MAAM,UAAU,CAAA;AAC7D,OAAO,qBAAqB,MAAM,yBAAyB,CAAA;AAC3D,OAAO,kBAAkB,MAAM,6BAA6B,CAAA;AAC5D,OAAO,qBAAqB,MAAM,wBAAwB,CAAA;AAC1D,OAAO,oBAAoB,MAAM,wBAAwB,CAAA;AACzD,OAAO,gBAAgB,MAAM,2BAA2B,CAAA;AACxD,OAAO,qBAAqB,MAAM,0BAA0B,CAAA;AAC5D,OAAO,uBAAuB,MAAM,4BAA4B,CAAA;AAChE,OAAO,mBAAmB,MAAM,2BAA2B,CAAA;AAyC3D;;;GAGG;AACH,MAAM,OAAO,QAAQ;IAGY;IAFZ,MAAM,CAAW;IAElC,YAA6B,IAAqB;QAArB,SAAI,GAAJ,IAAI,CAAiB;QAC9C,IAAI,CAAC,MAAM,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,aAAa,CAAC,CAAA;IAC/E,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAgB;QACzB,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,GAAG,IAAI,CAAC,IAAI,CAAA;QAC5H,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,aAAa,CAAA;QAChD,MAAM,GAAG,GAAoB,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,CAAA;QAE5D,oCAAoC;QACpC,IAAI,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACnC,IAAI,CAAC,UAAU,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAA;YAC5F,CAAC;YACD,MAAM,sBAAsB,GAAG,MAAM,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;YACpF,IAAI,sBAAsB,EAAE,CAAC;gBACzB,OAAO,sBAAsB,CAAA;YACjC,CAAC;QACL,CAAC;QAED,yBAAyB;QACzB,MAAM,cAAc,GAAG,MAAM,oBAAoB,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,CAAC,CAAA;QAE9E,iGAAiG;QACjG,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,WAAW,CAAC,IAAI,KAAK,CAAA;QAC3F,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE,CAAC;YAClD,OAAO,cAAc,CAAA;QACzB,CAAC;QAED,IAAI,KAAK,GAA8B,iBAAiB,CAAA;QACxD,IAAI,gBAAgB,GAAG,wBAAwB,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;QAE9E,IAAI,CAAC;YACD,2CAA2C;YAC3C,IAAI,iBAAiB,GAAa,cAAc,CAAA;YAChD,IAAI,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC;gBACjC,KAAK,GAAG,gBAAgB,CAAA;gBACxB,iBAAiB,GAAG,MAAM,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,cAAc,CAAC,CAAA;gBAC7E,gBAAgB,GAAG,wBAAwB,CAAC,iBAAiB,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;YACjF,CAAC;YAED,wCAAwC;YACxC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,uBAAuB,EAAE,CAAC;gBACrC,OAAO,iBAAiB,CAAA;YAC5B,CAAC;YACD,IAAI,gBAAgB,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,kBAAkB,CAAC,iBAAiB,CAAC,EAAE,CAAC;gBAC1E,OAAO,iBAAiB,CAAA;YAC5B,CAAC;YAED,IAAI,CAAC,UAAU,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAA;YAC7F,CAAC;YAED,KAAK,GAAG,mBAAmB,CAAA;YAC3B,MAAM,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,GAAG,MAAM,mBAAmB,CAClE,GAAG,EACH,OAAO,EACP,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,sBAAsB,EACtB,gBAAgB,CACnB,CAAA;YACD,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACpB,OAAO,gBAAgB,CAAA;YAC3B,CAAC;YACD,gBAAgB,GAAG,wBAAwB,CAAC,gBAAgB,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;YAE5E,yCAAyC;YACzC,KAAK,GAAG,kBAAkB,CAAA;YAC1B,MAAM,CAAC,uBAAuB,EAAE,iBAAiB,CAAC,GAAG,qBAAqB,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAA;YAC9G,IAAI,iBAAiB,EAAE,CAAC;gBACpB,OAAO,uBAAuB,CAAA;YAClC,CAAC;YACD,gBAAgB,GAAG,wBAAwB,CAAC,uBAAuB,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;YAEnF,uEAAuE;YACvE,IAAI,CAAC,YAAY,EAAE,CAAC;gBAChB,OAAO,uBAAuB,CAAA;YAClC,CAAC;YACD,KAAK,GAAG,oBAAoB,CAAA;YAC5B,OAAO,MAAM,uBAAuB,CAAC,GAAG,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,YAAY,CAAC,CAAA;QACtG,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,CAAC;gBACP,KAAK,EAAE,OAAO;gBACd,IAAI,EAAE,sBAAsB;gBAC5B,OAAO,EAAE,uBAAuB;gBAChC,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,CAAC,mBAAmB,CAAC,EAAE;gBACjE,KAAK;aACR,CAAC,CAAA;YAEF,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBACvB,OAAO,gBAAgB,CAAA;YAC3B,CAAC;YAED,IAAI,CAAC;gBACD,MAAM,eAAe,GAAG,MAAM,mBAAmB,CAAC;oBAC9C,KAAK;oBACL,KAAK;oBACL,OAAO;oBACP,gBAAgB,EAAE,gBAAgB;iBACrC,CAAC,CAAA;gBACF,IAAI,CAAC,CAAC,eAAe,YAAY,QAAQ,CAAC,EAAE,CAAC;oBACzC,MAAM,CAAC,GAAG,CAAC;wBACP,KAAK,EAAE,MAAM;wBACb,IAAI,EAAE,qCAAqC;wBAC3C,OAAO,EAAE,wFAAwF;wBACjG,OAAO,EAAE,EAAE,KAAK,EAAE;qBACrB,CAAC,CAAA;oBACF,OAAO,gBAAgB,CAAA;gBAC3B,CAAC;gBACD,OAAO,eAAe,CAAA;YAC1B,CAAC;YAAC,OAAO,YAAY,EAAE,CAAC;gBACpB,MAAM,CAAC,GAAG,CAAC;oBACP,KAAK,EAAE,MAAM;oBACb,IAAI,EAAE,mCAAmC;oBACzC,OAAO,EAAE,oEAAoE;oBAC7E,OAAO,EAAE,EAAE,KAAK,EAAE;oBAClB,KAAK,EAAE,YAAY;iBACtB,CAAC,CAAA;gBACF,OAAO,gBAAgB,CAAA;YAC3B,CAAC;QACL,CAAC;IACL,CAAC;CACJ;AAED,MAAM,wBAAwB,GAAG,CAAC,QAAkB,EAAE,MAAsB,EAAE,KAAgC,EAAY,EAAE;IACxH,IAAI,CAAC;QACD,OAAO,QAAQ,CAAC,KAAK,EAAE,CAAA;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,CAAC;YACP,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,uBAAuB;YAC7B,OAAO,EAAE,kDAAkD;YAC3D,OAAO,EAAE,EAAE,KAAK,EAAE;YAClB,KAAK;SACR,CAAC,CAAA;QACF,OAAO,QAAQ,CAAA;IACnB,CAAC;AACL,CAAC,CAAA","sourcesContent":["import type { ClientMetadataProvider } from './adapters/ClientMetadataProvider'\nimport type { Fetcher } from './adapters/Fetcher'\nimport type { HtmlRewriterAdapter } from './adapters/HtmlRewriterAdapter'\nimport type { IdentityProvider } from './adapters/IdentityProvider'\nimport { type MOSConfig, normalizeMOSConfig } from './config'\nimport type { PipelineContext } from './context'\nimport { consoleLogger, type MOSProxyLogger } from './logger'\nimport customEndpointRequest from './stages/customEndpoint'\nimport isRedirectResponse from './stages/isRedirectResponse'\nimport rewriteOriginResponse from './stages/linkRewriting'\nimport performOriginRequest from './stages/originRequest'\nimport shouldIgnorePath from './stages/shouldIgnorePath'\nimport handleSurfaceBehavior from './stages/surfaceBehavior'\nimport handleSurfaceComponents from './stages/surfaceComponents'\nimport getSurfaceDecisions from './stages/surfaceDecisions'\nimport type { MOSConfigInput } from './types'\n\nexport type MOSProxyHtmlPipelineStage =\n | 'origin-response'\n | 'link-rewriting'\n | 'surface-decisions'\n | 'surface-behavior'\n | 'surface-components'\n\nexport interface MOSProxyHtmlPipelineErrorContext {\n error: unknown\n stage: MOSProxyHtmlPipelineStage\n request: Request\n lastSafeResponse: Response\n}\n\n/**\n * Called when the HTML pipeline throws. Return a `Response` to fully control the proxy's reply, or\n * re-throw to surface the error to the platform handler. If omitted, the proxy fails open and\n * returns `lastSafeResponse`. If the callback itself throws or returns a non-Response value, the\n * proxy logs a warning and falls back to `lastSafeResponse` so the site cannot be taken down by a\n * bug in the handler.\n */\nexport type MOSProxyHtmlPipelineErrorHandler = (ctx: MOSProxyHtmlPipelineErrorContext) => Response | Promise<Response>\n\nexport interface MOSProxyOptions {\n config: MOSConfigInput\n originFetcher: Fetcher\n apiFetcher: Fetcher | null\n htmlRewriter: HtmlRewriterAdapter | null\n clientMetadataProvider: ClientMetadataProvider | null\n identityProvider: IdentityProvider | null\n logger?: MOSProxyLogger\n onHtmlPipelineError?: MOSProxyHtmlPipelineErrorHandler\n customEndpointsEnabled: boolean\n linkRewritingEnabled: boolean\n surfaceDecisionsEnabled: boolean\n htmlTransformationEnabled: boolean\n}\n\n/**\n * Platform-agnostic MonetizationOS proxy. Build one with `MOSProxyBuilder`, then call\n * `proxy.handle(request)` from your platform's fetch entry point.\n */\nexport class MOSProxy {\n private readonly config: MOSConfig\n\n constructor(private readonly opts: MOSProxyOptions) {\n this.config = normalizeMOSConfig(opts.config, opts.logger ?? consoleLogger)\n }\n\n async handle(request: Request): Promise<Response> {\n const { originFetcher, apiFetcher, htmlRewriter, clientMetadataProvider, identityProvider, onHtmlPipelineError } = this.opts\n const logger = this.opts.logger ?? consoleLogger\n const ctx: PipelineContext = { config: this.config, logger }\n\n // Stage 1a: custom endpoint routing\n if (this.opts.customEndpointsEnabled) {\n if (!apiFetcher) {\n throw new Error('MOSProxy: customEndpoints is enabled but no API fetcher is configured')\n }\n const customEndpointResponse = await customEndpointRequest(ctx, request, apiFetcher)\n if (customEndpointResponse) {\n return customEndpointResponse\n }\n }\n\n // Stage 1b: origin fetch\n const originResponse = await performOriginRequest(ctx, request, originFetcher)\n\n // Auto-skip HTML pipeline for non-HTML content, or when HTML transformation is disabled entirely\n const isHtml = originResponse.headers.get('Content-Type')?.startsWith('text/html') ?? false\n if (!isHtml || !this.opts.htmlTransformationEnabled) {\n return originResponse\n }\n\n let stage: MOSProxyHtmlPipelineStage = 'origin-response'\n let failOpenResponse = cloneResponseForFallback(originResponse, logger, stage)\n\n try {\n // Stage 2: rewrite origin links (optional)\n let rewrittenResponse: Response = originResponse\n if (this.opts.linkRewritingEnabled) {\n stage = 'link-rewriting'\n rewrittenResponse = await rewriteOriginResponse(ctx, request, originResponse)\n failOpenResponse = cloneResponseForFallback(rewrittenResponse, logger, stage)\n }\n\n // Stage 3: surface decisions (optional)\n if (!this.opts.surfaceDecisionsEnabled) {\n return rewrittenResponse\n }\n if (shouldIgnorePath(ctx, request) || isRedirectResponse(rewrittenResponse)) {\n return rewrittenResponse\n }\n\n if (!apiFetcher) {\n throw new Error('MOSProxy: surfaceDecisions is enabled but no API fetcher is configured')\n }\n\n stage = 'surface-decisions'\n const [modifiedResponse, surfaceDecisions] = await getSurfaceDecisions(\n ctx,\n request,\n rewrittenResponse,\n apiFetcher,\n htmlRewriter,\n clientMetadataProvider,\n identityProvider,\n )\n if (!surfaceDecisions) {\n return modifiedResponse\n }\n failOpenResponse = cloneResponseForFallback(modifiedResponse, logger, stage)\n\n // Stage 4: surface behavior (HTTP-level)\n stage = 'surface-behavior'\n const [surfaceDecisionResponse, returnImmediately] = handleSurfaceBehavior(modifiedResponse, surfaceDecisions)\n if (returnImmediately) {\n return surfaceDecisionResponse\n }\n failOpenResponse = cloneResponseForFallback(surfaceDecisionResponse, logger, stage)\n\n // Stage 5: surface components (HTML-level) — requires an HTML rewriter\n if (!htmlRewriter) {\n return surfaceDecisionResponse\n }\n stage = 'surface-components'\n return await handleSurfaceComponents(ctx, surfaceDecisionResponse, surfaceDecisions, htmlRewriter)\n } catch (error) {\n logger.log({\n level: 'error',\n code: 'html-pipeline-failed',\n message: 'HTML pipeline failed.',\n context: { stage, hasErrorHandler: Boolean(onHtmlPipelineError) },\n error,\n })\n\n if (!onHtmlPipelineError) {\n return failOpenResponse\n }\n\n try {\n const handlerResponse = await onHtmlPipelineError({\n error,\n stage,\n request,\n lastSafeResponse: failOpenResponse,\n })\n if (!(handlerResponse instanceof Response)) {\n logger.log({\n level: 'warn',\n code: 'html-pipeline-error-handler-invalid',\n message: 'onHtmlPipelineError did not return a Response; falling back to the last safe response.',\n context: { stage },\n })\n return failOpenResponse\n }\n return handlerResponse\n } catch (handlerError) {\n logger.log({\n level: 'warn',\n code: 'html-pipeline-error-handler-threw',\n message: 'onHtmlPipelineError threw; falling back to the last safe response.',\n context: { stage },\n error: handlerError,\n })\n return failOpenResponse\n }\n }\n }\n}\n\nconst cloneResponseForFallback = (response: Response, logger: MOSProxyLogger, stage: MOSProxyHtmlPipelineStage): Response => {\n try {\n return response.clone()\n } catch (error) {\n logger.log({\n level: 'warn',\n code: 'response-clone-failed',\n message: 'Could not clone response for fail-open fallback.',\n context: { stage },\n error,\n })\n return response\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MOSProxy.js","sourceRoot":"","sources":["../src/MOSProxy.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 { IdentityProvider } from './adapters/IdentityProvider'\nimport type { ResourceProvider } from './adapters/ResourceProvider'\nimport { type MOSConfig, normalizeMOSConfig } from './config'\nimport type { PipelineContext } from './context'\nimport { consoleLogger, type MOSProxyLogger } from './logger'\nimport customEndpointRequest from './stages/customEndpoint'\nimport isRedirectResponse from './stages/isRedirectResponse'\nimport rewriteOriginResponse from './stages/linkRewriting'\nimport { handleMosAuthenticatedApiRoutes } from './stages/mosAuthenticatedApi'\nimport performOriginRequest from './stages/originRequest'\nimport shouldIgnorePath from './stages/shouldIgnorePath'\nimport handleSurfaceBehavior from './stages/surfaceBehavior'\nimport handleSurfaceComponents from './stages/surfaceComponents'\nimport getSurfaceDecisions from './stages/surfaceDecisions'\nimport type { MOSConfigInput, MosAuthenticatedApiRoute } from './types'\n\nexport type MOSProxyHtmlPipelineStage =\n | 'origin-response'\n | 'link-rewriting'\n | 'surface-decisions'\n | 'surface-behavior'\n | 'surface-components'\n\nexport interface MOSProxyHtmlPipelineErrorContext {\n error: unknown\n stage: MOSProxyHtmlPipelineStage\n request: Request\n lastSafeResponse: Response\n}\n\n/**\n * Called when the HTML pipeline throws. Return a `Response` to fully control the proxy's reply, or\n * re-throw to surface the error to the platform handler. If omitted, the proxy fails open and\n * returns `lastSafeResponse`. If the callback itself throws or returns a non-Response value, the\n * proxy logs a warning and falls back to `lastSafeResponse` so the site cannot be taken down by a\n * bug in the handler.\n */\nexport type MOSProxyHtmlPipelineErrorHandler = (ctx: MOSProxyHtmlPipelineErrorContext) => Response | Promise<Response>\n\nexport interface MOSProxyOptions {\n config: MOSConfigInput\n originFetcher: Fetcher\n apiFetcher: Fetcher | null\n htmlRewriter: HtmlRewriterAdapter | null\n clientMetadataProvider: ClientMetadataProvider | null\n identityProvider: IdentityProvider | null\n resourceProvider: ResourceProvider | null\n logger?: MOSProxyLogger\n onHtmlPipelineError?: MOSProxyHtmlPipelineErrorHandler\n customEndpointsEnabled: boolean\n linkRewritingEnabled: boolean\n surfaceDecisionsEnabled: boolean\n htmlTransformationEnabled: boolean\n mosAuthenticatedApiRoutes?: MosAuthenticatedApiRoute[]\n}\n\n/**\n * Platform-agnostic MonetizationOS proxy. Build one with `MOSProxyBuilder`, then call\n * `proxy.handle(request)` from your platform's fetch entry point.\n */\nexport class MOSProxy {\n private readonly config: MOSConfig\n\n constructor(private readonly opts: MOSProxyOptions) {\n this.config = normalizeMOSConfig(opts.config, opts.logger ?? consoleLogger)\n }\n\n async handle(request: Request): Promise<Response> {\n const { originFetcher, apiFetcher, htmlRewriter, clientMetadataProvider, identityProvider, resourceProvider, onHtmlPipelineError } =\n this.opts\n const logger = this.opts.logger ?? consoleLogger\n const ctx: PipelineContext = { config: this.config, logger }\n\n // Stage 1a: custom endpoint routing\n if (this.opts.customEndpointsEnabled) {\n if (!apiFetcher) {\n throw new Error('MOSProxy: customEndpoints is enabled but no API fetcher is configured')\n }\n const customEndpointResponse = await customEndpointRequest(ctx, request, apiFetcher)\n if (customEndpointResponse) {\n return customEndpointResponse\n }\n }\n\n // Stage 1b: authenticated API routing\n const authenticatedApiResult = await handleMosAuthenticatedApiRoutes(\n request,\n this.opts.mosAuthenticatedApiRoutes ?? [],\n ctx,\n identityProvider,\n clientMetadataProvider,\n apiFetcher,\n )\n if (authenticatedApiResult) {\n return authenticatedApiResult\n }\n\n // Stage 1c: origin fetch\n const originResponse = await performOriginRequest(ctx, request, originFetcher)\n\n // Auto-skip HTML pipeline for non-HTML content, or when HTML transformation is disabled entirely\n const isHtml = originResponse.headers.get('Content-Type')?.startsWith('text/html') ?? false\n if (!isHtml || !this.opts.htmlTransformationEnabled) {\n return originResponse\n }\n\n let stage: MOSProxyHtmlPipelineStage = 'origin-response'\n let failOpenResponse = cloneResponseForFallback(originResponse, logger, stage)\n\n try {\n // Stage 2: rewrite origin links (optional)\n let rewrittenResponse: Response = originResponse\n if (this.opts.linkRewritingEnabled) {\n stage = 'link-rewriting'\n rewrittenResponse = await rewriteOriginResponse(ctx, request, originResponse)\n failOpenResponse = cloneResponseForFallback(rewrittenResponse, logger, stage)\n }\n\n // Stage 3: surface decisions (optional)\n if (!this.opts.surfaceDecisionsEnabled) {\n return rewrittenResponse\n }\n if (shouldIgnorePath(ctx, request) || isRedirectResponse(rewrittenResponse)) {\n return rewrittenResponse\n }\n\n if (!apiFetcher) {\n throw new Error('MOSProxy: surfaceDecisions is enabled but no API fetcher is configured')\n }\n\n stage = 'surface-decisions'\n const [modifiedResponse, surfaceDecisions] = await getSurfaceDecisions(\n ctx,\n request,\n rewrittenResponse,\n apiFetcher,\n htmlRewriter,\n clientMetadataProvider,\n identityProvider,\n resourceProvider,\n )\n if (!surfaceDecisions) {\n return modifiedResponse\n }\n failOpenResponse = cloneResponseForFallback(modifiedResponse, logger, stage)\n\n // Stage 4: surface behavior (HTTP-level)\n stage = 'surface-behavior'\n const [surfaceDecisionResponse, returnImmediately] = handleSurfaceBehavior(modifiedResponse, surfaceDecisions)\n if (returnImmediately) {\n return surfaceDecisionResponse\n }\n failOpenResponse = cloneResponseForFallback(surfaceDecisionResponse, logger, stage)\n\n // Stage 5: surface components (HTML-level) — requires an HTML rewriter\n if (!htmlRewriter) {\n return surfaceDecisionResponse\n }\n stage = 'surface-components'\n return await handleSurfaceComponents(ctx, surfaceDecisionResponse, surfaceDecisions, htmlRewriter)\n } catch (error) {\n logger.log({\n level: 'error',\n code: 'html-pipeline-failed',\n message: 'HTML pipeline failed.',\n context: { stage, hasErrorHandler: Boolean(onHtmlPipelineError) },\n error,\n })\n\n if (!onHtmlPipelineError) {\n return failOpenResponse\n }\n\n try {\n const handlerResponse = await onHtmlPipelineError({\n error,\n stage,\n request,\n lastSafeResponse: failOpenResponse,\n })\n if (!(handlerResponse instanceof Response)) {\n logger.log({\n level: 'warn',\n code: 'html-pipeline-error-handler-invalid',\n message: 'onHtmlPipelineError did not return a Response; falling back to the last safe response.',\n context: { stage },\n })\n return failOpenResponse\n }\n return handlerResponse\n } catch (handlerError) {\n logger.log({\n level: 'warn',\n code: 'html-pipeline-error-handler-threw',\n message: 'onHtmlPipelineError threw; falling back to the last safe response.',\n context: { stage },\n error: handlerError,\n })\n return failOpenResponse\n }\n }\n }\n}\n\nconst cloneResponseForFallback = (response: Response, logger: MOSProxyLogger, stage: MOSProxyHtmlPipelineStage): Response => {\n try {\n return response.clone()\n } catch (error) {\n logger.log({\n level: 'warn',\n code: 'response-clone-failed',\n message: 'Could not clone response for fail-open fallback.',\n context: { stage },\n error,\n })\n return response\n }\n}\n"]}
|
|
@@ -2,9 +2,10 @@ import type { ClientMetadataProvider } from './adapters/ClientMetadataProvider';
|
|
|
2
2
|
import type { Fetcher } from './adapters/Fetcher';
|
|
3
3
|
import type { HtmlRewriterAdapter } from './adapters/HtmlRewriterAdapter';
|
|
4
4
|
import type { IdentityProvider } from './adapters/IdentityProvider';
|
|
5
|
+
import type { ResourceProvider } from './adapters/ResourceProvider';
|
|
5
6
|
import type { MOSProxyLogger } from './logger';
|
|
6
7
|
import { MOSProxy, type MOSProxyHtmlPipelineErrorHandler } from './MOSProxy';
|
|
7
|
-
import type { MOSConfigInput } from './types';
|
|
8
|
+
import type { MOSConfigInput, MosAuthenticatedApiRoute } from './types';
|
|
8
9
|
/**
|
|
9
10
|
* Fluent builder for `MOSProxy`. Provide configuration and platform adapters, then `build()`.
|
|
10
11
|
*
|
|
@@ -44,12 +45,14 @@ export declare class MOSProxyBuilder {
|
|
|
44
45
|
private _htmlRewriter;
|
|
45
46
|
private _clientMetadataProvider;
|
|
46
47
|
private _identityProvider;
|
|
48
|
+
private _resourceProvider;
|
|
47
49
|
private _logger;
|
|
48
50
|
private _onHtmlPipelineError;
|
|
49
51
|
private _customEndpoints;
|
|
50
52
|
private _linkRewriting;
|
|
51
53
|
private _surfaceDecisions;
|
|
52
54
|
private _htmlTransformation;
|
|
55
|
+
private _additionalAuthenticatedApiRoutes;
|
|
53
56
|
withConfig(config: MOSConfigInput): this;
|
|
54
57
|
withOriginFetcher(fetcher: Fetcher): this;
|
|
55
58
|
withApiFetcher(fetcher: Fetcher): this;
|
|
@@ -63,6 +66,13 @@ export declare class MOSProxyBuilder {
|
|
|
63
66
|
* methods fall back to the built-in defaults.
|
|
64
67
|
*/
|
|
65
68
|
withIdentityProvider(provider: IdentityProvider): this;
|
|
69
|
+
/**
|
|
70
|
+
* Override the resource object sent to the surface-decisions API per request. `build` receives
|
|
71
|
+
* only the `Request`; the proxy derives defaults (`{ id: pathname, meta: pageMetadata }`) and
|
|
72
|
+
* shallow-merges your returned record over them. Return only the keys you want to add or
|
|
73
|
+
* override (e.g. a content tier or canonical id) — `id`/`meta` are preserved unless you set them.
|
|
74
|
+
*/
|
|
75
|
+
withResourceProvider(provider: ResourceProvider): this;
|
|
66
76
|
withLogger(logger: MOSProxyLogger): this;
|
|
67
77
|
/**
|
|
68
78
|
* Register a callback to handle HTML pipeline errors. The proxy fails open by default and
|
|
@@ -82,5 +92,11 @@ export declare class MOSProxyBuilder {
|
|
|
82
92
|
* if custom endpoints and surface decisions are both disabled alongside this.
|
|
83
93
|
*/
|
|
84
94
|
withoutHtmlTransformation(): this;
|
|
95
|
+
/**
|
|
96
|
+
* Add an additional route which, when matched by an incoming request, will be forwarded to the MonetizationOS API
|
|
97
|
+
* with authentication handled by the configured identity provider.
|
|
98
|
+
* This is in addition to the default `/mos-api/offer-redemptions` route.
|
|
99
|
+
*/
|
|
100
|
+
withMosAuthenticatedApiRoutes(...routes: MosAuthenticatedApiRoute[]): this;
|
|
85
101
|
build(): MOSProxy;
|
|
86
102
|
}
|
package/dist/MOSProxyBuilder.js
CHANGED
|
@@ -38,12 +38,14 @@ export class MOSProxyBuilder {
|
|
|
38
38
|
_htmlRewriter = null;
|
|
39
39
|
_clientMetadataProvider = null;
|
|
40
40
|
_identityProvider = null;
|
|
41
|
+
_resourceProvider = null;
|
|
41
42
|
_logger = null;
|
|
42
43
|
_onHtmlPipelineError = null;
|
|
43
44
|
_customEndpoints = true;
|
|
44
45
|
_linkRewriting = true;
|
|
45
46
|
_surfaceDecisions = true;
|
|
46
47
|
_htmlTransformation = true;
|
|
48
|
+
_additionalAuthenticatedApiRoutes = [];
|
|
47
49
|
withConfig(config) {
|
|
48
50
|
this._config = config;
|
|
49
51
|
return this;
|
|
@@ -75,6 +77,16 @@ export class MOSProxyBuilder {
|
|
|
75
77
|
this._identityProvider = provider;
|
|
76
78
|
return this;
|
|
77
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Override the resource object sent to the surface-decisions API per request. `build` receives
|
|
82
|
+
* only the `Request`; the proxy derives defaults (`{ id: pathname, meta: pageMetadata }`) and
|
|
83
|
+
* shallow-merges your returned record over them. Return only the keys you want to add or
|
|
84
|
+
* override (e.g. a content tier or canonical id) — `id`/`meta` are preserved unless you set them.
|
|
85
|
+
*/
|
|
86
|
+
withResourceProvider(provider) {
|
|
87
|
+
this._resourceProvider = provider;
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
78
90
|
withLogger(logger) {
|
|
79
91
|
this._logger = logger;
|
|
80
92
|
return this;
|
|
@@ -112,6 +124,15 @@ export class MOSProxyBuilder {
|
|
|
112
124
|
this._htmlTransformation = false;
|
|
113
125
|
return this;
|
|
114
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Add an additional route which, when matched by an incoming request, will be forwarded to the MonetizationOS API
|
|
129
|
+
* with authentication handled by the configured identity provider.
|
|
130
|
+
* This is in addition to the default `/mos-api/offer-redemptions` route.
|
|
131
|
+
*/
|
|
132
|
+
withMosAuthenticatedApiRoutes(...routes) {
|
|
133
|
+
this._additionalAuthenticatedApiRoutes.push(...routes);
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
115
136
|
build() {
|
|
116
137
|
if (!this._config) {
|
|
117
138
|
throw new Error('MOSProxyBuilder: withConfig(...) is required');
|
|
@@ -127,12 +148,21 @@ export class MOSProxyBuilder {
|
|
|
127
148
|
htmlRewriter: this._htmlRewriter,
|
|
128
149
|
clientMetadataProvider: this._clientMetadataProvider,
|
|
129
150
|
identityProvider: this._identityProvider,
|
|
151
|
+
resourceProvider: this._resourceProvider,
|
|
130
152
|
logger: this._logger ?? undefined,
|
|
131
153
|
onHtmlPipelineError: this._onHtmlPipelineError ?? undefined,
|
|
132
154
|
customEndpointsEnabled: this._customEndpoints,
|
|
133
155
|
linkRewritingEnabled: this._linkRewriting,
|
|
134
156
|
surfaceDecisionsEnabled: this._surfaceDecisions,
|
|
135
157
|
htmlTransformationEnabled: this._htmlTransformation,
|
|
158
|
+
mosAuthenticatedApiRoutes: [
|
|
159
|
+
...this._additionalAuthenticatedApiRoutes,
|
|
160
|
+
{
|
|
161
|
+
matchPath: '/mos-api/offer-redemptions',
|
|
162
|
+
method: 'POST',
|
|
163
|
+
mosPath: '/api/v1/offer-redemptions',
|
|
164
|
+
},
|
|
165
|
+
],
|
|
136
166
|
};
|
|
137
167
|
return new MOSProxy(opts);
|
|
138
168
|
}
|
|
@@ -1 +1 @@
|
|
|
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 { IdentityProvider } from './adapters/IdentityProvider'\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 _identityProvider: IdentityProvider | 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 /**\n * Override identity provision for the surface-decisions API. Provide `resolve` to control the\n * identity payload sent to the API (e.g. resolved from a request header instead of cookies),\n * and/or `persist` to control how identity is recorded back on the response (e.g. suppress the\n * default anonymous-session cookie or write it elsewhere). Either method is optional; omitted\n * methods fall back to the built-in defaults.\n */\n withIdentityProvider(provider: IdentityProvider): this {\n this._identityProvider = 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 identityProvider: this._identityProvider,\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
|
+
{"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 { IdentityProvider } from './adapters/IdentityProvider'\nimport type { ResourceProvider } from './adapters/ResourceProvider'\nimport type { MOSProxyLogger } from './logger'\nimport { MOSProxy, type MOSProxyHtmlPipelineErrorHandler, type MOSProxyOptions } from './MOSProxy'\nimport type { MOSConfigInput, MosAuthenticatedApiRoute } 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 _identityProvider: IdentityProvider | null = null\n private _resourceProvider: ResourceProvider | 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 private _additionalAuthenticatedApiRoutes: MosAuthenticatedApiRoute[] = []\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 /**\n * Override identity provision for the surface-decisions API. Provide `resolve` to control the\n * identity payload sent to the API (e.g. resolved from a request header instead of cookies),\n * and/or `persist` to control how identity is recorded back on the response (e.g. suppress the\n * default anonymous-session cookie or write it elsewhere). Either method is optional; omitted\n * methods fall back to the built-in defaults.\n */\n withIdentityProvider(provider: IdentityProvider): this {\n this._identityProvider = provider\n return this\n }\n\n /**\n * Override the resource object sent to the surface-decisions API per request. `build` receives\n * only the `Request`; the proxy derives defaults (`{ id: pathname, meta: pageMetadata }`) and\n * shallow-merges your returned record over them. Return only the keys you want to add or\n * override (e.g. a content tier or canonical id) — `id`/`meta` are preserved unless you set them.\n */\n withResourceProvider(provider: ResourceProvider): this {\n this._resourceProvider = 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 /**\n * Add an additional route which, when matched by an incoming request, will be forwarded to the MonetizationOS API\n * with authentication handled by the configured identity provider.\n * This is in addition to the default `/mos-api/offer-redemptions` route.\n */\n withMosAuthenticatedApiRoutes(...routes: MosAuthenticatedApiRoute[]): this {\n this._additionalAuthenticatedApiRoutes.push(...routes)\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 identityProvider: this._identityProvider,\n resourceProvider: this._resourceProvider,\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 mosAuthenticatedApiRoutes: [\n ...this._additionalAuthenticatedApiRoutes,\n {\n matchPath: '/mos-api/offer-redemptions',\n method: 'POST',\n mosPath: '/api/v1/offer-redemptions',\n },\n ],\n }\n return new MOSProxy(opts)\n }\n}\n"]}
|
|
@@ -21,7 +21,7 @@ export const buildIdentity = ({ anonymousIdentifier, userJwt, createAnonymousIde
|
|
|
21
21
|
return { createAnonymousIdentifier: true };
|
|
22
22
|
};
|
|
23
23
|
export const defaultResolveIdentity = (args) => buildIdentity({
|
|
24
|
-
...getExistingCookies(args.request, args.originResponse, args.config),
|
|
24
|
+
...(args.originResponse ? getExistingCookies(args.request, args.originResponse, args.config) : {}),
|
|
25
25
|
createAnonymousIdentifierFallback: args.config.createAnonymousIdentifierFallback,
|
|
26
26
|
});
|
|
27
27
|
export const defaultPersistIdentity = (args) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IdentityProvider.js","sourceRoot":"","sources":["../../src/adapters/IdentityProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAmC9C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAC9B,OAAgB,EAChB,cAAwB,EACxB,MAAiB,EACiC,EAAE;IACpD,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAA;IAChG,MAAM,qBAAqB,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,0BAA0B,CAAC,CAAA;IAClG,MAAM,mBAAmB,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,8BAA8B,CAAC,CAAA;IACpG,IAAI,qBAAqB,IAAI,mBAAmB,EAAE,CAAC;QAC/C,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAA;IACrG,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAC1D,MAAM,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAA;IACtE,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,8BAA8B,CAAC,CAAA;IAC9D,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,CAAA;AAC3C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,EAC1B,mBAAmB,EACnB,OAAO,EACP,iCAAiC,GAAG,KAAK,GAK5C,EAAY,EAAE;IACX,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,iCAAiC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,iCAAiC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAA;IACjH,CAAC;IAED,IAAI,mBAAmB,EAAE,CAAC;QACtB,OAAO,EAAE,mBAAmB,EAAE,CAAA;IAClC,CAAC;IAED,OAAO,EAAE,yBAAyB,EAAE,IAAI,EAAE,CAAA;AAC9C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,IAAyB,EAAY,EAAE,CAC1E,aAAa,CAAC;IACV,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"IdentityProvider.js","sourceRoot":"","sources":["../../src/adapters/IdentityProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAmC9C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAC9B,OAAgB,EAChB,cAAwB,EACxB,MAAiB,EACiC,EAAE;IACpD,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAA;IAChG,MAAM,qBAAqB,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,0BAA0B,CAAC,CAAA;IAClG,MAAM,mBAAmB,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,8BAA8B,CAAC,CAAA;IACpG,IAAI,qBAAqB,IAAI,mBAAmB,EAAE,CAAC;QAC/C,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAA;IACrG,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAC1D,MAAM,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAA;IACtE,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,8BAA8B,CAAC,CAAA;IAC9D,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,CAAA;AAC3C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,EAC1B,mBAAmB,EACnB,OAAO,EACP,iCAAiC,GAAG,KAAK,GAK5C,EAAY,EAAE;IACX,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,iCAAiC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,iCAAiC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAA;IACjH,CAAC;IAED,IAAI,mBAAmB,EAAE,CAAC;QACtB,OAAO,EAAE,mBAAmB,EAAE,CAAA;IAClC,CAAC;IAED,OAAO,EAAE,yBAAyB,EAAE,IAAI,EAAE,CAAA;AAC9C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,IAAyB,EAAY,EAAE,CAC1E,aAAa,CAAC;IACV,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAClG,iCAAiC,EAAE,IAAI,CAAC,MAAM,CAAC,iCAAiC;CACnF,CAAC,CAAA;AAEN,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,IAAyB,EAAY,EAAE;IAC1E,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IAC/D,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,EAAE,UAAU,CAAA;IACjD,IAAI,CAAC,UAAU,EAAE,CAAC;QACd,OAAO,QAAQ,CAAA;IACnB,CAAC;IAED,MAAM,MAAM,GAAG,2BAA2B,IAAI,QAAQ,IAAI,QAAQ,CAAC,yBAAyB,KAAK,IAAI,CAAA;IACrG,yGAAyG;IACzG,uGAAuG;IACvG,MAAM,WAAW,GACb,mCAAmC,IAAI,QAAQ;QAC/C,QAAQ,CAAC,iCAAiC,KAAK,IAAI;QACnD,CAAC,SAAS,CAAC,QAAQ,EAAE,eAAe;QACpC,CAAC,kBAAkB,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,mBAAmB,CAAA;IAEtE,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1B,OAAO,QAAQ,CAAA;IACnB,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IAC7C,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,MAAM,CAAC,0BAA0B,IAAI,UAAU,UAAU,CAAC,CAAA;IAC1F,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE;QAC/B,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,OAAO;KACV,CAAC,CAAA;AACN,CAAC,CAAA","sourcesContent":["import { parse, parseSetCookie } from 'cookie'\nimport type { MOSConfig } from '../config'\nimport type { MOSProxyLogger } from '../logger'\nimport type { SurfaceDecisionResponse } from '../types'\n\nexport type Identity =\n | { createAnonymousIdentifier: true }\n | { userJwt: string; createAnonymousIdentifierFallback?: true }\n | { anonymousIdentifier: string }\n\nexport interface ResolveIdentityArgs {\n request: Request\n originResponse?: Response\n config: MOSConfig\n logger: MOSProxyLogger\n}\n\nexport interface PersistIdentityArgs {\n resolved: Identity\n decisions: SurfaceDecisionResponse\n response: Response\n request: Request\n config: MOSConfig\n logger: MOSProxyLogger\n}\n\n/**\n * Either method is optional; omitted methods use the built-in defaults. Both fail open: a throwing\n * `resolve` skips surface decisions; a throwing `persist` keeps the pre-persist response.\n */\nexport interface IdentityProvider {\n resolve?(args: ResolveIdentityArgs): Identity | Promise<Identity>\n persist?(args: PersistIdentityArgs): Response | Promise<Response>\n}\n\nexport const getExistingCookies = (\n request: Request,\n originResponse: Response,\n config: MOSConfig,\n): { anonymousIdentifier?: string; userJwt?: string } => {\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\nexport const buildIdentity = ({\n anonymousIdentifier,\n userJwt,\n createAnonymousIdentifierFallback = false,\n}: {\n anonymousIdentifier?: string\n userJwt?: string\n createAnonymousIdentifierFallback?: boolean\n}): Identity => {\n if (userJwt) {\n return createAnonymousIdentifierFallback ? { userJwt, createAnonymousIdentifierFallback: true } : { userJwt }\n }\n\n if (anonymousIdentifier) {\n return { anonymousIdentifier }\n }\n\n return { createAnonymousIdentifier: true }\n}\n\nexport const defaultResolveIdentity = (args: ResolveIdentityArgs): Identity =>\n buildIdentity({\n ...(args.originResponse ? getExistingCookies(args.request, args.originResponse, args.config) : {}),\n createAnonymousIdentifierFallback: args.config.createAnonymousIdentifierFallback,\n })\n\nexport const defaultPersistIdentity = (args: PersistIdentityArgs): Response => {\n const { resolved, decisions, response, request, config } = args\n const identifier = decisions.identity?.identifier\n if (!identifier) {\n return response\n }\n\n const minted = 'createAnonymousIdentifier' in resolved && resolved.createAnonymousIdentifier === true\n // A JWT resolved with the fallback flag mints a fresh anonymous identifier only when the API reports the\n // JWT as unauthenticated, and only when the request did not already carry an anonymous session cookie.\n const jwtFallback =\n 'createAnonymousIdentifierFallback' in resolved &&\n resolved.createAnonymousIdentifierFallback === true &&\n !decisions.identity?.isAuthenticated &&\n !getExistingCookies(request, response, config).anonymousIdentifier\n\n if (!minted && !jwtFallback) {\n return response\n }\n\n const headers = new Headers(response.headers)\n headers.append('Set-Cookie', `${config.anonymousSessionCookieName}=${identifier}; Path=/`)\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n })\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PageMetadata } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* The resource the surface-decisions request is being made for. `id` defaults to the request
|
|
4
|
+
* pathname and `meta` to the HTML-parsed page metadata; additional keys are passed through to the
|
|
5
|
+
* MOS API untouched.
|
|
6
|
+
*/
|
|
7
|
+
export type Resource = {
|
|
8
|
+
id: string;
|
|
9
|
+
meta?: PageMetadata;
|
|
10
|
+
} & Record<string, unknown>;
|
|
11
|
+
/**
|
|
12
|
+
* Supplies extra per-request fields for the resource object sent to the surface-decisions API. The
|
|
13
|
+
* returned record is merged over the proxy's derived defaults (`{ id: pathname, meta: pageMetadata }`),
|
|
14
|
+
* so return only the keys you want to add or override — `id`/`meta` are preserved unless you set them:
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* const resourceProvider: ResourceProvider = {
|
|
18
|
+
* build: (request) => ({ tier: tierFromRequest(request) }),
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Merging is shallow, matching `ClientMetadataProvider`.
|
|
23
|
+
*/
|
|
24
|
+
export interface ResourceProvider {
|
|
25
|
+
build(request: Request): Partial<Resource> & Record<string, unknown>;
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResourceProvider.js","sourceRoot":"","sources":["../../src/adapters/ResourceProvider.ts"],"names":[],"mappings":"","sourcesContent":["import type { PageMetadata } from '../types'\n\n/**\n * The resource the surface-decisions request is being made for. `id` defaults to the request\n * pathname and `meta` to the HTML-parsed page metadata; additional keys are passed through to the\n * MOS API untouched.\n */\nexport type Resource = {\n id: string\n meta?: PageMetadata\n} & Record<string, unknown>\n\n/**\n * Supplies extra per-request fields for the resource object sent to the surface-decisions API. The\n * returned record is merged over the proxy's derived defaults (`{ id: pathname, meta: pageMetadata }`),\n * so return only the keys you want to add or override — `id`/`meta` are preserved unless you set them:\n *\n * ```ts\n * const resourceProvider: ResourceProvider = {\n * build: (request) => ({ tier: tierFromRequest(request) }),\n * }\n * ```\n *\n * Merging is shallow, matching `ClientMetadataProvider`.\n */\nexport interface ResourceProvider {\n build(request: Request): Partial<Resource> & Record<string, unknown>\n}\n"]}
|
package/dist/adapters/index.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export type { Fetcher } from './Fetcher';
|
|
|
3
3
|
export type { ContentOptions, ElementHandlers, HtmlRewriterAdapter, HtmlRewriterCapabilities, HtmlRewriterSession, RewriterElement, RewriterText, } from './HtmlRewriterAdapter';
|
|
4
4
|
export type { Identity, IdentityProvider, PersistIdentityArgs, ResolveIdentityArgs } from './IdentityProvider';
|
|
5
5
|
export { buildIdentity, defaultPersistIdentity, defaultResolveIdentity, getExistingCookies, } from './IdentityProvider';
|
|
6
|
+
export type { Resource, ResourceProvider } from './ResourceProvider';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAYA,OAAO,EACH,aAAa,EACb,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,GACrB,MAAM,oBAAoB,CAAA","sourcesContent":["export type { ClientMetadataProvider } from './ClientMetadataProvider'\nexport type { Fetcher } from './Fetcher'\nexport type {\n ContentOptions,\n ElementHandlers,\n HtmlRewriterAdapter,\n HtmlRewriterCapabilities,\n HtmlRewriterSession,\n RewriterElement,\n RewriterText,\n} from './HtmlRewriterAdapter'\nexport type { Identity, IdentityProvider, PersistIdentityArgs, ResolveIdentityArgs } from './IdentityProvider'\nexport {\n buildIdentity,\n defaultPersistIdentity,\n defaultResolveIdentity,\n getExistingCookies,\n} from './IdentityProvider'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAYA,OAAO,EACH,aAAa,EACb,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,GACrB,MAAM,oBAAoB,CAAA","sourcesContent":["export type { ClientMetadataProvider } from './ClientMetadataProvider'\nexport type { Fetcher } from './Fetcher'\nexport type {\n ContentOptions,\n ElementHandlers,\n HtmlRewriterAdapter,\n HtmlRewriterCapabilities,\n HtmlRewriterSession,\n RewriterElement,\n RewriterText,\n} from './HtmlRewriterAdapter'\nexport type { Identity, IdentityProvider, PersistIdentityArgs, ResolveIdentityArgs } from './IdentityProvider'\nexport {\n buildIdentity,\n defaultPersistIdentity,\n defaultResolveIdentity,\n getExistingCookies,\n} from './IdentityProvider'\nexport type { Resource, ResourceProvider } from './ResourceProvider'\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.
|
|
3
|
+
export declare const MOS_PROXY_PACKAGE_VERSION = "1.4.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.
|
|
4
|
+
export const MOS_PROXY_PACKAGE_VERSION = '1.4.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.
|
|
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.4.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/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { ClientMetadataProvider, ContentOptions, ElementHandlers, Fetcher, HtmlRewriterAdapter, HtmlRewriterCapabilities, HtmlRewriterSession, Identity, IdentityProvider, PersistIdentityArgs, ResolveIdentityArgs, RewriterElement, RewriterText, } from './adapters';
|
|
1
|
+
export type { ClientMetadataProvider, ContentOptions, ElementHandlers, Fetcher, HtmlRewriterAdapter, HtmlRewriterCapabilities, HtmlRewriterSession, Identity, IdentityProvider, PersistIdentityArgs, ResolveIdentityArgs, Resource, ResourceProvider, RewriterElement, RewriterText, } from './adapters';
|
|
2
2
|
export { buildIdentity, defaultPersistIdentity, defaultResolveIdentity, getExistingCookies, } from './adapters';
|
|
3
3
|
export type { MOSConfig } from './config';
|
|
4
4
|
export type { MOSProxyLogCode, MOSProxyLogEvent, MOSProxyLogger, MOSProxyLogLevel } from './logger';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,OAAO,EACH,aAAa,EACb,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,GACrB,MAAM,YAAY,CAAA;AAGnB,OAAO,EACH,QAAQ,GAKX,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA","sourcesContent":["export type {\n ClientMetadataProvider,\n ContentOptions,\n ElementHandlers,\n Fetcher,\n HtmlRewriterAdapter,\n HtmlRewriterCapabilities,\n HtmlRewriterSession,\n Identity,\n IdentityProvider,\n PersistIdentityArgs,\n ResolveIdentityArgs,\n Resource,\n ResourceProvider,\n RewriterElement,\n RewriterText,\n} from './adapters'\nexport {\n buildIdentity,\n defaultPersistIdentity,\n defaultResolveIdentity,\n getExistingCookies,\n} from './adapters'\nexport type { MOSConfig } from './config'\nexport type { MOSProxyLogCode, MOSProxyLogEvent, MOSProxyLogger, MOSProxyLogLevel } from './logger'\nexport {\n MOSProxy,\n type MOSProxyHtmlPipelineErrorContext,\n type MOSProxyHtmlPipelineErrorHandler,\n type MOSProxyHtmlPipelineStage,\n type MOSProxyOptions,\n} from './MOSProxy'\nexport { MOSProxyBuilder } from './MOSProxyBuilder'\nexport type {\n Feature,\n FeatureMeterableProperty,\n FeatureNumberProperty,\n MOSConfigInput,\n ModifyHttpResponse,\n PageMetadata,\n SetHttpResponse,\n SubSurfaceBehaviorApi,\n SubSurfaceMetadataApi,\n SurfaceBehaviorApi,\n SurfaceDecisionError,\n SurfaceDecisionResponse,\n WebComponentElement,\n WebComponentRangeReplacement,\n WebContentSurfaceBehavior,\n WebElement,\n} from './types'\n"]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { Fetcher } from '../adapters/Fetcher';
|
|
2
2
|
import type { Identity } from '../adapters/IdentityProvider';
|
|
3
|
+
import type { Resource } from '../adapters/ResourceProvider';
|
|
3
4
|
import type { PipelineContext } from '../context';
|
|
4
|
-
import type {
|
|
5
|
+
import type { SurfaceDecisionResponse } from '../types';
|
|
5
6
|
export type FetchSurfaceDecisionsArgs = {
|
|
6
7
|
identity: Identity;
|
|
7
|
-
path: string;
|
|
8
8
|
url: string;
|
|
9
9
|
clientMetadata: Record<string, unknown>;
|
|
10
|
-
|
|
10
|
+
resource: Resource;
|
|
11
11
|
userAgent?: string | undefined;
|
|
12
12
|
originStatus: number;
|
|
13
13
|
};
|
|
@@ -22,4 +22,4 @@ export type FetchSurfaceDecisionsResult = {
|
|
|
22
22
|
status?: number;
|
|
23
23
|
statusCode?: number;
|
|
24
24
|
};
|
|
25
|
-
export default function fetchSurfaceDecisions(ctx: PipelineContext, { identity,
|
|
25
|
+
export default function fetchSurfaceDecisions(ctx: PipelineContext, { identity, url, clientMetadata, resource, userAgent, originStatus }: FetchSurfaceDecisionsArgs, apiFetcher: Fetcher): Promise<FetchSurfaceDecisionsResult>;
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { withMosProxyHeaders } from '../apiRequestHeaders';
|
|
2
|
-
export default async function fetchSurfaceDecisions(ctx, { identity,
|
|
2
|
+
export default async function fetchSurfaceDecisions(ctx, { identity, url, clientMetadata, resource, userAgent, originStatus }, apiFetcher) {
|
|
3
3
|
const { config } = ctx;
|
|
4
4
|
const body = JSON.stringify({
|
|
5
5
|
...clientMetadata,
|
|
6
6
|
surfaceSlug: config.surfaceSlug,
|
|
7
7
|
identity,
|
|
8
|
-
resource
|
|
9
|
-
id: path,
|
|
10
|
-
meta: pageMetadata,
|
|
11
|
-
},
|
|
8
|
+
resource,
|
|
12
9
|
http: {
|
|
13
10
|
url,
|
|
14
11
|
userAgent,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchSurfaceDecisions.js","sourceRoot":"","sources":["../../src/stages/fetchSurfaceDecisions.ts"],"names":[],"mappings":"
|
|
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 type { Identity } from '../adapters/IdentityProvider'\nimport type { Resource } from '../adapters/ResourceProvider'\nimport { withMosProxyHeaders } from '../apiRequestHeaders'\nimport type { PipelineContext } from '../context'\nimport type { SurfaceDecisionError, SurfaceDecisionResponse } from '../types'\n\nexport type FetchSurfaceDecisionsArgs = {\n identity: Identity\n url: string\n clientMetadata: Record<string, unknown>\n resource: Resource\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 { identity, url, clientMetadata, resource, 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,\n resource,\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 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"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ClientMetadataProvider, type Fetcher, type IdentityProvider } from '../adapters';
|
|
2
|
+
import type { PipelineContext } from '../context';
|
|
3
|
+
import type { MosAuthenticatedApiRoute } from '../types';
|
|
4
|
+
export declare const handleMosAuthenticatedApiRoutes: (request: Request, routes: MosAuthenticatedApiRoute[], ctx: PipelineContext, identityProvider: IdentityProvider | null, clientMetadataProvider: ClientMetadataProvider | null, apiFetcher: Fetcher | null) => Promise<Response | null>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { defaultResolveIdentity } from '../adapters';
|
|
2
|
+
import { withMosProxyHeaders } from '../apiRequestHeaders';
|
|
3
|
+
export const handleMosAuthenticatedApiRoutes = async (request, routes, ctx, identityProvider, clientMetadataProvider, apiFetcher) => {
|
|
4
|
+
if (!routes?.length) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
const url = new URL(request.url);
|
|
8
|
+
for (const route of routes) {
|
|
9
|
+
if (url.pathname === route.matchPath && request.method.toUpperCase() === route.method) {
|
|
10
|
+
return handleMosAuthenticatedApiRoute(request, route, ctx, identityProvider, clientMetadataProvider, apiFetcher);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
};
|
|
15
|
+
const handleMosAuthenticatedApiRoute = async (request, route, ctx, identityProvider, clientMetadataProvider, apiFetcher) => {
|
|
16
|
+
if (!apiFetcher) {
|
|
17
|
+
throw new Error('MOSProxy: mosAuthenticatedApiRoutes are configured but no API fetcher is configured');
|
|
18
|
+
}
|
|
19
|
+
const { config, logger } = ctx;
|
|
20
|
+
const requestBody = await request.json();
|
|
21
|
+
const identity = await (identityProvider?.resolve ?? defaultResolveIdentity)({ request, config, logger });
|
|
22
|
+
return await apiFetcher(new Request(new URL(route.mosPath, config.mosHost), {
|
|
23
|
+
method: route.method,
|
|
24
|
+
body: JSON.stringify({
|
|
25
|
+
...requestBody,
|
|
26
|
+
...(clientMetadataProvider?.build(request) ?? {}),
|
|
27
|
+
identity,
|
|
28
|
+
http: { url: request.url, userAgent: request.headers.get('User-Agent') ?? undefined },
|
|
29
|
+
}),
|
|
30
|
+
headers: withMosProxyHeaders({
|
|
31
|
+
'Content-Type': 'application/json',
|
|
32
|
+
Authorization: `Bearer ${config.mosSecretKey}`,
|
|
33
|
+
}),
|
|
34
|
+
}));
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=mosAuthenticatedApi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mosAuthenticatedApi.js","sourceRoot":"","sources":["../../src/stages/mosAuthenticatedApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,sBAAsB,EAAuC,MAAM,aAAa,CAAA;AACtH,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAI1D,MAAM,CAAC,MAAM,+BAA+B,GAAG,KAAK,EAChD,OAAgB,EAChB,MAAkC,EAClC,GAAoB,EACpB,gBAAyC,EACzC,sBAAqD,EACrD,UAA0B,EACF,EAAE;IAC1B,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAClB,OAAO,IAAI,CAAA;IACf,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAChC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QACzB,IAAI,GAAG,CAAC,QAAQ,KAAK,KAAK,CAAC,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;YACpF,OAAO,8BAA8B,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,UAAU,CAAC,CAAA;QACpH,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAA;AACf,CAAC,CAAA;AAED,MAAM,8BAA8B,GAAG,KAAK,EACxC,OAAgB,EAChB,KAA+B,EAC/B,GAAoB,EACpB,gBAAyC,EACzC,sBAAqD,EACrD,UAA0B,EACF,EAAE;IAC1B,IAAI,CAAC,UAAU,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,qFAAqF,CAAC,CAAA;IAC1G,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAA;IAC9B,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAA;IACxC,MAAM,QAAQ,GAAG,MAAM,CAAC,gBAAgB,EAAE,OAAO,IAAI,sBAAsB,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IAEzG,OAAO,MAAM,UAAU,CACnB,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE;QAChD,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACjB,GAAG,WAAW;YACd,GAAG,CAAC,sBAAsB,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YACjD,QAAQ;YACR,IAAI,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,SAAS,EAAE;SACxF,CAAC;QACF,OAAO,EAAE,mBAAmB,CAAC;YACzB,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,MAAM,CAAC,YAAY,EAAE;SACjD,CAAC;KACL,CAAC,CACL,CAAA;AACL,CAAC,CAAA","sourcesContent":["import { type ClientMetadataProvider, defaultResolveIdentity, type Fetcher, type IdentityProvider } from '../adapters'\nimport { withMosProxyHeaders } from '../apiRequestHeaders'\nimport type { PipelineContext } from '../context'\nimport type { MosAuthenticatedApiRoute } from '../types'\n\nexport const handleMosAuthenticatedApiRoutes = async (\n request: Request,\n routes: MosAuthenticatedApiRoute[],\n ctx: PipelineContext,\n identityProvider: IdentityProvider | null,\n clientMetadataProvider: ClientMetadataProvider | null,\n apiFetcher: Fetcher | null,\n): Promise<Response | null> => {\n if (!routes?.length) {\n return null\n }\n\n const url = new URL(request.url)\n for (const route of routes) {\n if (url.pathname === route.matchPath && request.method.toUpperCase() === route.method) {\n return handleMosAuthenticatedApiRoute(request, route, ctx, identityProvider, clientMetadataProvider, apiFetcher)\n }\n }\n\n return null\n}\n\nconst handleMosAuthenticatedApiRoute = async (\n request: Request,\n route: MosAuthenticatedApiRoute,\n ctx: PipelineContext,\n identityProvider: IdentityProvider | null,\n clientMetadataProvider: ClientMetadataProvider | null,\n apiFetcher: Fetcher | null,\n): Promise<Response | null> => {\n if (!apiFetcher) {\n throw new Error('MOSProxy: mosAuthenticatedApiRoutes are configured but no API fetcher is configured')\n }\n\n const { config, logger } = ctx\n const requestBody = await request.json()\n const identity = await (identityProvider?.resolve ?? defaultResolveIdentity)({ request, config, logger })\n\n return await apiFetcher(\n new Request(new URL(route.mosPath, config.mosHost), {\n method: route.method,\n body: JSON.stringify({\n ...requestBody,\n ...(clientMetadataProvider?.build(request) ?? {}),\n identity,\n http: { url: request.url, userAgent: request.headers.get('User-Agent') ?? undefined },\n }),\n headers: withMosProxyHeaders({\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.mosSecretKey}`,\n }),\n }),\n )\n}\n"]}
|
|
@@ -2,6 +2,7 @@ import type { ClientMetadataProvider } from '../adapters/ClientMetadataProvider'
|
|
|
2
2
|
import type { Fetcher } from '../adapters/Fetcher';
|
|
3
3
|
import type { HtmlRewriterAdapter } from '../adapters/HtmlRewriterAdapter';
|
|
4
4
|
import { type IdentityProvider } from '../adapters/IdentityProvider';
|
|
5
|
+
import type { ResourceProvider } from '../adapters/ResourceProvider';
|
|
5
6
|
import type { PipelineContext } from '../context';
|
|
6
7
|
import type { SurfaceDecisionResponse } from '../types';
|
|
7
|
-
export default function getSurfaceDecisions(ctx: PipelineContext, request: Request, response: Response, apiFetcher: Fetcher, rewriter: HtmlRewriterAdapter | null, clientMetadataProvider: ClientMetadataProvider | null, identityProvider: IdentityProvider | null): Promise<[Response, SurfaceDecisionResponse | null]>;
|
|
8
|
+
export default function getSurfaceDecisions(ctx: PipelineContext, request: Request, response: Response, apiFetcher: Fetcher, rewriter: HtmlRewriterAdapter | null, clientMetadataProvider: ClientMetadataProvider | null, identityProvider: IdentityProvider | null, resourceProvider: ResourceProvider | null): Promise<[Response, SurfaceDecisionResponse | null]>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defaultPersistIdentity, defaultResolveIdentity } from '../adapters/IdentityProvider';
|
|
2
2
|
import fetchSurfaceDecisions from './fetchSurfaceDecisions';
|
|
3
3
|
import { parsePageMetadata } from './pageMetadata';
|
|
4
|
-
export default async function getSurfaceDecisions(ctx, request, response, apiFetcher, rewriter, clientMetadataProvider, identityProvider) {
|
|
4
|
+
export default async function getSurfaceDecisions(ctx, request, response, apiFetcher, rewriter, clientMetadataProvider, identityProvider, resourceProvider) {
|
|
5
5
|
const { config, logger } = ctx;
|
|
6
6
|
const resolve = identityProvider?.resolve ?? defaultResolveIdentity;
|
|
7
7
|
let identity;
|
|
@@ -21,12 +21,12 @@ export default async function getSurfaceDecisions(ctx, request, response, apiFet
|
|
|
21
21
|
const pageMetadata = metadataStream && rewriter ? await parsePageMetadata(ctx, new Response(metadataStream, response), rewriter) : {};
|
|
22
22
|
let modifiedResponse = passThroughStream ? new Response(passThroughStream, response) : response;
|
|
23
23
|
const clientMetadata = clientMetadataProvider?.build(request) ?? {};
|
|
24
|
+
const resource = { id: new URL(request.url).pathname, meta: pageMetadata, ...resourceProvider?.build(request) };
|
|
24
25
|
const result = await fetchSurfaceDecisions(ctx, {
|
|
25
26
|
identity,
|
|
26
|
-
path: new URL(request.url).pathname,
|
|
27
27
|
url: request.url,
|
|
28
28
|
clientMetadata,
|
|
29
|
-
|
|
29
|
+
resource,
|
|
30
30
|
userAgent: request.headers.get('User-Agent') ?? undefined,
|
|
31
31
|
originStatus: response.status,
|
|
32
32
|
}, apiFetcher);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surfaceDecisions.js","sourceRoot":"","sources":["../../src/stages/surfaceDecisions.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAwC,MAAM,8BAA8B,CAAA;
|
|
1
|
+
{"version":3,"file":"surfaceDecisions.js","sourceRoot":"","sources":["../../src/stages/surfaceDecisions.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 { defaultPersistIdentity, defaultResolveIdentity, type Identity, type IdentityProvider } from '../adapters/IdentityProvider'\nimport type { ResourceProvider } from '../adapters/ResourceProvider'\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 identityProvider: IdentityProvider | null,\n resourceProvider: ResourceProvider | null,\n): Promise<[Response, SurfaceDecisionResponse | null]> {\n const { config, logger } = ctx\n\n const resolve = identityProvider?.resolve ?? defaultResolveIdentity\n let identity: Identity\n try {\n identity = await resolve({ request, originResponse: response, config, logger })\n } catch (error) {\n logger.log({\n level: 'warn',\n code: 'identity-resolve-failed',\n message: 'Identity provider resolve threw; skipping surface decisions and returning origin response.',\n error,\n })\n return [response, null]\n }\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 resource = { id: new URL(request.url).pathname, meta: pageMetadata, ...resourceProvider?.build(request) }\n\n const result = await fetchSurfaceDecisions(\n ctx,\n {\n identity,\n url: request.url,\n clientMetadata,\n resource,\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 const persist = identityProvider?.persist ?? defaultPersistIdentity\n try {\n modifiedResponse = await persist({\n resolved: identity,\n decisions: surfaceDecisions,\n response: modifiedResponse,\n request,\n config,\n logger,\n })\n } catch (error) {\n logger.log({\n level: 'warn',\n code: 'identity-persist-failed',\n message: 'Identity provider persist threw; keeping pre-persist response.',\n error,\n })\n }\n\n return [modifiedResponse, surfaceDecisions]\n}\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -92,6 +92,11 @@ export interface SurfaceDecisionError {
|
|
|
92
92
|
status: 'error';
|
|
93
93
|
statusCode: number;
|
|
94
94
|
}
|
|
95
|
+
export type MosAuthenticatedApiRoute = {
|
|
96
|
+
matchPath: string;
|
|
97
|
+
method: 'POST' | 'PUT' | 'PATCH';
|
|
98
|
+
mosPath: string;
|
|
99
|
+
};
|
|
95
100
|
export interface MOSConfigInput {
|
|
96
101
|
/** Origin website base URL, e.g. `https://news.example.com`. */
|
|
97
102
|
originUrl: string;
|
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 * 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"]}
|
|
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 type MosAuthenticatedApiRoute = {\n matchPath: string\n method: 'POST' | 'PUT' | 'PATCH'\n mosPath: string\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"]}
|