diff --git a/web/packages/next/local-user.ts b/web/packages/next/local-user.ts new file mode 100644 index 000000000..d20bb7781 --- /dev/null +++ b/web/packages/next/local-user.ts @@ -0,0 +1,42 @@ +// TODO: This file belongs to the accounts package +import * as yup from "yup"; + +const localUserSchema = yup.object({ + /** The user's ID. */ + id: yup.number().required(), + /** The user's email. */ + email: yup.string().required(), + /** + * The user's (plaintext) auth token. + * + * It is used for making API calls on their behalf. + */ + token: yup.string().required(), +}); + +/** Locally available data for the logged in user's */ +export type LocalUser = yup.InferType; + +/** + * Return the logged-in user (if someone is indeed logged in). + * + * The user's data is stored in the browser's localStorage. + */ +export const localUser = async (): Promise => { + // TODO(MR): duplicate of LS_KEYS.USER + const s = localStorage.getItem("user"); + if (!s) return undefined; + return await localUserSchema.validate(JSON.parse(s), { + strict: true, + }); +}; + +/** + * A wrapper over {@link localUser} with that throws if no one is logged in. + */ +export const ensureLocalUser = async (): Promise => { + const user = await localUser(); + if (!user) + throw new Error("Attempting to access user data when not logged in"); + return user; +}; diff --git a/web/packages/next/worker/comlink-worker.ts b/web/packages/next/worker/comlink-worker.ts index f082ac114..a5237fccc 100644 --- a/web/packages/next/worker/comlink-worker.ts +++ b/web/packages/next/worker/comlink-worker.ts @@ -1,6 +1,7 @@ import { ensureElectron } from "@/next/electron"; import log, { logToDisk } from "@/next/log"; import { expose, wrap, type Remote } from "comlink"; +import { ensureLocalUser } from "../local-user"; export class ComlinkWorker InstanceType> { public remote: Promise>>; @@ -35,29 +36,20 @@ export class ComlinkWorker InstanceType> { } } -// TODO(MR): Temporary method to forward auth tokens to workers -const getAuthToken = () => { - // LS_KEYS.USER - const userJSONString = localStorage.getItem("user"); - if (!userJSONString) return undefined; - const json: unknown = JSON.parse(userJSONString); - if (!json || typeof json != "object" || !("token" in json)) - return undefined; - const token = json.token; - if (typeof token != "string") return undefined; - return token; -}; - /** - * A minimal set of utility functions that we expose to all workers that we - * create. + * A set of utility functions that we expose to all workers that we create. * * Inside the worker's code, this can be accessed by using the sibling * `workerBridge` object after importing it from `worker-bridge.ts`. + * + * Not all workers need access to all these functions, and this can indeed be + * done in a more fine-grained, per-worker, manner if needed. */ const workerBridge = { + // Needed: generally (presumably) logToDisk, - getAuthToken, + // Needed by ML worker + getAuthToken: () => ensureLocalUser().then((user) => user.token), convertToJPEG: (inputFileData: Uint8Array, filename: string) => ensureElectron().convertToJPEG(inputFileData, filename), detectFaces: (input: Float32Array) => ensureElectron().detectFaces(input),