Files
atlas-seller-kit/apps/extension/entrypoints/ozon-page-json.content.ts
2026-09-07 17:51:11 +08:00

106 lines
3.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Runs in Ozon's MAIN world so the request has exactly the same origin and
* session context as the page. It accepts only Atlas' two fixed, numeric-SKU
* routes and returns a small widget-state allowlist; it never exposes cookies,
* request headers or arbitrary fetch capability to the isolated script.
*/
export default defineContentScript({
matches: ['*://www.ozon.ru/*', '*://www.ozon.kz/*', '*://www.ozon.by/*'],
world: 'MAIN',
runAt: 'document_idle',
main() {
window.addEventListener('message', (event) => {
if (event.source !== window || !isRequest(event.data)) return;
void respond(event.data);
});
},
});
type Request = {
source: 'atlas-collector';
type: 'ozon-page-json.request';
requestId: string;
kind: 'modal-aspects' | 'product' | 'product-detail';
sku: string;
};
function isRequest(value: unknown): value is Request {
if (!value || typeof value !== 'object' || Array.isArray(value))
return false;
const data = value as Record<string, unknown>;
return (
data.source === 'atlas-collector' &&
data.type === 'ozon-page-json.request' &&
typeof data.requestId === 'string' &&
/^[a-zA-Z0-9-]{16,120}$/.test(data.requestId) &&
(data.kind === 'modal-aspects' ||
data.kind === 'product' ||
data.kind === 'product-detail') &&
typeof data.sku === 'string' &&
/^\d{4,}$/.test(data.sku)
);
}
async function respond(request: Request) {
try {
const pagePath =
request.kind === 'modal-aspects'
? `/modal/aspectsNew?product_id=${request.sku}`
: request.kind === 'product-detail'
? `/product/${request.sku}/?layout_container=pdpPage2column&layout_page_index=2`
: `/product/${request.sku}/`;
const response = await fetch(
`/api/entrypoint-api.bx/page/json/v2?url=${encodeURIComponent(pagePath)}`,
{ credentials: 'same-origin' },
);
if (!response.ok)
throw new Error(`Ozon 页面状态请求失败(HTTP ${response.status})`);
const value = await response.json();
window.postMessage(
{
source: 'atlas-collector',
type: 'ozon-page-json.response',
requestId: request.requestId,
ok: true,
data: allowlistedPageState(value),
},
location.origin,
);
} catch (error) {
window.postMessage(
{
source: 'atlas-collector',
type: 'ozon-page-json.response',
requestId: request.requestId,
ok: false,
error:
error instanceof Error
? error.message
: 'Ozon 页面状态请求失败',
},
location.origin,
);
}
}
function allowlistedPageState(value: unknown) {
if (!value || typeof value !== 'object' || Array.isArray(value))
return { widgetStates: {} };
const states = (value as { widgetStates?: unknown }).widgetStates;
if (!states || typeof states !== 'object' || Array.isArray(states))
return { widgetStates: {} };
const widgetStates: Record<string, unknown> = {};
for (const [name, state] of Object.entries(
states as Record<string, unknown>,
)) {
if (
/^web(Aspects|AspectsModal|ProductHeading|Price|Gallery|Description|RichContent|Features|ShortCharacteristics|DetailedCharacteristics|Characteristics)-/.test(
name,
)
) {
widgetStates[name] = state;
}
}
return { widgetStates };
}