14 スクリプトAPIの使用
14.1 目標
Sa2webページスクリプトと標準インターフェースインターセプションスクリプトで利用可能な window.api 機能を説明し、サイト設定、内部サイト設定、アカウント設定、プラグインスクリプトでのスクリプトをより確実に書けるようにする。
スクリプトAPIには5つの主要カテゴリがあります:
| API | 目的 |
|---|---|
api.config |
カスタム設定を読み取り;現在はコラボレーションリンク下でのみ有効 |
api.http |
ページCORS制限をバイパスしてHTTPリクエスト送信 |
api.user |
ユーザー、サイト、アカウント、デバイスでスコープされたデータの読み書き |
api.dom |
DOMクエリ、可視性チェック、要素変更リスニング、オーバーレイ作成 |
api.utils |
条件待機とページ内JavaScript実行 |
api.header() |
記録されたリクエストまたはレスポンスヘッダーを読み取り |
ページスクリプトと標準インターフェースインターセプションスクリプトは window.api を使用可能。SSEスクリプトは data が渡されることのみ保証され、通常 window.api に依存しない。
14.2 全体構造
スクリプト内では api を直接使用するか、window.api 経由でアクセス可能:
interface Window {
api: {
user: UserApi;
config: Record<string, unknown>;
http: HttpApi;
dom: DomApi;
utils: UtilsApi;
header(headerName: string, isRequestHeader: boolean): Promise<string | string[] | undefined>;
};
}例:
const apiBase = api.config.apiBase;
const userToken = await api.user.get('token');
const submit = api.dom.querySelector(document, 'button[type="submit"]');
const profile = await api.http.ajax({ url: `http://192.168.1.111:8080/profile` });スクリプトではSa2webの api.dom クエリツールを推奨。CSSセレクタとXPathセレクタの両方をサポートし、複雑なビジネスページでは document.querySelector() 単独より適している。
14.3 api.config
api.config はサイトスクリプト環境からカスタム設定を読み取ります。
config: Record<string, unknown>例:
const apiBase = api.config.apiBase;
const featureEnabled = api.config.featureEnabled === true;14.4 api.http
api.http はユーザースクリプト用のHTTPリクエストツールを提供。api.http.ajax はブラウザメインプロセスで実際のリクエストを実行するため、ページのCORSポリシーによる制限を受けません。
14.4.1 api.http.ajax(options)
HTTPリクエストを送信。
ajax(options: {
url: string;
method?: string;
data?: any;
headers?: Record<string, string>;
timeout?: number;
dataType?: 'json' | 'text' | 'html' | 'arrayBuffer';
contentType?: string;
processData?: boolean;
}): Promise<{
ok: boolean;
status: number;
statusText: string;
data?: any;
error?: string;
timeout?: boolean;
}>パラメータ:
| オプション | 型 | デフォルト | 説明 |
|---|---|---|---|
url |
string |
- | リクエストURL。 |
method |
string |
GET |
HTTPメソッド。 |
data |
any |
- | リクエストデータ。GET と HEAD リクエストはクエリ文字列にシリアライズ。他のメソッドはリクエストボディに書き込み。 |
headers |
Record<string, string> |
{} |
リクエストヘッダー。 |
timeout |
number |
- | ミリ秒単位のタイムアウト。0 より大きい場合のみ有効。 |
dataType |
'json' \| 'text' \| 'html' \| 'arrayBuffer' |
json |
レスポンスパースモード。 |
contentType |
string |
application/x-www-form-urlencoded; charset=UTF-8 |
リクエストボディContent-Type。 |
processData |
boolean |
true |
data を自動シリアライズするか。false の場合、data を直接リクエストボディとして渡す。 |
戻り値:
| フィールド | 型 | 説明 |
|---|---|---|
ok |
boolean |
HTTP 2xx レスポンスで true。パースエラー、HTTPエラー、タイムアウト、アボート、ネットワークエラーで false。 |
status |
number |
HTTPステータスコード。0 はタイムアウト、アボート、ネットワークレイヤー失敗。 |
statusText |
string |
HTTPステータステキスト。非HTTP失敗の場合は timeout、abort、error。 |
data |
any |
パース済みレスポンスデータ。 |
error |
string |
パース失敗または非HTTP失敗のエラーメッセージ。 |
timeout |
boolean |
設定タイムアウトでリクエストがアボートされた場合 true。 |
GETリクエスト例:
const ret = await api.http.ajax({
url: 'https://example.com/api/profile',
method: 'GET',
dataType: 'json',
timeout: 10000
});
if (ret.ok) {
console.log(ret.data);
}POSTリクエスト例:
const ret = await api.http.ajax({
url: 'https://example.com/api/items',
method: 'POST',
contentType: 'application/json',
data: { name: 'demo' }
});
if (!ret.ok) {
console.warn(ret.status, ret.error || ret.statusText);
}14.5 api.user
api.user はスクリプト実行中のユーザー関連データを読み書き。異なるディメンションでストレージスコープを分離可能。
一般的なパラメータ:
| パラメータ | 型 | デフォルト | 説明 |
|---|---|---|---|
site |
boolean |
false |
サイトで分離するか |
account |
boolean |
false |
サイトアカウントまたはワークスペース名で分離するか |
did |
boolean |
false |
デバイスで分離するか |
ディメンション推奨:
| シナリオ | 推奨事項 |
|---|---|
| 同じユーザーのデータをサイト間で共有 | site=false |
| 各サイトでデータを独立して保存 | site=true |
| 同じサイト下の異なるアカウントを分離 | account=true |
| 同じユーザーを異なるデバイスで分離 | did=true |
14.5.1 api.user.put()
キー値ペアを保存。
put(
name: string,
value: string,
site?: boolean,
account?: boolean,
did?: boolean
): Promise<{ status: boolean }>例:
await api.user.put('token', 'abc123');
await api.user.put('draft:lastOrderId', 'A-1001', true, true);14.5.2 api.user.get()
指定キーを読み取り。
get(
name: string,
site?: boolean,
account?: boolean,
did?: boolean
): Promise<{ value: string | null, status: boolean }>例:
const ret = await api.user.get('token');
if (ret.status && ret.value) {
console.log(ret.value);
}14.5.3 api.user.remove()
指定キーを削除。
remove(
name: string,
site?: boolean,
account?: boolean,
did?: boolean
): Promise<{ status: boolean }>例:
await api.user.remove('token');
await api.user.remove('draft:lastOrderId', true, true);14.5.4 api.user.incr()
指定キーの数値をステップ分増加。キーが存在しない場合は作成。
incr(
name: string,
step?: number,
site?: boolean,
account?: boolean,
did?: boolean
): Promise<{ status: boolean, value: number | string }>例:
const ret = await api.user.incr('submitCount', 1, true);
console.log(ret.value);14.5.5 api.user.decr()
指定キーの数値をステップ分減少。キーが存在しない場合は負の初期値で作成。
decr(
name: string,
step?: number,
site?: boolean,
account?: boolean,
did?: boolean
): Promise<{ status: boolean, value: number | string }>例:
const ret = await api.user.decr('remainingQuota', 1, true, true);
console.log(ret.value);14.5.6 api.user.startsWith()
キー名プレフィックスでデータ検索。
startsWith(
prefix: string,
site?: boolean,
account?: boolean,
did?: boolean
): Promise<Array<{ name: string, value: string }>>例:
const items = await api.user.startsWith('cache:', true);
for (const item of items) {
console.log(item.name, item.value);
}14.5.7 api.user.countAll()
指定キーネームのレコード数をカウント。
countAll(
name: string,
site?: boolean,
account?: boolean
): Promise<{ value: number, status: boolean }>例:
const ret = await api.user.countAll('token', true);
console.log(ret.value);14.5.8 api.user.sumAll()
指定キーネームの値の数値合計を計算。
sumAll(
name: string,
site?: boolean,
account?: boolean
): Promise<{ value: number, status: boolean }>例:
const ret = await api.user.sumAll('score', true);
console.log(ret.value);14.6 api.dom
api.dom はDOMクエリ、可視性チェック、接続リスナー、リサイズリスナー、オーバーレイ作成を提供。
セレクタサポート:
| 構文 | 説明 |
|---|---|
.button.primary |
CSSセレクタ |
xpath://div[@id="app"] |
XPathセレクタ |
.dialog:p |
一致要素の親要素を返す |
.dialog:p2 |
一致要素から2レベル上の祖先を返す |
.header:bottom |
オーバーレイ境界メソッドで要素の下境界を使用 |
.sidebar:right |
オーバーレイ境界メソッドで要素の右境界を使用 |
?sec-matchSelectorも参照。
14.6.1 api.dom.createMutationObserver()
MutationObserver を作成しキャッシュ。同じバインディング名のオブザーバーがターゲット要素に既に存在する場合、既存オブザーバーを直接返す。
createMutationObserver(
ele: Element,
bindStr: string,
childList: boolean,
subtree: boolean,
attributes: boolean,
characterData: boolean,
fn: (mutations: MutationRecord[]) => void
): MutationObserver例:
api.dom.createMutationObserver(
document.body,
'__bodyObserver__',
true,
true,
false,
false,
(mutations) => console.log(mutations)
);14.6.2 api.dom.querySelector()
最初の一致要素をクエリ。
querySelector(doc: Document, cssOrXPathSelector: string): HTMLElement | null例:
const el = api.dom.querySelector(
document,
'xpath://button[contains(.,"Submit")]'
);14.6.3 api.dom.querySelectorAll()
すべての一致要素をクエリ。
querySelectorAll(doc: Document, cssOrXPathSelector: string): HTMLElement[]例:
const buttons = api.dom.querySelectorAll(document, 'button.primary');
buttons.forEach((button) => console.log(button.textContent));14.6.4 api.dom.isVisible()
要素が可視交差領域にあるかチェック。
isVisible(ele: HTMLElement): Promise<boolean>例:
const el = api.dom.querySelector(document, '.submit');
if (el && await api.dom.isVisible(el)) {
console.log('visible');
}14.6.5 api.dom.getVisibleRect()
要素の現在の可視矩形を取得。
getVisibleRect(ele: HTMLElement): Promise<DOMRectReadOnly>例:
const el = api.dom.querySelector(document, '.panel');
if (el) {
const rect = await api.dom.getVisibleRect(el);
console.log(rect.left, rect.top, rect.width, rect.height);
}14.6.6 api.dom.getConnectListeners()
現在の接続リスナーリストを取得。
getConnectListeners(): Array<{
querySelector: string;
callback: (isConnected: boolean) => void;
isConnected?: boolean;
}>例:
api.dom.addConnectListener('.modal', () => {});
console.log(api.dom.getConnectListeners());14.6.7 api.dom.addConnectListener()
要素がドキュメントに現れたり消えたりするのをリスン。
addConnectListener(
cssOrXPathSelector: string,
callback: (isConnected: boolean) => void
): void例:
api.dom.addConnectListener('.dialog', (isConnected) => {
console.log('dialog:', isConnected);
});14.6.8 api.dom.removeConnectListener()
指定セレクタの接続リスナーを削除。
removeConnectListener(cssOrXPathSelectors: string[]): void例:
api.dom.removeConnectListener(['.dialog', '.toast']);14.6.9 api.dom.addResizeListener()
ターゲット要素のサイズと位置変更をリスン。要素が存在しない場合、コールバックは空の矩形を受信。
addResizeListener(
cssOrXPathSelector: string,
bindWindowStr: string,
callback: (rect: DOMRect) => void,
createObserver?: boolean,
delayTime?: number
): ResizeObserver | (() => void)例:
api.dom.addResizeListener('.target', '__targetResize__', (rect) => {
console.log(rect.width, rect.height);
});14.6.10 api.dom.createOverlayBy()
ターゲット要素の可視領域に従う固定位置オーバーレイを作成。
createOverlayBy(
cssOrXPathSelector: string,
bindWindowStr: string,
createObserver?: boolean,
delayTime?: number,
fn?: (rect: DOMRectReadOnly) => void
): HTMLElement例:
const overlay = api.dom.createOverlayBy('.target', '__overlay__');
overlay.style.border = '2px solid #f00';
overlay.style.pointerEvents = 'none';
overlay.style.zIndex = '999999';14.6.11 api.dom.createOverlayByBorder()
上、右、下、左境界から固定位置オーバーレイを作成。境界値はピクセル数またはセレクタ。
createOverlayByBorder(
bindWindowStr: string,
top: string | number,
right: string | number,
bottom: string | number,
left: string | number,
createObserver?: boolean,
delayTime?: number
): HTMLElement例:
const panel = api.dom.createOverlayByBorder(
'__centerPanel__',
'header:bottom',
20,
'footer:top',
'.sidebar:right'
);
panel.style.background = 'rgba(0,0,0,.08)';14.7 api.utils
api.utils はページ条件待機とページコンテキストでのコード実行のための一般的なヘルパー機能を提供。
14.7.1 api.utils.wait()
条件関数がtruthy値を返すまでポーリング。タイムアウトでエラー投げ。
wait(
fn: () => boolean,
timeoutMs: number,
intervalMs?: number
): Promise<void>例:
await api.utils.wait(
() => !!api.dom.querySelector(document, '.ready'),
10000,
200
);14.7.2 api.utils.runScript()
現在のページでJavaScriptコードを実行し結果を返す。
runScript(
code: string,
callback?: (result: any, error: Error) => void
): Promise<any>例:
const title = await api.utils.runScript('document.title');
console.log(title);コールバック形式:
await api.utils.runScript('document.body.innerText.slice(0, 100)', (result, error) => {
if (error) {
console.error(error);
return;
}
console.log(result);
});14.8 api.header()
api.header(headerName, isRequestHeader) はリモートブラウザで記録されたリクエストまたはレスポンスヘッダーを読み取り。
header(
headerName: string,
isRequestHeader: boolean
): Promise<string | string[] | undefined>パラメータ:
| パラメータ | 型 | 説明 |
|---|---|---|
headerName |
string |
リクエストまたはレスポンスヘッダー名。読み取り時に小文字変換 |
isRequestHeader |
boolean |
true でリクエストヘッダー読み取り。false でレスポンスヘッダー読み取り |
例:
const cookie = await api.header('cookie', true);
const setCookie = await api.header('set-cookie', false);注意:
- サイト設定で追加されたリクエストまたはレスポンスヘッダーのみ記録される。
- リクエストヘッダーはリモートブラウザが送信したリクエストから来る。
- レスポンスヘッダーはリモートブラウザが受信したレスポンスから来る。
- レスポンスヘッダーは文字列配列を返す場合がある。
14.9 一般的なスクリプト組み合わせ
14.9.1 要素を待機してクリック
await api.utils.wait(
() => !!api.dom.querySelector(document, '.login-button'),
10000,
200
);
const button = api.dom.querySelector(document, '.login-button');
button?.click();14.9.2 XPathで英語ボタンを検索
const submit = api.dom.querySelector(
document,
'xpath://button[contains(.,"Submit")]'
);
if (submit && await api.dom.isVisible(submit)) {
submit.click();
}14.9.3 ページ状態保存
const count = await api.user.incr('visitCount', 1, true, true);
await api.user.put('lastTitle', document.title, true, true);
console.log(count.value);14.9.4 関心領域にオーバーレイ追加
const overlay = api.dom.createOverlayBy('.customer-phone', '__phoneMask__');
overlay.style.background = '#fff';
overlay.style.pointerEvents = 'none';
overlay.style.zIndex = '999999';14.10 使用原則
スクリプトをビジネスコードのように管理:
- 一致URLを制限し、スクリプトが無関係なページで実行されないようにする。
- ロールバックとトラブルシューティングのためにスクリプトに明確な名前を付ける。
- まずテストサイトまたはテストアカウントで検証。
- DOMセレクタに依存するスクリプトを回帰テスト。
- 保存データに明確なプレフィックスを使用、例:
cache:、draft:、state:。 - シークレット、長寿命トークン、アカウントパスワードをスクリプトにハードコードしない。
- スクリプト変更理由を記録し、必要時にコードレビュー実施。
14.11 トラブルシューティングチェックリスト
| 問題 | 確認事項 |
|---|---|
api が存在しない |
スクリプトタイプが window.api をサポートするか確認。SSEスクリプトはこれに依存すべきではない |
| 要素が見つからない | URLが一致するか、ページが読み込み完了したか、セレクタが変更されたか確認 |
| XPathが動作しない | xpath:// プレフィックスが使用されているか確認 |
| ヘッダーが読めない | 対応するリクエストまたはレスポンスヘッダー名をサイト設定で先に追加 |
| ユーザーデータがスコープ間で混在 | site、account、did ディメンションパラメータ確認 |
| オーバーレイ位置が異常 | ターゲット要素が可視か、境界セレクタが正しいか確認 |
| スクリプトが他ページに影響 | 一致URLを絞り込むか、スクリプト先頭にページ条件チェック追加 |