@solarisdk/browserbase-compat 0.2.0 → 0.3.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/CHANGELOG.md +14 -0
- package/COMPAT.md +31 -6
- package/README.md +3 -2
- package/dist/client.d.ts +69 -36
- package/dist/client.js +291 -143
- package/dist/errors.d.ts +4 -0
- package/dist/errors.js +6 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +2 -1
- package/dist/mapping.d.ts +5 -0
- package/dist/mapping.js +56 -4
- package/dist/options.d.ts +59 -0
- package/dist/options.js +112 -0
- package/dist/types.d.ts +12 -1
- package/dist/unsupported.d.ts +9 -0
- package/dist/unsupported.js +10 -0
- package/package.json +1 -1
package/dist/mapping.d.ts
CHANGED
|
@@ -7,6 +7,11 @@ export interface MappedCreate {
|
|
|
7
7
|
/** Soft differences the caller should know about (also emitted via the warn callback). */
|
|
8
8
|
warnings: string[];
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* The gateway does not return a session's keepAlive flag, so a keepAlive create also stores this reserved key in the session's
|
|
12
|
+
* user metadata, and `retrieve` / `list` read the flag back from it (and hide the key). The gateway allows 50 metadata keys.
|
|
13
|
+
*/
|
|
14
|
+
export declare const KEEP_ALIVE_KEY = "solari_compat_keep_alive";
|
|
10
15
|
/**
|
|
11
16
|
* Translate Browserbase `sessions.create` params into a Solari `POST /sessions` body.
|
|
12
17
|
* Hard gaps throw SolariCompatUnsupported. Soft gaps (a setting we cannot honour but whose absence does not change
|
package/dist/mapping.js
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
import { SolariCompatUnsupported } from "./errors.js";
|
|
2
2
|
const SOLARI_REGION_ALIASES = new Set(["us-west-2"]);
|
|
3
|
+
/**
|
|
4
|
+
* The gateway does not return a session's keepAlive flag, so a keepAlive create also stores this reserved key in the session's
|
|
5
|
+
* user metadata, and `retrieve` / `list` read the flag back from it (and hide the key). The gateway allows 50 metadata keys.
|
|
6
|
+
*/
|
|
7
|
+
export const KEEP_ALIVE_KEY = "solari_compat_keep_alive";
|
|
8
|
+
const METADATA_MAX_KEYS = 50;
|
|
9
|
+
const PARAM_KEYS = new Set(["browserSettings", "extensionId", "keepAlive", "projectId", "proxies", "proxySettings", "region", "api_timeout", "timeout", "userMetadata"]);
|
|
10
|
+
const SETTING_KEYS = new Set([
|
|
11
|
+
"advancedStealth", "allowedDomains", "blockAds", "captchaImageSelector", "captchaInputSelector", "context", "extensionId",
|
|
12
|
+
"ignoreCertificateErrors", "logSession", "os", "recordSession", "riskPolicyId", "solveCaptchas", "verified", "viewport",
|
|
13
|
+
]);
|
|
14
|
+
/** Raise for any key outside `known`: a dropped key is a silent failure (and for `allowedDomains`-like keys it would fail open). */
|
|
15
|
+
function onlyKeys(obj, known, where) {
|
|
16
|
+
if (obj === undefined || obj === null || typeof obj !== "object" || Array.isArray(obj))
|
|
17
|
+
return;
|
|
18
|
+
for (const k of Object.keys(obj)) {
|
|
19
|
+
if (!known.has(k))
|
|
20
|
+
throw new SolariCompatUnsupported(`${where}.${k}`, "this setting is not supported");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const CONTEXT_KEYS = new Set(["id", "persist"]);
|
|
24
|
+
const VIEWPORT_KEYS = new Set(["width", "height"]);
|
|
25
|
+
const PROXY_KEYS = new Set(["type", "domainPattern", "geolocation", "server", "username", "password"]);
|
|
26
|
+
const GEO_KEYS = new Set(["country", "state", "city"]);
|
|
3
27
|
function proxyBody(proxies, caCerts) {
|
|
4
28
|
if (caCerts && caCerts.length > 0) {
|
|
5
29
|
throw new SolariCompatUnsupported("proxySettings.caCertificates", "custom CA certificates are not supported");
|
|
@@ -14,6 +38,8 @@ function proxyBody(proxies, caCerts) {
|
|
|
14
38
|
throw new SolariCompatUnsupported("multiple proxies / domain routing rules", "pass at most one managed proxy; per-domain routing is not supported");
|
|
15
39
|
}
|
|
16
40
|
const p = proxies[0];
|
|
41
|
+
onlyKeys(p, PROXY_KEYS, "proxies[]");
|
|
42
|
+
onlyKeys(p.geolocation, GEO_KEYS, "proxies[].geolocation");
|
|
17
43
|
if (p.domainPattern !== undefined && p.domainPattern !== "") {
|
|
18
44
|
throw new SolariCompatUnsupported("proxies[].domainPattern", "per-domain proxy routing is not supported");
|
|
19
45
|
}
|
|
@@ -42,7 +68,12 @@ function proxyBody(proxies, caCerts) {
|
|
|
42
68
|
*/
|
|
43
69
|
export function mapCreateParams(params, strict) {
|
|
44
70
|
const p = params ?? {};
|
|
71
|
+
onlyKeys(p, PARAM_KEYS, "sessions.create");
|
|
45
72
|
const bs = p.browserSettings ?? {};
|
|
73
|
+
onlyKeys(bs, SETTING_KEYS, "browserSettings");
|
|
74
|
+
onlyKeys(bs.context, CONTEXT_KEYS, "browserSettings.context");
|
|
75
|
+
onlyKeys(bs.viewport, VIEWPORT_KEYS, "browserSettings.viewport");
|
|
76
|
+
onlyKeys(p.proxySettings, new Set(["caCertificates"]), "proxySettings");
|
|
46
77
|
const warnings = [];
|
|
47
78
|
const soft = (feature, why) => {
|
|
48
79
|
if (strict)
|
|
@@ -50,6 +81,8 @@ export function mapCreateParams(params, strict) {
|
|
|
50
81
|
warnings.push(`${feature}: ${why}`);
|
|
51
82
|
};
|
|
52
83
|
// ── hard gaps ────────────────────────────────────────────────────────────────
|
|
84
|
+
if (bs.riskPolicyId !== undefined)
|
|
85
|
+
throw new SolariCompatUnsupported("browserSettings.riskPolicyId", "risk policies are a Browserbase feature with no Solari equivalent");
|
|
53
86
|
if (p.extensionId || bs.extensionId)
|
|
54
87
|
throw new SolariCompatUnsupported("extensions", "browser extensions cannot be loaded");
|
|
55
88
|
if (bs.ignoreCertificateErrors === true)
|
|
@@ -88,12 +121,31 @@ export function mapCreateParams(params, strict) {
|
|
|
88
121
|
body.allowedDomains = allowedDomains;
|
|
89
122
|
if (bs.context?.id)
|
|
90
123
|
body.profileId = bs.context.id;
|
|
91
|
-
|
|
92
|
-
|
|
124
|
+
// Browserbase's name for the session timeout is `api_timeout`; `timeout` next to other params is the older spelling.
|
|
125
|
+
if (p.api_timeout !== undefined && p.timeout !== undefined && p.api_timeout !== p.timeout) {
|
|
126
|
+
throw new SolariCompatUnsupported("sessions.create timeout", "api_timeout and timeout are both the session timeout and differ; pass api_timeout only");
|
|
127
|
+
}
|
|
128
|
+
const sessionTimeout = p.api_timeout ?? p.timeout;
|
|
129
|
+
if (sessionTimeout !== undefined)
|
|
130
|
+
body.timeoutSeconds = sessionTimeout; // the gateway validates (>= 60) and clamps to the plan maximum
|
|
93
131
|
if (p.keepAlive === true)
|
|
94
132
|
body.keepAlive = true;
|
|
95
|
-
|
|
96
|
-
|
|
133
|
+
const um = p.userMetadata;
|
|
134
|
+
if (um !== undefined && (um === null || typeof um !== "object" || Array.isArray(um))) {
|
|
135
|
+
throw new SolariCompatUnsupported("userMetadata", "expected an object of key/value pairs");
|
|
136
|
+
}
|
|
137
|
+
if (um !== undefined && KEEP_ALIVE_KEY in um) {
|
|
138
|
+
throw new SolariCompatUnsupported(`userMetadata.${KEEP_ALIVE_KEY}`, "this key is reserved: it records keepAlive so retrieve and list can report it");
|
|
139
|
+
}
|
|
140
|
+
if (p.keepAlive === true) {
|
|
141
|
+
if (um !== undefined && Object.keys(um).length >= METADATA_MAX_KEYS) {
|
|
142
|
+
throw new SolariCompatUnsupported(`keepAlive with ${Object.keys(um).length} userMetadata keys`, `one of the ${METADATA_MAX_KEYS} metadata keys is reserved for keepAlive; pass at most ${METADATA_MAX_KEYS - 1}`);
|
|
143
|
+
}
|
|
144
|
+
body.userMetadata = { ...(um ?? {}), [KEEP_ALIVE_KEY]: true };
|
|
145
|
+
}
|
|
146
|
+
else if (um !== undefined) {
|
|
147
|
+
body.userMetadata = um;
|
|
148
|
+
}
|
|
97
149
|
return {
|
|
98
150
|
body,
|
|
99
151
|
...(bs.context?.id && bs.context.persist === true ? { persistProfileId: bs.context.id } : {}),
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-call options, as in Browserbase's SDK. `query`, `headers`, `timeout`, `maxRetries` and `signal` apply to every request a
|
|
3
|
+
* call makes; `body` and `idempotencyKey` only to calls that create something (`sessions.create`, `contexts.create`).
|
|
4
|
+
* The rest (`method`, `path`, `stream`, `httpAgent`, `defaultBaseURL`, `__binary*`) raise `SolariCompatUnsupported`.
|
|
5
|
+
*/
|
|
6
|
+
export interface RequestOptions {
|
|
7
|
+
query?: Record<string, unknown> | undefined;
|
|
8
|
+
body?: Record<string, unknown> | null | undefined;
|
|
9
|
+
headers?: Record<string, string | null | undefined> | undefined;
|
|
10
|
+
/** Retries for this call (overrides the client's). */
|
|
11
|
+
maxRetries?: number;
|
|
12
|
+
/** Request timeout in milliseconds (overrides the client's). Not the session timeout: that is `api_timeout` on `sessions.create`. */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
signal?: AbortSignal | undefined | null;
|
|
15
|
+
/** Only on create calls. */
|
|
16
|
+
idempotencyKey?: string;
|
|
17
|
+
/** Not supported: raises. */
|
|
18
|
+
method?: string;
|
|
19
|
+
path?: string;
|
|
20
|
+
defaultBaseURL?: string | undefined;
|
|
21
|
+
stream?: boolean | undefined;
|
|
22
|
+
httpAgent?: unknown;
|
|
23
|
+
__binaryRequest?: boolean | undefined;
|
|
24
|
+
__binaryResponse?: boolean | undefined;
|
|
25
|
+
}
|
|
26
|
+
/** Browserbase's heuristic: a non-empty object whose keys are all request options is the options argument, not the params. */
|
|
27
|
+
export declare function isRequestOptions(o: unknown): o is RequestOptions;
|
|
28
|
+
/** `fn(params?, options?)` and `fn(options?)`: which is which. */
|
|
29
|
+
export declare function splitArgs<P>(first: P | RequestOptions | undefined, second: RequestOptions | undefined): [P | undefined, RequestOptions | undefined];
|
|
30
|
+
/** What a call hands to the HTTP layer. */
|
|
31
|
+
export interface Call {
|
|
32
|
+
headers?: Record<string, string | null | undefined>;
|
|
33
|
+
query?: Record<string, unknown>;
|
|
34
|
+
body?: Record<string, unknown>;
|
|
35
|
+
timeout?: number;
|
|
36
|
+
maxRetries?: number;
|
|
37
|
+
signal?: AbortSignal | null;
|
|
38
|
+
idempotencyKey?: string;
|
|
39
|
+
}
|
|
40
|
+
/** Validate a call's options. Nothing is dropped: an option that cannot be honoured raises. */
|
|
41
|
+
export declare function resolveOptions(options: RequestOptions | undefined, allow: {
|
|
42
|
+
body?: boolean;
|
|
43
|
+
idempotencyKey?: boolean;
|
|
44
|
+
}, feature: string): Call;
|
|
45
|
+
/** A call's options for the follow-up requests of a multi-request call: no body, no idempotency key. */
|
|
46
|
+
export declare function followUp(call: Call): Call;
|
|
47
|
+
/** Headers the caller may not set: the key is the client's, not a header to override. */
|
|
48
|
+
export declare function assertHeaders(h: Record<string, string | null | undefined> | undefined, where: string): void;
|
|
49
|
+
export declare function setHeader(target: Record<string, string>, name: string, value: string | null | undefined): void;
|
|
50
|
+
/**
|
|
51
|
+
* What every method returns. Awaits like a Promise; `asResponse()` and `withResponse()` (Browserbase's APIPromise extras)
|
|
52
|
+
* raise `SolariCompatUnsupported`, because a call here can be several HTTP requests with no single response.
|
|
53
|
+
*/
|
|
54
|
+
export declare class CompatPromise<T> extends Promise<T> {
|
|
55
|
+
static get [Symbol.species](): PromiseConstructor;
|
|
56
|
+
asResponse(): never;
|
|
57
|
+
withResponse(): never;
|
|
58
|
+
}
|
|
59
|
+
export declare function compat<T>(fn: () => Promise<T>): CompatPromise<T>;
|
package/dist/options.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { SolariCompatUnsupported } from "./errors.js";
|
|
2
|
+
const REQUEST_OPTION_KEYS = new Set([
|
|
3
|
+
"method", "path", "query", "body", "headers", "defaultBaseURL", "maxRetries", "stream", "timeout", "httpAgent", "signal",
|
|
4
|
+
"idempotencyKey", "__binaryRequest", "__binaryResponse",
|
|
5
|
+
]);
|
|
6
|
+
const REFUSED = {
|
|
7
|
+
method: "the HTTP method is fixed by the call",
|
|
8
|
+
path: "the path is fixed by the call",
|
|
9
|
+
defaultBaseURL: "set baseURL on the client",
|
|
10
|
+
stream: "responses are not streamed",
|
|
11
|
+
httpAgent: "pass a fetch with your own dispatcher to the client instead",
|
|
12
|
+
__binaryRequest: "binary requests are not used",
|
|
13
|
+
__binaryResponse: "binary responses are not used",
|
|
14
|
+
};
|
|
15
|
+
/** Browserbase's heuristic: a non-empty object whose keys are all request options is the options argument, not the params. */
|
|
16
|
+
export function isRequestOptions(o) {
|
|
17
|
+
if (!o || typeof o !== "object" || Array.isArray(o))
|
|
18
|
+
return false;
|
|
19
|
+
const keys = Object.keys(o);
|
|
20
|
+
return keys.length > 0 && keys.every((k) => REQUEST_OPTION_KEYS.has(k));
|
|
21
|
+
}
|
|
22
|
+
/** `fn(params?, options?)` and `fn(options?)`: which is which. */
|
|
23
|
+
export function splitArgs(first, second) {
|
|
24
|
+
if (second === undefined && isRequestOptions(first))
|
|
25
|
+
return [undefined, first];
|
|
26
|
+
return [first, second];
|
|
27
|
+
}
|
|
28
|
+
/** Validate a call's options. Nothing is dropped: an option that cannot be honoured raises. */
|
|
29
|
+
export function resolveOptions(options, allow, feature) {
|
|
30
|
+
if (options === undefined || options === null)
|
|
31
|
+
return {};
|
|
32
|
+
if (typeof options !== "object" || Array.isArray(options))
|
|
33
|
+
throw new SolariCompatUnsupported(`${feature}: request options`, "expected an object");
|
|
34
|
+
for (const k of Object.keys(options)) {
|
|
35
|
+
if (options[k] === undefined)
|
|
36
|
+
continue;
|
|
37
|
+
if (k in REFUSED)
|
|
38
|
+
throw new SolariCompatUnsupported(`${feature}: request option ${k}`, REFUSED[k]);
|
|
39
|
+
if (!REQUEST_OPTION_KEYS.has(k))
|
|
40
|
+
throw new SolariCompatUnsupported(`${feature}: request option ${k}`, "not a request option");
|
|
41
|
+
}
|
|
42
|
+
if (options.body !== undefined && options.body !== null && !allow.body) {
|
|
43
|
+
throw new SolariCompatUnsupported(`${feature}: request option body`, "this call takes no extra body fields");
|
|
44
|
+
}
|
|
45
|
+
if (options.idempotencyKey !== undefined && !allow.idempotencyKey) {
|
|
46
|
+
throw new SolariCompatUnsupported(`${feature}: request option idempotencyKey`, "only create calls take an idempotency key");
|
|
47
|
+
}
|
|
48
|
+
if (options.body !== undefined && options.body !== null && (typeof options.body !== "object" || Array.isArray(options.body))) {
|
|
49
|
+
throw new SolariCompatUnsupported(`${feature}: request option body`, "expected an object");
|
|
50
|
+
}
|
|
51
|
+
if (options.timeout !== undefined && !(typeof options.timeout === "number" && options.timeout > 0)) {
|
|
52
|
+
throw new SolariCompatUnsupported(`${feature}: request option timeout`, "expected a positive number of milliseconds");
|
|
53
|
+
}
|
|
54
|
+
if (options.maxRetries !== undefined && !(Number.isInteger(options.maxRetries) && options.maxRetries >= 0)) {
|
|
55
|
+
throw new SolariCompatUnsupported(`${feature}: request option maxRetries`, "expected a non-negative integer");
|
|
56
|
+
}
|
|
57
|
+
assertHeaders(options.headers, `${feature}: request option headers`);
|
|
58
|
+
return {
|
|
59
|
+
...(options.headers ? { headers: options.headers } : {}),
|
|
60
|
+
...(options.query ? { query: options.query } : {}),
|
|
61
|
+
...(options.body ? { body: options.body } : {}),
|
|
62
|
+
...(options.timeout !== undefined ? { timeout: options.timeout } : {}),
|
|
63
|
+
...(options.maxRetries !== undefined ? { maxRetries: options.maxRetries } : {}),
|
|
64
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
65
|
+
...(options.idempotencyKey !== undefined ? { idempotencyKey: options.idempotencyKey } : {}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** A call's options for the follow-up requests of a multi-request call: no body, no idempotency key. */
|
|
69
|
+
export function followUp(call) {
|
|
70
|
+
const { body: _b, idempotencyKey: _i, ...rest } = call;
|
|
71
|
+
return rest;
|
|
72
|
+
}
|
|
73
|
+
const RESERVED_HEADERS = new Set(["authorization", "idempotency-key"]);
|
|
74
|
+
/** Headers the caller may not set: the key is the client's, not a header to override. */
|
|
75
|
+
export function assertHeaders(h, where) {
|
|
76
|
+
if (h === undefined)
|
|
77
|
+
return;
|
|
78
|
+
if (h === null || typeof h !== "object" || Array.isArray(h))
|
|
79
|
+
throw new SolariCompatUnsupported(where, "expected an object");
|
|
80
|
+
for (const k of Object.keys(h)) {
|
|
81
|
+
if (RESERVED_HEADERS.has(k.toLowerCase()))
|
|
82
|
+
throw new SolariCompatUnsupported(where, `${k} cannot be set: the client sets it`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export function setHeader(target, name, value) {
|
|
86
|
+
const lower = name.toLowerCase();
|
|
87
|
+
for (const k of Object.keys(target))
|
|
88
|
+
if (k.toLowerCase() === lower)
|
|
89
|
+
delete target[k];
|
|
90
|
+
if (value !== null && value !== undefined)
|
|
91
|
+
target[name] = value;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* What every method returns. Awaits like a Promise; `asResponse()` and `withResponse()` (Browserbase's APIPromise extras)
|
|
95
|
+
* raise `SolariCompatUnsupported`, because a call here can be several HTTP requests with no single response.
|
|
96
|
+
*/
|
|
97
|
+
export class CompatPromise extends Promise {
|
|
98
|
+
static get [Symbol.species]() {
|
|
99
|
+
return Promise;
|
|
100
|
+
}
|
|
101
|
+
asResponse() {
|
|
102
|
+
throw new SolariCompatUnsupported("asResponse()", "a call can make several requests; there is no single Response");
|
|
103
|
+
}
|
|
104
|
+
withResponse() {
|
|
105
|
+
throw new SolariCompatUnsupported("withResponse()", "a call can make several requests; there is no single Response");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export function compat(fn) {
|
|
109
|
+
return new CompatPromise((resolve, reject) => {
|
|
110
|
+
fn().then(resolve, reject);
|
|
111
|
+
});
|
|
112
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export interface BrowserSettings {
|
|
|
40
40
|
verified?: boolean;
|
|
41
41
|
captchaImageSelector?: string;
|
|
42
42
|
captchaInputSelector?: string;
|
|
43
|
+
/** Not supported: raises. */
|
|
44
|
+
riskPolicyId?: string;
|
|
43
45
|
os?: "windows" | "mac" | "linux" | "mobile" | "tablet";
|
|
44
46
|
allowedDomains?: string[];
|
|
45
47
|
ignoreCertificateErrors?: boolean;
|
|
@@ -48,6 +50,9 @@ export interface SessionCreateParams {
|
|
|
48
50
|
projectId?: string;
|
|
49
51
|
extensionId?: string;
|
|
50
52
|
browserSettings?: BrowserSettings;
|
|
53
|
+
/** The session timeout in seconds (Browserbase's name for it). */
|
|
54
|
+
api_timeout?: number;
|
|
55
|
+
/** @deprecated The older spelling of `api_timeout`, read only when passed next to other params. A lone `{ timeout }` is the request timeout, as in Browserbase's SDK. */
|
|
51
56
|
timeout?: number;
|
|
52
57
|
keepAlive?: boolean;
|
|
53
58
|
proxies?: boolean | ProxyConfig[];
|
|
@@ -107,7 +112,11 @@ export interface SessionLiveURLs {
|
|
|
107
112
|
export interface Context {
|
|
108
113
|
id: string;
|
|
109
114
|
name?: string;
|
|
110
|
-
createdAt
|
|
115
|
+
createdAt: string;
|
|
116
|
+
/** Solari does not track when a profile was last saved: the same as `createdAt`. */
|
|
117
|
+
updatedAt: string;
|
|
118
|
+
/** Always empty: Solari keys belong to an organisation, there are no projects. */
|
|
119
|
+
projectId: string;
|
|
111
120
|
}
|
|
112
121
|
export interface ContextCreateResponse {
|
|
113
122
|
id: string;
|
|
@@ -115,4 +124,6 @@ export interface ContextCreateResponse {
|
|
|
115
124
|
publicKey: string;
|
|
116
125
|
cipherAlgorithm: string;
|
|
117
126
|
initializationVectorSize: number;
|
|
127
|
+
/** Empty: contexts are saved by releasing a `persist: true` session, not by uploading. */
|
|
128
|
+
uploadUrl: string;
|
|
118
129
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** A resource whose methods all throw SolariCompatUnsupported (kept for the public type; see `unsupportedMethods`). */
|
|
2
|
+
export type UnsupportedResource = {
|
|
3
|
+
[method: string]: (...args: unknown[]) => never;
|
|
4
|
+
};
|
|
5
|
+
/** A resource with exactly these methods, each of which throws SolariCompatUnsupported naming `<feature>.<method>`. */
|
|
6
|
+
export type UnsupportedMethods<K extends string> = {
|
|
7
|
+
[P in K]: (...args: unknown[]) => never;
|
|
8
|
+
};
|
|
9
|
+
export declare function unsupportedMethods<const K extends string>(feature: string, hint: string, methods: readonly K[]): UnsupportedMethods<K>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SolariCompatUnsupported } from "./errors.js";
|
|
2
|
+
export function unsupportedMethods(feature, hint, methods) {
|
|
3
|
+
const out = {};
|
|
4
|
+
for (const m of methods) {
|
|
5
|
+
out[m] = () => {
|
|
6
|
+
throw new SolariCompatUnsupported(`${feature}.${m}`, hint);
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
return out;
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solarisdk/browserbase-compat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Drop-in Browserbase-style SDK surface for Solari Browser: sessions, connectUrl (CDP), contexts, live view, replay events.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|