@prodix/sdk-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/dist/client.d.ts +34 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +84 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/serialize.d.ts +7 -0
- package/dist/serialize.d.ts.map +1 -0
- package/dist/serialize.js +99 -0
- package/dist/serialize.js.map +1 -0
- package/package.json +30 -0
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# @prodix/sdk-core
|
|
2
|
+
|
|
3
|
+
Core client for [Prodix](https://www.prodixsolutions.co) — AI-powered visual testing across real device profiles.
|
|
4
|
+
|
|
5
|
+
Most projects don't need this package directly — install a framework integration instead, such as [`@prodix/cypress`](https://www.npmjs.com/package/@prodix/cypress).
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { ProdixClient, serializeDom } from "@prodix/sdk-core";
|
|
11
|
+
|
|
12
|
+
const client = new ProdixClient({
|
|
13
|
+
apiKey: process.env.PRODIX_API_KEY,
|
|
14
|
+
projectId: process.env.PRODIX_PROJECT_ID,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
await client.snapshot({
|
|
18
|
+
name: "Homepage",
|
|
19
|
+
html: serializeDom(document),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
await client.completeRun();
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`serializeDom` captures the current page as self-contained HTML — including computed styles from CSS-in-JS, current form state, and canvas contents — so it can be re-rendered later across every device profile.
|
|
26
|
+
|
|
27
|
+
Get an API key from your project's Settings page in the [Prodix dashboard](https://app.prodixsolutions.co).
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type ProdixConfig = {
|
|
2
|
+
apiKey: string | undefined;
|
|
3
|
+
projectId: string | undefined;
|
|
4
|
+
apiUrl?: string;
|
|
5
|
+
branch?: string;
|
|
6
|
+
commit?: string;
|
|
7
|
+
};
|
|
8
|
+
export type ScreenSnapshot = {
|
|
9
|
+
name: string;
|
|
10
|
+
html: string;
|
|
11
|
+
width?: number | undefined;
|
|
12
|
+
height?: number | undefined;
|
|
13
|
+
};
|
|
14
|
+
export type RunStatus = "pending" | "processing" | "completed" | "failed";
|
|
15
|
+
export declare class ProdixApiError extends Error {
|
|
16
|
+
readonly status: number;
|
|
17
|
+
constructor(status: number, message: string);
|
|
18
|
+
}
|
|
19
|
+
export declare class ProdixClient {
|
|
20
|
+
#private;
|
|
21
|
+
constructor(config: ProdixConfig);
|
|
22
|
+
get projectId(): string;
|
|
23
|
+
/** Starts a run on first call; later calls return the same run ID. */
|
|
24
|
+
startRun(): Promise<string>;
|
|
25
|
+
snapshot(screen: ScreenSnapshot): Promise<{
|
|
26
|
+
screenId: string;
|
|
27
|
+
}>;
|
|
28
|
+
/** Submits the run for analysis. Returns null if no snapshot was taken. */
|
|
29
|
+
completeRun(): Promise<{
|
|
30
|
+
runId: string;
|
|
31
|
+
status: RunStatus;
|
|
32
|
+
} | null>;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;AAS1E,qBAAa,cAAe,SAAQ,KAAK;IAErC,QAAQ,CAAC,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM;CAKlB;AAED,qBAAa,YAAY;;gBAQX,MAAM,EAAE,YAAY;IAYhC,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,sEAAsE;IACtE,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAerB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAWrE,2EAA2E;IACrE,WAAW,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,CAAA;KAAE,GAAG,IAAI,CAAC;CAgC1E"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const DEFAULT_API_URL = "https://api.prodixsolutions.co";
|
|
2
|
+
const REQUEST_TIMEOUT_MS = 30_000;
|
|
3
|
+
function fromEnv(name) {
|
|
4
|
+
return globalThis.process?.env[name] || undefined;
|
|
5
|
+
}
|
|
6
|
+
export class ProdixApiError extends Error {
|
|
7
|
+
status;
|
|
8
|
+
constructor(status, message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.status = status;
|
|
11
|
+
this.name = "ProdixApiError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class ProdixClient {
|
|
15
|
+
#apiKey;
|
|
16
|
+
#projectId;
|
|
17
|
+
#apiUrl;
|
|
18
|
+
#branch;
|
|
19
|
+
#commit;
|
|
20
|
+
#run = null;
|
|
21
|
+
constructor(config) {
|
|
22
|
+
if (!config.apiKey)
|
|
23
|
+
throw new Error("Prodix: API key is missing. Set PRODIX_API_KEY.");
|
|
24
|
+
if (!config.projectId)
|
|
25
|
+
throw new Error("Prodix: project ID is missing. Set PRODIX_PROJECT_ID.");
|
|
26
|
+
this.#apiKey = config.apiKey;
|
|
27
|
+
this.#projectId = config.projectId;
|
|
28
|
+
this.#apiUrl = (config.apiUrl ?? DEFAULT_API_URL).replace(/\/+$/, "");
|
|
29
|
+
// GITHUB_HEAD_REF is the source branch on pull requests; GITHUB_REF_NAME would be "123/merge".
|
|
30
|
+
this.#branch = config.branch ?? fromEnv("GITHUB_HEAD_REF") ?? fromEnv("GITHUB_REF_NAME");
|
|
31
|
+
this.#commit = config.commit ?? fromEnv("GITHUB_SHA");
|
|
32
|
+
}
|
|
33
|
+
get projectId() {
|
|
34
|
+
return this.#projectId;
|
|
35
|
+
}
|
|
36
|
+
/** Starts a run on first call; later calls return the same run ID. */
|
|
37
|
+
startRun() {
|
|
38
|
+
this.#run ??= this.#request("POST", "/v1/runs", {
|
|
39
|
+
projectId: this.#projectId,
|
|
40
|
+
branch: this.#branch,
|
|
41
|
+
commit: this.#commit,
|
|
42
|
+
}).then((res) => res.runId, (err) => {
|
|
43
|
+
this.#run = null;
|
|
44
|
+
throw err;
|
|
45
|
+
});
|
|
46
|
+
return this.#run;
|
|
47
|
+
}
|
|
48
|
+
async snapshot(screen) {
|
|
49
|
+
const runId = await this.startRun();
|
|
50
|
+
return this.#request("POST", `/v1/runs/${runId}/screens`, {
|
|
51
|
+
name: screen.name,
|
|
52
|
+
htmlSnapshot: screen.html,
|
|
53
|
+
platform: "web",
|
|
54
|
+
width: screen.width,
|
|
55
|
+
height: screen.height,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/** Submits the run for analysis. Returns null if no snapshot was taken. */
|
|
59
|
+
async completeRun() {
|
|
60
|
+
if (!this.#run)
|
|
61
|
+
return null;
|
|
62
|
+
const runId = await this.#run;
|
|
63
|
+
const result = await this.#request("POST", `/v1/runs/${runId}/complete`);
|
|
64
|
+
this.#run = null;
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
async #request(method, path, body) {
|
|
68
|
+
const res = await fetch(`${this.#apiUrl}${path}`, {
|
|
69
|
+
method,
|
|
70
|
+
headers: {
|
|
71
|
+
Authorization: `Bearer ${this.#apiKey}`,
|
|
72
|
+
...(body === undefined ? {} : { "Content-Type": "application/json" }),
|
|
73
|
+
},
|
|
74
|
+
...(body === undefined ? {} : { body: JSON.stringify(body) }),
|
|
75
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
76
|
+
});
|
|
77
|
+
if (!res.ok) {
|
|
78
|
+
const error = (await res.json().catch(() => null));
|
|
79
|
+
throw new ProdixApiError(res.status, `Prodix API ${method} ${path} failed (${res.status}): ${error?.message ?? res.statusText}`);
|
|
80
|
+
}
|
|
81
|
+
return (await res.json());
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAiBA,MAAM,eAAe,GAAG,gCAAgC,CAAC;AACzD,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC,SAAS,OAAO,CAAC,IAAY;IAC3B,OAAO,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC;AACpD,CAAC;AAED,MAAM,OAAO,cAAe,SAAQ,KAAK;IAE5B;IADX,YACW,MAAc,EACvB,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHN,WAAM,GAAN,MAAM,CAAQ;QAIvB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,YAAY;IACd,OAAO,CAAS;IAChB,UAAU,CAAS;IACnB,OAAO,CAAS;IAChB,OAAO,CAAqB;IAC5B,OAAO,CAAqB;IACrC,IAAI,GAA2B,IAAI,CAAC;IAEpC,YAAY,MAAoB;QAC9B,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACvF,IAAI,CAAC,MAAM,CAAC,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAEhG,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,eAAe,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACtE,+FAA+F;QAC/F,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,iBAAiB,CAAC,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACzF,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;IACxD,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,sEAAsE;IACtE,QAAQ;QACN,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAoB,MAAM,EAAE,UAAU,EAAE;YACjE,SAAS,EAAE,IAAI,CAAC,UAAU;YAC1B,MAAM,EAAE,IAAI,CAAC,OAAO;YACpB,MAAM,EAAE,IAAI,CAAC,OAAO;SACrB,CAAC,CAAC,IAAI,CACL,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,EAClB,CAAC,GAAY,EAAE,EAAE;YACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,MAAM,GAAG,CAAC;QACZ,CAAC,CACF,CAAC;QACF,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,MAAsB;QACnC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAY,KAAK,UAAU,EAAE;YACxD,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,YAAY,EAAE,MAAM,CAAC,IAAI;YACzB,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB,CAAC,CAAC;IACL,CAAC;IAED,2EAA2E;IAC3E,KAAK,CAAC,WAAW;QACf,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QAC5B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAChC,MAAM,EACN,YAAY,KAAK,WAAW,CAC7B,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAI,MAAsB,EAAE,IAAY,EAAE,IAAc;QACpE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;YAChD,MAAM;YACN,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,EAAE;gBACvC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;aACtE;YACD,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7D,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,kBAAkB,CAAC;SAChD,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAgC,CAAC;YAClF,MAAM,IAAI,cAAc,CACtB,GAAG,CAAC,MAAM,EACV,cAAc,MAAM,IAAI,IAAI,YAAY,GAAG,CAAC,MAAM,MAAM,KAAK,EAAE,OAAO,IAAI,GAAG,CAAC,UAAU,EAAE,CAC3F,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAC;IACjC,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC3D,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Captures the current page as self-contained HTML the Prodix worker can re-render
|
|
3
|
+
* at other viewport sizes. Must stay free of outside references: Playwright runs it
|
|
4
|
+
* via `page.evaluate(serializeDom)`, which ships only the function's source.
|
|
5
|
+
*/
|
|
6
|
+
export declare function serializeDom(doc?: Document): string;
|
|
7
|
+
//# sourceMappingURL=serialize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,GAAE,QAAmB,GAAG,MAAM,CA0F7D"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Captures the current page as self-contained HTML the Prodix worker can re-render
|
|
3
|
+
* at other viewport sizes. Must stay free of outside references: Playwright runs it
|
|
4
|
+
* via `page.evaluate(serializeDom)`, which ships only the function's source.
|
|
5
|
+
*/
|
|
6
|
+
export function serializeDom(doc = document) {
|
|
7
|
+
const clone = doc.documentElement.cloneNode(true);
|
|
8
|
+
// Elements may belong to another window (Cypress runs the app in an iframe),
|
|
9
|
+
// so match on tagName rather than instanceof.
|
|
10
|
+
const pairs = (selector) => {
|
|
11
|
+
const live = doc.querySelectorAll(selector);
|
|
12
|
+
const cloned = clone.querySelectorAll(selector);
|
|
13
|
+
const out = [];
|
|
14
|
+
live.forEach((el, i) => {
|
|
15
|
+
const twin = cloned[i];
|
|
16
|
+
if (twin)
|
|
17
|
+
out.push([el, twin]);
|
|
18
|
+
});
|
|
19
|
+
return out;
|
|
20
|
+
};
|
|
21
|
+
// CSS-in-JS libraries (styled-components, emotion) insert rules through the CSSOM,
|
|
22
|
+
// leaving the <style> tag empty, so cloneNode alone would drop those styles.
|
|
23
|
+
for (const [live, twin] of pairs("style")) {
|
|
24
|
+
const rules = live.sheet?.cssRules;
|
|
25
|
+
if (!live.textContent?.trim() && rules?.length) {
|
|
26
|
+
twin.textContent = Array.from(rules, (rule) => rule.cssText).join("\n");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Current form state lives in properties, not attributes.
|
|
30
|
+
for (const [live, twin] of pairs("input, textarea, select")) {
|
|
31
|
+
if (live.tagName === "INPUT") {
|
|
32
|
+
const input = live;
|
|
33
|
+
if (input.type === "checkbox" || input.type === "radio") {
|
|
34
|
+
if (input.checked)
|
|
35
|
+
twin.setAttribute("checked", "");
|
|
36
|
+
else
|
|
37
|
+
twin.removeAttribute("checked");
|
|
38
|
+
}
|
|
39
|
+
else if (input.type !== "password" && input.type !== "file") {
|
|
40
|
+
twin.setAttribute("value", input.value);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else if (live.tagName === "TEXTAREA") {
|
|
44
|
+
twin.textContent = live.value;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const options = twin.options;
|
|
48
|
+
Array.from(live.options).forEach((option, i) => {
|
|
49
|
+
if (option.selected)
|
|
50
|
+
options[i]?.setAttribute("selected", "");
|
|
51
|
+
else
|
|
52
|
+
options[i]?.removeAttribute("selected");
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
for (const [live, twin] of pairs("canvas")) {
|
|
57
|
+
try {
|
|
58
|
+
const img = doc.createElement("img");
|
|
59
|
+
img.src = live.toDataURL();
|
|
60
|
+
for (const attr of ["class", "style", "width", "height"]) {
|
|
61
|
+
const value = live.getAttribute(attr);
|
|
62
|
+
if (value !== null)
|
|
63
|
+
img.setAttribute(attr, value);
|
|
64
|
+
}
|
|
65
|
+
twin.replaceWith(img);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Tainted canvas (cross-origin content) can't be read; leave it blank.
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// The live DOM already reflects what scripts did; re-running them would change it.
|
|
72
|
+
clone.querySelectorAll("script").forEach((el) => el.remove());
|
|
73
|
+
clone.querySelectorAll("*").forEach((el) => {
|
|
74
|
+
for (const { name } of Array.from(el.attributes)) {
|
|
75
|
+
if (name.startsWith("on"))
|
|
76
|
+
el.removeAttribute(name);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
let head = clone.querySelector("head");
|
|
80
|
+
if (!head) {
|
|
81
|
+
head = doc.createElement("head");
|
|
82
|
+
clone.prepend(head);
|
|
83
|
+
}
|
|
84
|
+
const adopted = doc.adoptedStyleSheets ?? [];
|
|
85
|
+
if (adopted.length > 0) {
|
|
86
|
+
const style = doc.createElement("style");
|
|
87
|
+
style.textContent = adopted
|
|
88
|
+
.flatMap((sheet) => Array.from(sheet.cssRules, (rule) => rule.cssText))
|
|
89
|
+
.join("\n");
|
|
90
|
+
head.append(style);
|
|
91
|
+
}
|
|
92
|
+
// Relative URLs (stylesheets, images, fonts) must keep pointing at the original site.
|
|
93
|
+
clone.querySelectorAll("base").forEach((el) => el.remove());
|
|
94
|
+
const base = doc.createElement("base");
|
|
95
|
+
base.setAttribute("href", doc.baseURI);
|
|
96
|
+
head.prepend(base);
|
|
97
|
+
return `${doc.doctype ? "<!DOCTYPE html>" : ""}${clone.outerHTML}`;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=serialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prodix/sdk-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core client for Prodix AI visual testing",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./serialize": {
|
|
12
|
+
"types": "./dist/serialize.d.ts",
|
|
13
|
+
"import": "./dist/serialize.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^22.15.3",
|
|
21
|
+
"typescript": "^5.8.3"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc -p tsconfig.json",
|
|
28
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
29
|
+
}
|
|
30
|
+
}
|