Skip to content

Commit

Permalink
Add zod types for extension messages; clean up other zod types
Browse files Browse the repository at this point in the history
  • Loading branch information
mwhirls committed Feb 7, 2024
1 parent 998c735 commit 22196e1
Show file tree
Hide file tree
Showing 13 changed files with 115 additions and 115 deletions.
2 changes: 1 addition & 1 deletion src/common/components/OptionsButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { sendMessage } from '../../content-scripts/util/browser-runtime';
import { RuntimeMessage, RuntimeEvent } from '../events';

function openOptions(context: ExtensionContext) {
const message: RuntimeMessage = { event: RuntimeEvent.OpenOptions, data: undefined };
const message: RuntimeMessage = { event: RuntimeEvent.enum.OpenOptions, data: undefined };
return sendMessage(message, context);
}

Expand Down
142 changes: 71 additions & 71 deletions src/common/events.ts
Original file line number Diff line number Diff line change
@@ -1,87 +1,87 @@
import { TatoebaSentence } from "./tatoeba-types";
import { z } from "zod";

export enum RuntimeEvent {
CountKanji = 'count-kanji',
CountSentences = 'count-sentences',
LookupKanji = 'lookup-kanji',
LookupSentences = 'lookup-sentences',
LookupWords = 'lookup-words',
MetadataDetected = 'metadata-detected',
PlayAudio = 'play-audio',
PurgeDictionaries = 'purge-dictionaries',
SubtitleTrackSwitched = 'subtitle-track-switched',
SeekCue = 'seek-cue',
SeekTime = 'seek-time',
ToggleSubs = 'toggle-subs',
OpenOptions = 'open-options',
}
export const RuntimeEvent = z.enum([
"CountKanji",
"CountSentences",
"LookupKanji",
"LookupSentences",
"LookupWords",
"MetadataDetected",
"PlayAudio",
"PurgeDictionaries",
"SubtitleTrackSwitched",
"SeekCue",
"SeekTime",
"ToggleSubs",
"OpenOptions"
] as const);

export interface RuntimeMessage {
export const RuntimeMessage = z.object({
event: RuntimeEvent,
data: unknown
}
data: z.any()
})

export enum SeekDirection {
Next,
Repeat,
Previous,
}
export const SeekDirection = z.enum([
"Next",
"Repeat",
"Previous",
] as const)

export interface SeekCueMessage {
export const SeekCueMessage = z.object({
direction: SeekDirection
}
})

export interface SeekTimeMessage {
startTime: number
}
export const SeekTimeMessage = z.object({
startTime: z.number(),
});

export interface LookupWordsMessage {
words: {
surfaceForm: string;
baseForm: string;
katakana: string;
hiragana: string;
}[];
}
export const LookupWordsMessage = z.object({
words: z.array(z.object({
surfaceForm: z.string(),
baseForm: z.string(),
katakana: z.string(),
hiragana: z.string(),
}))
})

export interface Success<T> {
type: 'success';
data: T;
}
export const CountKanjiMessage = z.object({
kanji: z.array(z.string())
})

export interface Error<S> {
type: 'error';
data: S;
message: string;
}
export const CountSentencesMessage = z.object({
searchTerm: z.string()
})

export interface MessageResponse<T, S> {
result: Success<T> | Error<S>
}
export const LookupSentencesMessage = z.object({
searchTerm: z.string(),
page: z.number(),
perPage: z.number(),
})

export interface CountKanjiMessage {
kanji: string[];
}
const Sentence: z.ZodType<TatoebaSentence> = z.any(); // todo: better validation for this type
export const LookupSentencesResult = z.object({
sentences: z.array(Sentence),
pages: z.number(),
})

export interface CountSentencesMessage {
searchTerm: string;
}
export const LookupKanjiMessage = z.object({
kanji: z.array(z.string())
})

export interface LookupSentencesMessage {
searchTerm: string;
page: number;
perPage: number;
}
export const PlayAudioMessage = z.object({
utterance: z.string()
})

export interface LookupSentencesResult {
sentences: TatoebaSentence[];
pages: number;
}

export interface LookupKanjiMessage {
kanji: string[];
}

export interface PlayAudioMessage {
utterance: string;
}
export type RuntimeEvent = z.infer<typeof RuntimeEvent>;
export type RuntimeMessage = z.infer<typeof RuntimeMessage>;
export type SeekDirection = z.infer<typeof SeekDirection>;
export type SeekCueMessage = z.infer<typeof SeekCueMessage>;
export type SeekTimeMessage = z.infer<typeof SeekTimeMessage>;
export type LookupWordsMessage = z.infer<typeof LookupWordsMessage>;
export type CountKanjiMessage = z.infer<typeof CountKanjiMessage>;
export type CountSentencesMessage = z.infer<typeof CountSentencesMessage>;
export type LookupSentencesMessage = z.infer<typeof LookupSentencesMessage>;
export type LookupSentencesResult = z.infer<typeof LookupSentencesResult>;
export type LookupKanjiMessage = z.infer<typeof LookupKanjiMessage>;
export type PlayAudioMessage = z.infer<typeof PlayAudioMessage>;
20 changes: 10 additions & 10 deletions src/common/netflix-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ export const CdnUrl = z.object({
});

export const TTDownloadable = z.object({
urls: z.array(z.object(CdnUrl.shape)),
urls: z.array(CdnUrl),
});

export const TimedTextTrack = z.object({
language: z.nullable(z.string()),
languageDescription: z.string(),
new_track_id: z.string(),
ttDownloadables: z.record(z.object(TTDownloadable.shape)),
ttDownloadables: z.record(TTDownloadable),
});

export const RecommendedMedia = z.object({
Expand All @@ -22,8 +22,8 @@ export const RecommendedMedia = z.object({

export const NetflixMetadata = z.object({
movieId: z.number(),
recommendedMedia: z.object(RecommendedMedia.shape),
timedtexttracks: z.array(z.object(TimedTextTrack.shape)),
recommendedMedia: RecommendedMedia,
timedtexttracks: z.array(TimedTextTrack),
});

export const TimedTextSwitch = z.object({
Expand All @@ -36,27 +36,27 @@ export const NetflixSessionPlayer = z.object({

export const NetflixVideoPlayer = z.object({
getAllPlayerSessionIds: z.function().returns(z.array(z.string())),
getVideoPlayerBySessionId: z.function().args(z.string()).returns(z.object(NetflixSessionPlayer.shape)),
getVideoPlayerBySessionId: z.function().args(z.string()).returns(NetflixSessionPlayer),
})

export const NetflixAPI = z.object({
videoPlayer: z.object(NetflixVideoPlayer.shape)
videoPlayer: NetflixVideoPlayer
});

export const NetflixPlayerApp = z.object({
getAPI: z.function().returns(z.object(NetflixAPI.shape))
getAPI: z.function().returns(NetflixAPI)
});

export const NetflixState = z.object({
playerApp: z.object(NetflixPlayerApp.shape)
playerApp: NetflixPlayerApp
});

export const NetflixAppContext = z.object({
state: z.object(NetflixState.shape)
state: NetflixState
});

export const Netflix = z.object({
appContext: z.object(NetflixAppContext.shape)
appContext: NetflixAppContext
});

export type CdnUrl = z.infer<typeof CdnUrl>;
Expand Down
12 changes: 6 additions & 6 deletions src/content-scripts/components/Video.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,17 +123,17 @@ function onSeekCue(direction: SeekDirection, currentTime: number, cues: TextTrac
if (!index) {
return;
}
if (direction === SeekDirection.Next) {
if (direction === SeekDirection.enum.Next) {
index = Math.min(index + 1, cues.length - 1);
}
else if (direction === SeekDirection.Previous) {
else if (direction === SeekDirection.enum.Previous) {
index = Math.max(0, index - 1)
}

// videoElem.currentTime can't be set without triggering a Netflix error,
// so dispatch to the page script to set time directly using Netflix API
const cue = cues[index];
window.dispatchEvent(new CustomEvent(RuntimeEvent.SeekTime, { detail: { startTime: cue.startTime } }));
window.dispatchEvent(new CustomEvent(RuntimeEvent.enum.SeekTime, { detail: { startTime: cue.startTime } }));
}

interface CueWithText {
Expand Down Expand Up @@ -169,7 +169,7 @@ async function lookupWords(words: bunsetsu.Word[], context: ExtensionContext): P
};
})
};
const message: RuntimeMessage = { event: RuntimeEvent.LookupWords, data: data };
const message: RuntimeMessage = { event: RuntimeEvent.enum.LookupWords, data: data };
const entries = await sendMessage(message, context);
return words.map((word, index) => {
return {
Expand Down Expand Up @@ -209,10 +209,10 @@ function Video({ dbStatus, webvttSubtitles, videoElem }: VideoProps) {

useEffect(() => {
const runtimeListener = (message: RuntimeMessage) => {
if (message.event === RuntimeEvent.SeekCue) {
if (message.event === RuntimeEvent.enum.SeekCue) {
const data = message.data as SeekCueMessage;
onSeekCue(data.direction, videoElem.currentTime, cuesRef.current);
} else if (message.event === RuntimeEvent.ToggleSubs) {
} else if (message.event === RuntimeEvent.enum.ToggleSubs) {
setShow(prev => !prev);
}
};
Expand Down
8 changes: 4 additions & 4 deletions src/content-scripts/components/VideoContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ function VideoContainer({ dbStatus }: VideoContainerProps) {
const data = (event as CustomEvent).detail as TimedTextSwitch;
setCurrTrack(data.track.trackId);
};
window.addEventListener(RuntimeEvent.MetadataDetected, metadataListener);
window.addEventListener(RuntimeEvent.SubtitleTrackSwitched, trackSwitchedListener);
window.addEventListener(RuntimeEvent.enum.MetadataDetected, metadataListener);
window.addEventListener(RuntimeEvent.enum.SubtitleTrackSwitched, trackSwitchedListener);

// We insert our components into the Netflix DOM, but they constantly
// mutate it. Watch for changes so we know when to re-render.
Expand All @@ -109,8 +109,8 @@ function VideoContainer({ dbStatus }: VideoContainerProps) {
netflixObserver.observe(document.body, config);

return () => {
window.removeEventListener(RuntimeEvent.MetadataDetected, metadataListener);
window.removeEventListener(RuntimeEvent.MetadataDetected, trackSwitchedListener);
window.removeEventListener(RuntimeEvent.enum.MetadataDetected, metadataListener);
window.removeEventListener(RuntimeEvent.enum.SubtitleTrackSwitched, trackSwitchedListener);
netflixObserver.disconnect();
};
}, []);
Expand Down
4 changes: 2 additions & 2 deletions src/content-scripts/components/lookup/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ async function countKanji(entry: JMdictWord, context: ExtensionContext): Promise
const kanji = kanjiWords.flatMap(word => extractKanji(word));
const unique = kanji.filter((c, index, arr) => arr.indexOf(c) === index);
const data: CountKanjiMessage = { kanji: unique };
const message: RuntimeMessage = { event: RuntimeEvent.LookupKanji, data: data };
const message: RuntimeMessage = { event: RuntimeEvent.enum.LookupKanji, data: data };
return sendMessage(message, context);
}

async function countSentences(word: bunsetsu.Word, context: ExtensionContext): Promise<number> {
const data: CountSentencesMessage = {
searchTerm: word.baseForm ?? toHiragana(word.reading),
};
const message: RuntimeMessage = { event: RuntimeEvent.CountSentences, data: data };
const message: RuntimeMessage = { event: RuntimeEvent.enum.CountSentences, data: data };
return sendMessage(message, context);
}

Expand Down
2 changes: 1 addition & 1 deletion src/content-scripts/components/lookup/Examples.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ async function lookupSentences(word: bunsetsu.Word, page: number, context: Exten
page,
perPage: SENTENCES_PER_PAGE,
};
const message: RuntimeMessage = { event: RuntimeEvent.LookupSentences, data: data };
const message: RuntimeMessage = { event: RuntimeEvent.enum.LookupSentences, data: data };
return sendMessage(message, context);
}

Expand Down
2 changes: 1 addition & 1 deletion src/content-scripts/components/lookup/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function onAudioClicked(word: bunsetsu.Word, context: ExtensionContext) {
return;
}
const data: PlayAudioMessage = { utterance };
const message: RuntimeMessage = { event: RuntimeEvent.PlayAudio, data };
const message: RuntimeMessage = { event: RuntimeEvent.enum.PlayAudio, data };
sendMessage(message, context);
}

Expand Down
2 changes: 1 addition & 1 deletion src/content-scripts/components/lookup/Kanji.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ async function lookupKanji(entry: JMdictWord, context: ExtensionContext): Promis
const kanji = kanjiWords.flatMap(word => extractKanji(word));
const unique = kanji.filter((c, index, arr) => arr.indexOf(c) === index);
const data: LookupKanjiMessage = { kanji: unique };
const message: RuntimeMessage = { event: RuntimeEvent.LookupKanji, data: data };
const message: RuntimeMessage = { event: RuntimeEvent.enum.LookupKanji, data: data };
return sendMessage(message, context);
}

Expand Down
6 changes: 3 additions & 3 deletions src/content-scripts/interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,18 @@ JSON.parse = (text) => {
if (parsed.result) {
const metadata = NetflixMetadata.safeParse(parsed.result);
if (metadata.success) {
window.dispatchEvent(new CustomEvent(RuntimeEvent.MetadataDetected, { detail: metadata.data }));
window.dispatchEvent(new CustomEvent(RuntimeEvent.enum.MetadataDetected, { detail: metadata.data }));
}
}
const tts = TimedTextSwitch.safeParse(parsed);
if (tts.success) {
window.dispatchEvent(new CustomEvent(RuntimeEvent.SubtitleTrackSwitched, { detail: tts.data }));
window.dispatchEvent(new CustomEvent(RuntimeEvent.enum.SubtitleTrackSwitched, { detail: tts.data }));
}
}
return parsed;
}

window.addEventListener(RuntimeEvent.SeekTime, (event) => {
window.addEventListener(RuntimeEvent.enum.SeekTime, (event) => {
const data = (event as CustomEvent).detail as SeekTimeMessage;
const time = data.startTime;

Expand Down
2 changes: 1 addition & 1 deletion src/options/components/PurgeButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { StorageType } from "../../storage/storage";
const DB_STATUS_KEY = 'lastDBStatusResult'

async function purgeDictionaries(): Promise<number> {
const message: RuntimeMessage = { event: RuntimeEvent.PurgeDictionaries, data: undefined };
const message: RuntimeMessage = { event: RuntimeEvent.enum.PurgeDictionaries, data: undefined };
return chrome.runtime.sendMessage(message);
}

Expand Down
Loading

0 comments on commit 22196e1

Please sign in to comment.