{"version":3,"file":"mod-user-data.cjs","sources":["../src/lib/user-data/json-schema.ts","../src/lib/user-data/model.ts","../src/lib/user-data/state.ts"],"sourcesContent":["import { z } from 'zod';\n\n// Source: zod's `README.md`, crediting https://github.com/ggoodman\n\nconst literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);\ntype Literal = z.infer<typeof literalSchema>;\ntype Json = Literal | { [key: string]: Json } | Json[];\nexport const jsonSchema: z.ZodType<Json> = z.lazy(() =>\n\tz.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)])\n);\n","import { z } from 'zod';\nimport { generateDashboardId } from '../utils';\nimport { jsonSchema } from './json-schema.ts';\n\n/**\n * A regular expression that matches semantic version numbers.\n *\n * Taken from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string\n */\nexport const semverRegExp =\n\t/^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$/;\n/**\n * A regular expression that matches valid identifiers.\n *\n * Used for dashboard and widget instance IDs.\n *\n * @see {@link WidgetInstance}\n */\nexport const idSchema = z.string();\n/**\n * A schema that matches valid layout configurations.\n */\nexport const layoutSchema = z.array(\n\tz.array(z.union([idSchema, z.literal('.')]))\n);\n/**\n * Represents the schema for a dashboard.\n */\nexport const dashboardSchema = z.object({\n\t/**\n\t * The title of the dashboard.\n\t */\n\ttitle: z.string(),\n\t/**\n\t * The layout of the dashboard.\n\t */\n\tlayout: layoutSchema\n});\n\n/**\n * Represents the schema for a widget instance.\n *\n * @see {@link WidgetInstance}\n */\nexport const widgetInstanceSchema = z.object({\n\t/**\n\t * The configuration of the widget.\n\t */\n\tconfiguration: z.record(z.string(), jsonSchema),\n\t/**\n\t * The type ID of the widget.\n\t *\n\t *\n\t * This is used to determine which widget type to use to render the widget.\n\t *\n\t * @see {@link Widget.id}\n\t */\n\ttype: z.string()\n});\n/**\n * The schema for the user data.\n *\n * @see {@link UserData}\n */\nexport const userDataSchema = z.object({\n\t/**\n\t * The version of the client that created this user data.\n\t */\n\tversion: z.string().regex(semverRegExp),\n\t/**\n\t * The user's dashboards.\n\t */\n\tdashboards: z.record(idSchema, dashboardSchema),\n\t/**\n\t * The user's widget instances.\n\t */\n\twidgetInstances: z.record(idSchema, widgetInstanceSchema)\n});\n/**\n * Represents the user data.\n *\n * @see {@link userDataSchema}\n */\nexport type UserData = z.infer<typeof userDataSchema>;\n/**\n * Represents a dashboard.\n *\n * @see {@link dashboardSchema}\n *\n * @alpha\n */\nexport type Dashboard = z.infer<typeof dashboardSchema>;\n/**\n * Represents a widget instance.\n *\n * @see {@link widgetInstanceSchema}\n */\nexport type WidgetInstance = z.infer<typeof widgetInstanceSchema>;\n\n/**\n * Returns a new and empty dashboard with a unique id.\n */\nexport function getEmptyDashboard(): readonly [\n\tid: string,\n\tdashboard: Dashboard\n] {\n\tconst id = generateDashboardId();\n\treturn [\n\t\tid,\n\t\t{\n\t\t\ttitle: `Untitled (${new Date().toLocaleString()})`,\n\t\t\tlayout: [\n\t\t\t\t['.', '.'],\n\t\t\t\t['.', '.']\n\t\t\t]\n\t\t}\n\t];\n}\n\n/**\n * Returns a new blank user data object.\n * @param version - the current application version\n */\nexport function getBlankUserData(version: string): UserData {\n\tconst [id, dashboard] = getEmptyDashboard();\n\treturn {\n\t\tversion,\n\t\tdashboards: {\n\t\t\t[id]: dashboard\n\t\t},\n\t\twidgetInstances: {}\n\t};\n}\n","import { z } from 'zod';\nimport { getUser } from '../auth';\nimport { userDataSchema } from './model.ts';\n\n/**\n * Retrieves user data from local storage.\n *\n * @returns The user data if found in local storage, otherwise undefined.\n */\n// TODO: Cache return value\nexport function getUserData() {\n\tconst user = getUser();\n\n\tif (!user) {\n\t\treturn undefined;\n\t}\n\n\tconst storedData = localStorage.getItem(\n\t\t`userdata-${user.username}-${user.natsUrl}`\n\t);\n\tif (!storedData) {\n\t\treturn undefined;\n\t}\n\n\ttry {\n\t\treturn userDataSchema.parse(JSON.parse(storedData));\n\t} catch (err) {\n\t\t// don't throw to trigger no data user flow\n\t\tconsole.warn('Cannot parse or validate locally stored user data.');\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Removes the user data from local storage.\n */\nexport function removeUserData() {\n\tconst user = getUser();\n\n\tif (!user) {\n\t\tthrow new Error('Cannot set user data without logged in user.');\n\t}\n\n\tlocalStorage.removeItem(`userdata-${user.username}-${user.natsUrl}`);\n}\n\n/**\n * Sets the user data in the local storage based on the given input.\n *\n * @param newUserData - The new user data to be set.\n */\nexport function setUserData(newUserData: z.input<typeof userDataSchema>) {\n\tconst user = getUser();\n\n\tif (!user) {\n\t\tthrow new Error('Cannot set user data without logged in user.');\n\t}\n\n\tconst validatedUserData = userDataSchema.parse(newUserData);\n\tlocalStorage.setItem(\n\t\t`userdata-${user.username}-${user.natsUrl}`,\n\t\tJSON.stringify(validatedUserData)\n\t);\n}\n"],"names":["literalSchema","z","jsonSchema","semverRegExp","idSchema","layoutSchema","dashboardSchema","widgetInstanceSchema","userDataSchema","getEmptyDashboard","generateDashboardId","getBlankUserData","version","id","dashboard","getUserData","user","getUser","storedData","removeUserData","setUserData","newUserData","validatedUserData"],"mappings":"8NAIA,MAAMA,EAAgBC,EAAE,EAAA,MAAM,CAACA,EAAAA,EAAE,OAAU,EAAAA,EAAA,EAAE,OAAO,EAAGA,EAAAA,EAAE,QAAQ,EAAGA,EAAE,EAAA,KAAA,CAAM,CAAC,EAGhEC,EAA8BD,EAAE,EAAA,KAAK,IACjDA,IAAE,MAAM,CAACD,EAAeC,EAAAA,EAAE,MAAMC,CAAU,EAAGD,EAAA,EAAE,OAAOC,CAAU,CAAC,CAAC,CACnE,ECAaC,EACZ,sLAQYC,EAAWH,IAAE,OAAO,EAIpBI,EAAeJ,EAAE,EAAA,MAC7BA,IAAE,MAAMA,EAAA,EAAE,MAAM,CAACG,EAAUH,EAAAA,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,CAC5C,EAIaK,EAAkBL,IAAE,OAAO,CAIvC,MAAOA,IAAE,OAAO,EAIhB,OAAQI,CACT,CAAC,EAOYE,EAAuBN,IAAE,OAAO,CAI5C,cAAeA,EAAE,EAAA,OAAOA,EAAE,EAAA,OAAA,EAAUC,CAAU,EAS9C,KAAMD,IAAE,OAAO,CAChB,CAAC,EAMYO,EAAiBP,IAAE,OAAO,CAItC,QAASA,EAAAA,EAAE,SAAS,MAAME,CAAY,EAItC,WAAYF,EAAA,EAAE,OAAOG,EAAUE,CAAe,EAI9C,gBAAiBL,EAAA,EAAE,OAAOG,EAAUG,CAAoB,CACzD,CAAC,EAyBM,SAASE,GAGd,CAEM,MAAA,CADIC,EAAAA,sBAGV,CACC,MAAO,aAAa,IAAI,KAAK,EAAE,eAAgB,CAAA,IAC/C,OAAQ,CACP,CAAC,IAAK,GAAG,EACT,CAAC,IAAK,GAAG,CACV,CACD,CAAA,CAEF,CAMO,SAASC,EAAiBC,EAA2B,CAC3D,KAAM,CAACC,EAAIC,CAAS,EAAIL,EAAkB,EACnC,MAAA,CACN,QAAAG,EACA,WAAY,CACX,CAACC,CAAE,EAAGC,CACP,EACA,gBAAiB,CAAC,CAAA,CAEpB,CC1HO,SAASC,GAAc,CAC7B,MAAMC,EAAOC,EAAAA,UAEb,GAAI,CAACD,EACG,OAGR,MAAME,EAAa,aAAa,QAC/B,YAAYF,EAAK,QAAQ,IAAIA,EAAK,OAAO,EAAA,EAE1C,GAAKE,EAID,GAAA,CACH,OAAOV,EAAe,MAAM,KAAK,MAAMU,CAAU,CAAC,OACrC,CAEb,QAAQ,KAAK,oDAAoD,EAC1D,MACR,CACD,CAKO,SAASC,GAAiB,CAChC,MAAMH,EAAOC,EAAAA,UAEb,GAAI,CAACD,EACE,MAAA,IAAI,MAAM,8CAA8C,EAG/D,aAAa,WAAW,YAAYA,EAAK,QAAQ,IAAIA,EAAK,OAAO,EAAE,CACpE,CAOO,SAASI,EAAYC,EAA6C,CACxE,MAAML,EAAOC,EAAAA,UAEb,GAAI,CAACD,EACE,MAAA,IAAI,MAAM,8CAA8C,EAGzD,MAAAM,EAAoBd,EAAe,MAAMa,CAAW,EAC7C,aAAA,QACZ,YAAYL,EAAK,QAAQ,IAAIA,EAAK,OAAO,GACzC,KAAK,UAAUM,CAAiB,CAAA,CAElC"}