Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 53 additions & 31 deletions types/chrome/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6900,22 +6900,38 @@ declare namespace chrome {
* @since Chrome 78
*/
export namespace loginState {
export interface SessionStateChangedEvent extends chrome.events.Event<(sessionState: SessionState) => void> {}

/** Possible profile types. */
export type ProfileType = "SIGNIN_PROFILE" | "USER_PROFILE";
export enum ProfileType {
SIGNIN_PROFILE = "SIGNIN_PROFILE",
USER_PROFILE = "USER_PROFILE",
}

/** Possible session states. */
export type SessionState = "UNKNOWN" | "IN_OOBE_SCREEN" | "IN_LOGIN_SCREEN" | "IN_SESSION" | "IN_LOCK_SCREEN";
export enum SessionState {
UNKNOWN = "UNKNOWN",
IN_OOBE_SCREEN = "IN_OOBE_SCREEN",
IN_LOGIN_SCREEN = "IN_LOGIN_SCREEN",
IN_SESSION = "IN_SESSION",
IN_LOCK_SCREEN = "IN_LOCK_SCREEN",
IN_RMA_SCREEN = "IN_RMA_SCREEN",
}

/** Gets the type of the profile the extension is in. */
export function getProfileType(callback: (profileType: ProfileType) => void): void;
/**
* Gets the type of the profile the extension is in.
*
* Can return its result via Promise in Manifest V3 or later since Chrome 96.
*/
export function getProfileType(): Promise<`${ProfileType}`>;
export function getProfileType(callback: (result: `${ProfileType}`) => void): void;

/** Gets the current session state. */
export function getSessionState(callback: (sessionState: SessionState) => void): void;
/**
* Gets the current session state.
*
* Can return its result via Promise in Manifest V3 or later since Chrome 96.
*/
export function getSessionState(): Promise<`${SessionState}`>;
export function getSessionState(callback: (sessionState: `${SessionState}`) => void): void;

/** Dispatched when the session state changes. sessionState is the new session state.*/
export const onSessionStateChanged: SessionStateChangedEvent;
/** Dispatched when the session state changes. `sessionState` is the new session state.*/
export const onSessionStateChanged: events.Event<(sessionState: `${SessionState}`) => void>;
}

////////////////////
Expand Down Expand Up @@ -10720,11 +10736,8 @@ declare namespace chrome {
export interface CaptureInfo {
/** The id of the tab whose status changed. */
tabId: number;
/**
* The new capture status of the tab.
* One of: "pending", "active", "stopped", or "error"
*/
status: string;
/** The new capture status of the tab. */
status: `${TabCaptureState}`;
/** Whether an element in the tab being captured is in fullscreen mode. */
fullscreen: boolean;
}
Expand All @@ -10735,46 +10748,55 @@ declare namespace chrome {
}

export interface CaptureOptions {
/** Optional. */
audio?: boolean | undefined;
/** Optional. */
video?: boolean | undefined;
/** Optional. */
audioConstraints?: MediaStreamConstraint | undefined;
/** Optional. */
videoConstraints?: MediaStreamConstraint | undefined;
}

/** @since Chrome 71 */
export interface GetMediaStreamOptions {
/** Optional tab id of the tab which will later invoke getUserMedia() to consume the stream. If not specified then the resulting stream can be used only by the calling extension. The stream can only be used by frames in the given tab whose security origin matches the consumber tab's origin. The tab's origin must be a secure origin, e.g. HTTPS. */
/** Optional tab id of the tab which will later invoke `getUserMedia()` to consume the stream. If not specified then the resulting stream can be used only by the calling extension. The stream can only be used by frames in the given tab whose security origin matches the consumber tab's origin. The tab's origin must be a secure origin, e.g. HTTPS. */
consumerTabId?: number | undefined;
/** Optional tab id of the tab which will be captured. If not specified then the current active tab will be selected. Only tabs for which the extension has been granted the activeTab permission can be used as the target tab. */
/** Optional tab id of the tab which will be captured. If not specified then the current active tab will be selected. Only tabs for which the extension has been granted the `activeTab` permission can be used as the target tab. */
targetTabId?: number | undefined;
}

export interface CaptureStatusChangedEvent extends chrome.events.Event<(info: CaptureInfo) => void> {}
export enum TabCaptureState {
PENDING = "pending",
ACTIVE = "active",
STOPPED = "stopped",
ERROR = "error",
}

/**
* Captures the visible area of the currently active tab. Capture can only be started on the currently active tab after the extension has been invoked. Capture is maintained across page navigations within the tab, and stops when the tab is closed, or the media stream is closed by the extension.
* Captures the visible area of the currently active tab. Capture can only be started on the currently active tab after the extension has been invoked, similar to the way that activeTab works. Capture is maintained across page navigations within the tab, and stops when the tab is closed, or the media stream is closed by the extension.
* @param options Configures the returned media stream.
* @param callback Callback with either the tab capture stream or null.
*/
export function capture(options: CaptureOptions, callback: (stream: MediaStream | null) => void): void;

/**
* Returns a list of tabs that have requested capture or are being captured, i.e. status != stopped and status != error. This allows extensions to inform the user that there is an existing tab capture that would prevent a new tab capture from succeeding (or to prevent redundant requests for the same tab).
* @param callback Callback invoked with CaptureInfo[] for captured tabs.
*
* Can return its result via Promise in Manifest V3 or later since Chrome 116.
*/
export function getCapturedTabs(): Promise<CaptureInfo[]>;
export function getCapturedTabs(callback: (result: CaptureInfo[]) => void): void;

/**
* Creates a stream ID to capture the target tab. Similar to chrome.tabCapture.capture() method, but returns a media stream ID, instead of a media stream, to the consumer tab.
* @param options Options for the media stream id to retrieve.
* @param callback Callback to invoke with the result. If successful, the result is an opaque string that can be passed to the getUserMedia() API to generate a media stream that corresponds to the target tab. The created streamId can only be used once and expires after a few seconds if it is not used.
*
* Can return its result via Promise in Manifest V3 or later since Chrome 116.
*/
export function getMediaStreamId(options: GetMediaStreamOptions, callback: (streamId: string) => void): void;
export function getMediaStreamId(options?: GetMediaStreamOptions): Promise<string>;
export function getMediaStreamId(callback: (streamId: string) => void): void;
export function getMediaStreamId(
options: GetMediaStreamOptions | undefined,
callback: (streamId: string) => void,
): void;

/** Event fired when the capture status of a tab changes. This allows extension authors to keep track of the capture status of tabs to keep UI elements like page actions in sync. */
export var onStatusChanged: CaptureStatusChangedEvent;
export const onStatusChanged: events.Event<(info: CaptureInfo) => void>;
}

////////////////////
Expand Down
101 changes: 76 additions & 25 deletions types/chrome/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -996,38 +996,58 @@ function testGetManifest() {
};
}

// https://developer.chrome.com/extensions/tabCapture#type-CaptureOptions
function testTabCaptureOptions() {
// Constraints based on:
// https://github.com/muaz-khan/WebRTC-Experiment/blob/master/Chrome-Extensions/tabCapture/tab-capturing.js

const resolutions = {
maxWidth: 1920,
maxHeight: 1080,
};

const constraints: chrome.tabCapture.CaptureOptions = {
// https://developer.chrome.com/docs/extensions/reference/api/tabCapture
function testTabCapture() {
chrome.tabCapture.TabCaptureState.ACTIVE === "active";
chrome.tabCapture.TabCaptureState.ERROR === "error";
chrome.tabCapture.TabCaptureState.PENDING === "pending";
chrome.tabCapture.TabCaptureState.STOPPED === "stopped";

const captureOptions: chrome.tabCapture.CaptureOptions = {
audio: true,
video: true,
audioConstraints: {
mandatory: {
chromeMediaSource: "tab",
echoCancellation: true,
},
mandatory: {},
optional: {},
},
video: true,
videoConstraints: {
mandatory: {
chromeMediaSource: "tab",
maxWidth: resolutions.maxWidth,
maxHeight: resolutions.maxHeight,
minFrameRate: 30,
minAspectRatio: 1.77,
},
mandatory: {},
optional: {},
},
};

let constraints2: chrome.tabCapture.CaptureOptions;
constraints2 = constraints;
chrome.tabCapture.capture(captureOptions, (stream) => { // $ExpectType void
stream; // $ExpectType MediaStream | null
});

chrome.tabCapture.getCapturedTabs(); // $ExpectType Promise<CaptureInfo[]>
chrome.tabCapture.getCapturedTabs((result) => { // $ExpectType void
result; // $ExpectType CaptureInfo[]
});
// @ts-expect-error
chrome.tabCapture.getCapturedTabs(() => {}).then(() => {});

const mediaStreamOptions: chrome.tabCapture.GetMediaStreamOptions = {
consumerTabId: 123,
targetTabId: 456,
};

chrome.tabCapture.getMediaStreamId(); // $ExpectType Promise<string>
chrome.tabCapture.getMediaStreamId(mediaStreamOptions); // $ExpectType Promise<string>
chrome.tabCapture.getMediaStreamId((streamId) => { // $ExpectType void
streamId; // $ExpectType string
});
chrome.tabCapture.getMediaStreamId(mediaStreamOptions, (streamId) => { // $ExpectType void
streamId; // $ExpectType string
});
// @ts-expect-error
chrome.tabCapture.getMediaStreamId(() => {}).then(() => {});

checkChromeEvent(chrome.tabCapture.onStatusChanged, (info) => {
info.fullscreen; // $ExpectType boolean
info.status; // $ExpectType "active" | "error" | "pending" | "stopped"
info.tabId; // $ExpectType number
});
}

// https://developer.chrome.com/docs/extensions/reference/api/debugger
Expand Down Expand Up @@ -6028,6 +6048,37 @@ function testInstanceID() {
checkChromeEvent(chrome.instanceID.onTokenRefresh, () => void 0);
}

// https://developer.chrome.com/docs/extensions/reference/api/loginState
function testLoginState() {
chrome.loginState.ProfileType.SIGNIN_PROFILE === "SIGNIN_PROFILE";
chrome.loginState.ProfileType.USER_PROFILE === "USER_PROFILE";

chrome.loginState.SessionState.IN_LOCK_SCREEN === "IN_LOCK_SCREEN";
chrome.loginState.SessionState.IN_LOGIN_SCREEN === "IN_LOGIN_SCREEN";
chrome.loginState.SessionState.IN_OOBE_SCREEN === "IN_OOBE_SCREEN";
chrome.loginState.SessionState.IN_RMA_SCREEN === "IN_RMA_SCREEN";
chrome.loginState.SessionState.IN_SESSION === "IN_SESSION";
chrome.loginState.SessionState.UNKNOWN === "UNKNOWN";

chrome.loginState.getProfileType(); // $ExpectType Promise<"SIGNIN_PROFILE" | "USER_PROFILE">
chrome.loginState.getProfileType((result) => { // $ExpectType void
result; // $ExpectType "SIGNIN_PROFILE" | "USER_PROFILE"
});
// @ts-expect-error
chrome.loginState.getProfileType(() => {}).then(() => {});

chrome.loginState.getSessionState(); // $ExpectType Promise<"IN_LOCK_SCREEN" | "IN_LOGIN_SCREEN" | "IN_OOBE_SCREEN" | "IN_RMA_SCREEN" | "IN_SESSION" | "UNKNOWN">
chrome.loginState.getSessionState((result) => { // $ExpectType void
result; // $ExpectType "IN_LOCK_SCREEN" | "IN_LOGIN_SCREEN" | "IN_OOBE_SCREEN" | "IN_RMA_SCREEN" | "IN_SESSION" | "UNKNOWN"
});
// @ts-expect-error
chrome.loginState.getSessionState(() => {}).then(() => {});

checkChromeEvent(chrome.loginState.onSessionStateChanged, (sessionState) => {
sessionState; // $ExpectType "IN_LOCK_SCREEN" | "IN_LOGIN_SCREEN" | "IN_OOBE_SCREEN" | "IN_RMA_SCREEN" | "IN_SESSION" | "UNKNOWN"
});
}

function testUserScripts() {
const worldProperties: chrome.userScripts.WorldProperties = {
csp: "script-src 'self'",
Expand Down
5 changes: 4 additions & 1 deletion types/recordrtc/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,10 @@ declare namespace RecordRTC {
}

declare class RecordRTC {
constructor(stream: MediaStream | HTMLCanvasElement | HTMLVideoElement | HTMLElement, options?: RecordRTC.Options);
constructor(
stream: MediaStream | MediaStream[] | HTMLCanvasElement | HTMLVideoElement | HTMLElement,
options?: RecordRTC.Options,
);

/** start the recording */
startRecording(): void;
Expand Down
42 changes: 42 additions & 0 deletions types/recordrtc/recordrtc-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,48 @@ navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then(stream =>
StereoAudioRecorder.onAudioProcessStarted();
});

Promise.all([
navigator.mediaDevices.getUserMedia({ audio: true, video: true }),
navigator.mediaDevices.getDisplayMedia({ audio: true, video: true }),
]).then(streams => {
const instance = new RecordRTC(streams, {
type: "video",
disableLogs: true,
bufferSize: 2048,
ondataavailable: (blob: Blob) => {
console.log(blob);
},
onTimeStamp: (timestamp: number, timestamps: number[]) => {
console.log(timestamp, timestamps);
},
previewStream: (stream: MediaStream) => {
console.log(stream);
},
});

instance.stopRecording(() => {
const blob = instance.getBlob();
});

// $ExpectType State
instance.getState();

// $ExpectType { onRecordingStopped: (callback: () => void) => void; }
instance.setRecordingDuration(1);

const fiveMinutes = 5 * 1000 * 60;
// $ExpectType void
instance.setRecordingDuration(fiveMinutes, () => {});

// $ExpectType void
instance.getDataURL(dataURL => {
console.log({ dataURL });
});

// $ExpectType void
instance.setRecordingDuration(fiveMinutes).onRecordingStopped(() => {});
});

const canvas = document.querySelector("canvas")!;

const instance2 = new RecordRTC(canvas, {
Expand Down