Skip to content

Commit

Permalink
Change type of sessionRecorder to "unknown"
Browse files Browse the repository at this point in the history
To facilitate the typing for our window storage, I've added an interface that extends Window.  Additionally, there's a new script in the root of this repo that will clean out "dist" directories.
  • Loading branch information
okaycj committed Jun 10, 2024
1 parent 9e02234 commit 2f3406a
Show file tree
Hide file tree
Showing 13 changed files with 1,311 additions and 110 deletions.
1,304 changes: 1,238 additions & 66 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@
"scripts": {
"build": "npm run build --workspaces",
"changeset": "changeset",
"clean": "find '.' -type d -name 'node_modules' -or -name 'coverage' -or -name 'dist' -exec rm -rf {} \\;",
"clean": "trash \"./packages/**/dist\"",
"fix": "prettier './' -lw && npm run lint",
"format": "prettier './' -c",
"lint": "eslint './packages/**/src/**/*.ts' --fix",
"test": "npm test --workspaces"
},
"dependencies": {},
"devDependencies": {
"@changesets/cli": "^2.27.1",
"@eslint/js": "^9.1.1",
Expand All @@ -39,6 +38,7 @@
"prettier-plugin-packagejson": "^2.5.0",
"prettier-plugin-sort-json": "^4.0.0",
"rollup-plugin-serve": "^1.1.1",
"trash-cli": "^5.0.0",
"typescript-eslint": "^7.7.1"
},
"engines": {
Expand Down
3 changes: 3 additions & 0 deletions packages/data/src/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import Api from "./index";
import { LookitWindow } from "./types";

declare let window: LookitWindow;

jest.mock("./utils", () => ({
...jest.requireActual("./utils"),
Expand Down
17 changes: 3 additions & 14 deletions packages/data/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,9 @@ import {
} from "./api";

import LookitS3 from "./lookitS3";
import { Child, PastSession, Response, Study } from "./types";
import Recorder from "@lookit/record/dist/recorder";
import { LookitWindow } from "./types";

declare global {
interface Window {
chs: {
study: Study;
child: Child;
pastSessions: PastSession[];
response: Response;
sessionRecorder: Recorder | null;
};
}
}
declare let window: LookitWindow;

/**
* Load data from API that is needed for saving the experiment data, and that
Expand All @@ -38,7 +27,7 @@ const load = async (response_uuid: string) => {
child: await retrieveChild(),
pastSessions: await retrievePastSessions(response_uuid),
response: await retrieveResponse(response_uuid),
sessionRecorder: null
sessionRecorder: undefined,
},
});
//deepFreeze(window.chs);
Expand Down
2 changes: 1 addition & 1 deletion packages/data/src/lookitS3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class LookitS3 {
if (!response.UploadId) {
throw new AWSMissingAttrError("UploadId");
}

this.uploadId = response.UploadId;
this.logRecordingEvent(`Connection established.`);
}
Expand Down
10 changes: 10 additions & 0 deletions packages/data/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,13 @@ export type Env = {
bucket: string;
region: string;
};

export interface LookitWindow extends Window {
chs: {
study: Study;
child: Child;
pastSessions: PastSession[];
response: Response;
sessionRecorder: unknown;
};
}
3 changes: 3 additions & 0 deletions packages/lookit-initjspsych/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import Api from "@lookit/data";
import { LookitWindow } from "@lookit/data/dist/types";
import { DataCollection } from "jspsych/dist/modules/data/DataCollection";
import { UserFunc } from "./types";

declare let window: LookitWindow;

/**
* Function that returns a function to be used in place of jsPsych's option
* "on_data_update". "userFunc" should be the user's implementation of
Expand Down
27 changes: 18 additions & 9 deletions packages/record/src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,37 @@ export class RecorderInitializeError extends Error {
}
}

/** Error thrown when trying to stop an active session recording that cannot be found. */
/**
* Error thrown when trying to stop an active session recording that cannot be
* found.
*/
export class NoSessionRecordingError extends Error {
/**
* When trying to stop a recording that isn't found,
* provide the user with an explanation of what they could do to resolve the issue.
* When trying to stop a recording that isn't found, provide the user with an
* explanation of what they could do to resolve the issue.
*/
public constructor() {
const message = "Cannot stop a session recording because no active session recording was found. Maybe it needs to be started, or there was a problem starting the recording.";
const message =
"Cannot stop a session recording because no active session recording was found. Maybe it needs to be started, or there was a problem starting the recording.";
super(message);
this.name = "NoSessionRecordingError";
}
}

/** Error thrown when trying to trying to start a recording while another is already active. */
/**
* Error thrown when trying to trying to start a recording while another is
* already active.
*/
export class ExistingRecordingError extends Error {
/**
* When trying to start a recording but there is already an active recording in progress,
* provide the user with an explanation of what they could do to resolve the issue.
* When trying to start a recording but there is already an active recording
* in progress, provide the user with an explanation of what they could do to
* resolve the issue.
*/
public constructor() {
const message = "Cannot start a new recording because an active recording was found. Maybe a session recording needs to be stopped, trial recording is being used during session recording, or there was a problem stopping a prior recording.";
const message =
"Cannot start a new recording because an active recording was found. Maybe a session recording needs to be stopped, trial recording is being used during session recording, or there was a problem stopping a prior recording.";
super(message);
this.name = "ExistingRecordingError";
}
}
}
17 changes: 9 additions & 8 deletions packages/record/src/recorder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default class Recorder {
private localDownload: boolean = false;
private s3?: lookitS3;
private fileNameStr: string;
private stopPromise: Promise<void> | null = null;
private stopPromise?: Promise<void>;

/**
* Recorder for online experiments.
Expand Down Expand Up @@ -52,7 +52,7 @@ export default class Recorder {
*/
public get filename() {
return this.fileNameStr;
};
}

/**
* Get stream from either recorder.
Expand All @@ -72,17 +72,17 @@ export default class Recorder {
this.recorder.addEventListener("dataavailable", this.handleDataAvailable);
// create a stop promise and pass the resolve function as an argument to the stop event callback,
// so that the stop event handler can resolve the stop promise
this.stopPromise = new Promise((resolve, reject) => {
this.stopPromise = new Promise((resolve) => {
this.recorder.addEventListener("stop", this.handleStop(resolve));
})
});
if (!this.localDownload) {
await this.s3?.createUpload();
}
this.recorder.start();
}

/** Stop recording and camera/microphone. */

Check failure on line 84 in packages/record/src/recorder.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 20

Missing JSDoc @returns declaration
public async stop() {
public stop() {
this.recorder.stop();
this.stream.getTracks().map((t) => t.stop());
return this.stopPromise;
Expand All @@ -96,15 +96,15 @@ export default class Recorder {
}

/** Handle the recorder's stop event. */

Check failure on line 98 in packages/record/src/recorder.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 20

Missing JSDoc @returns declaration
private handleStop(resolve: { (value: void | PromiseLike<void>): void; }) {
private handleStop(resolve: { (value: void | PromiseLike<void>): void }) {
return async () => {
if (this.localDownload) {
await this.download();
} else {
await this.s3?.completeUpload();
}
resolve();
}
};
}

/**
Expand Down Expand Up @@ -164,7 +164,8 @@ export default class Recorder {
* Function to create a video recording filename.
*
* @param prefix - (string): Start of the file name for the video recording.
* @returns Filename string, including the prefix, date/time and webm extension.
* @returns Filename string, including the prefix, date/time and webm
* extension.
*/
private createFilename(prefix: string) {
return `${prefix}_${new Date().getTime()}.webm`;
Expand Down
6 changes: 4 additions & 2 deletions packages/record/src/start.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { LookitWindow } from "@lookit/data/dist/types";
import { JsPsych, JsPsychPlugin } from "jspsych";
import Recorder from "./recorder";
import { ExistingRecordingError } from "./error";
import Recorder from "./recorder";

declare let window: LookitWindow;

const info = <const>{ name: "start-record-plugin", parameters: {} };
type Info = typeof info;
Expand All @@ -22,7 +25,6 @@ export default class StartRecordPlugin implements JsPsychPlugin<Info> {
} else {
throw new ExistingRecordingError();
}

}

/** Trial function called by jsPsych. */
Expand Down
22 changes: 14 additions & 8 deletions packages/record/src/stop.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { JsPsych, JsPsychPlugin } from "jspsych";
import Recorder from "./recorder";
import RecorderType from "@lookit/record/dist/recorder";
import { NoSessionRecordingError } from "./error";
import Recorder from "./recorder";

import { LookitWindow } from "@lookit/data/dist/types";

declare let window: LookitWindow;

const info = <const>{ name: "stop-record-plugin", parameters: {} };
type Info = typeof info;

/** Stop recording. Used by researchers who want to record across trials. */
export default class StopRecordPlugin implements JsPsychPlugin<Info> {
public static readonly info = info;
private recorder: RecorderType;
private recorder: Recorder;

/**
* Plugin used to stop recording.
Expand All @@ -18,18 +21,21 @@ export default class StopRecordPlugin implements JsPsychPlugin<Info> {
*/
public constructor(private jsPsych: JsPsych) {
if (window.chs.sessionRecorder) {
this.recorder = window.chs.sessionRecorder;
this.recorder = window.chs.sessionRecorder as Recorder;
} else {
throw new NoSessionRecordingError();
}
}

/** Trial function called by jsPsych. */
/**
* Trial function called by jsPsych.
* @param display_element

Check failure on line 32 in packages/record/src/stop.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node.js 20

Missing JSDoc @param "display_element" description
*/
public trial(display_element: HTMLElement): void {
display_element.innerHTML = '<div>Uploading video, please wait...</div>';
this.recorder.stop().then(() => {
display_element.innerHTML = "<div>Uploading video, please wait...</div>";
this.recorder.stop()?.then(() => {
window.chs.sessionRecorder = null;
display_element.innerHTML = '';
display_element.innerHTML = "";
this.jsPsych.finishTrial();
});
}
Expand Down
3 changes: 3 additions & 0 deletions packages/surveys/src/exit.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import SurveyPlugin from "@jspsych/plugin-survey";
import { LookitWindow } from "@lookit/data/dist/types";
import { ParameterType, TrialType } from "jspsych";
import { surveyJSON } from "./exit_json";
import { exitSurveyFunction as survey_function } from "./utils";

declare let window: LookitWindow;

const info = <const>{
...SurveyPlugin.info,
parameters: {
Expand Down
3 changes: 3 additions & 0 deletions packages/surveys/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import Data from "@lookit/data";
import { LookitWindow } from "@lookit/data/dist/types";
import DOMPurify from "dompurify";
import { marked } from "marked";
import { Model } from "survey-jquery";

declare let window: LookitWindow;

const CONFIG = <const>{
marked: { async: false },
dompurify: { USE_PROFILES: { html: true } },
Expand Down

0 comments on commit 2f3406a

Please sign in to comment.