modelence 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -18,6 +18,7 @@ type MethodResult<T> = {
18
18
  error: Error | null;
19
19
  data: T | null;
20
20
  };
21
+ declare function callMethod<T = unknown>(methodName: string, args?: Args): Promise<T>;
21
22
  declare function useLoader<T>(methodName: string, args?: Args): MethodResult<T>;
22
23
 
23
24
  declare function useSession(): {
@@ -38,4 +39,4 @@ declare function loginWithPassword({ email, password }: {
38
39
 
39
40
  declare const AppProvider: any;
40
41
 
41
- export { AppProvider, getConfig, loginWithPassword, renderApp, signupWithPassword, useLoader, useSession };
42
+ export { AppProvider, callMethod, getConfig, loginWithPassword, renderApp, signupWithPassword, useLoader, useSession };
package/dist/client.js CHANGED
@@ -1,2 +1,2 @@
1
- import {a}from'./chunk-GDI7FXAT.js';import P,{useMemo,useState,useEffect}from'react';import {z as z$1}from'zod';import {jsx,Fragment}from'react/jsx-runtime';import j from'react-dom/client';function p(){let e=localStorage.getItem("modelence.session");try{return e?JSON.parse(e):null}catch(r){return console.error("Error parsing session from localStorage",r),null}}function f(e){localStorage.setItem("modelence.session",JSON.stringify(e));}var u=(e,r)=>{throw new Error(`Error calling method '${r}': ${e.toString()}`)};function g(e){u=e;}function m(e,r){return u(e,r)}async function i(e,r={}){try{return await v(`/api/_internal/method/${e}`,r)}catch(o){throw m(o,e),o}}async function v(e,r){let o=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({args:r,authToken:p()?.authToken,clientInfo:{screenWidth:window.screen.width,screenHeight:window.screen.height,windowWidth:window.innerWidth,windowHeight:window.innerHeight,pixelRatio:window.devicePixelRatio,orientation:window.screen.orientation?.type}})});if(!o.ok){let n=await o.text();throw new Error(n)}let t=await o.text();return t?JSON.parse(t):void 0}function k(e,r={}){let o=useMemo(()=>r,[JSON.stringify(r)]),[t,n]=useState({isLoading:!0,error:null,data:null});return useEffect(()=>{(async()=>{try{let a=await i(e,o);n({isLoading:!1,error:null,data:a});}catch(a){n({isLoading:!1,error:a,data:null});}})();},[e,o]),t}var h={};function M(e){return h[e]?.value}function w(e){h=e;}var y=!1,O=a.seconds(30),E=null;async function S(){if(y)return;y=!0;let{configs:e,session:r,user:o}=await i("_system.session.init");w(e),f(r),E=o?Object.freeze(z$1.object({id:z$1.string(),handle:z$1.string()}).parse(o)):null,await R();}async function R(){await i("_system.session.heartbeat"),setTimeout(R,O);}function W(){let[e,r]=useState(E);return useEffect(()=>{},[]),{user:e}}function l({children:e,loadingElement:r}){let[o,t]=useState(!0);return useEffect(()=>{async function n(){await S(),t(!1);}n();},[]),o?r??jsx("div",{children:"Loading..."}):jsx(Fragment,{children:e})}function z({loadingElement:e,routesElement:r,favicon:o,errorHandler:t}){if(t&&g(t),window.addEventListener("unload",()=>{}),j.createRoot(document.getElementById("root")).render(jsx(P.StrictMode,{children:jsx(C,{loadingElement:e,children:r})})),o){let n=document.querySelector("link[rel~='icon']");if(n)n.href=o;else {let s=document.createElement("link");s.rel="icon",s.href=o,document.head.appendChild(s);}}}async function D({email:e,password:r}){return i("_system.user.signupWithPassword",{email:e,password:r})}async function $({email:e,password:r}){return i("_system.user.loginWithPassword",{email:e,password:r})}var C="useClient"in P?P.useClient(l):l;export{C as AppProvider,M as getConfig,$ as loginWithPassword,z as renderApp,D as signupWithPassword,k as useLoader,W as useSession};//# sourceMappingURL=client.js.map
1
+ import {a}from'./chunk-GDI7FXAT.js';import P,{useMemo,useState,useEffect}from'react';import {z as z$1}from'zod';import {jsx,Fragment}from'react/jsx-runtime';import j from'react-dom/client';function p(){let e=localStorage.getItem("modelence.session");try{return e?JSON.parse(e):null}catch(r){return console.error("Error parsing session from localStorage",r),null}}function f(e){localStorage.setItem("modelence.session",JSON.stringify(e));}var u=(e,r)=>{throw new Error(`Error calling method '${r}': ${e.toString()}`)};function g(e){u=e;}function m(e,r){return u(e,r)}async function i(e,r={}){try{return await v(`/api/_internal/method/${e}`,r)}catch(o){throw m(o,e),o}}async function v(e,r){let o=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({args:r,authToken:p()?.authToken,clientInfo:{screenWidth:window.screen.width,screenHeight:window.screen.height,windowWidth:window.innerWidth,windowHeight:window.innerHeight,pixelRatio:window.devicePixelRatio,orientation:window.screen.orientation?.type}})});if(!o.ok){let n=await o.text();throw new Error(n)}let t=await o.text();return t?JSON.parse(t):void 0}function M(e,r={}){let o=useMemo(()=>r,[JSON.stringify(r)]),[t,n]=useState({isLoading:!0,error:null,data:null});return useEffect(()=>{(async()=>{try{let a=await i(e,o);n({isLoading:!1,error:null,data:a});}catch(a){n({isLoading:!1,error:a,data:null});}})();},[e,o]),t}var h={};function k(e){return h[e]?.value}function w(e){h=e;}var y=!1,O=a.seconds(30),E=null;async function S(){if(y)return;y=!0;let{configs:e,session:r,user:o}=await i("_system.session.init");w(e),f(r),E=o?Object.freeze(z$1.object({id:z$1.string(),handle:z$1.string()}).parse(o)):null,await R();}async function R(){await i("_system.session.heartbeat"),setTimeout(R,O);}function W(){let[e,r]=useState(E);return useEffect(()=>{},[]),{user:e}}function l({children:e,loadingElement:r}){let[o,t]=useState(!0);return useEffect(()=>{async function n(){await S(),t(!1);}n();},[]),o?r??jsx("div",{children:"Loading..."}):jsx(Fragment,{children:e})}function z({loadingElement:e,routesElement:r,favicon:o,errorHandler:t}){if(t&&g(t),window.addEventListener("unload",()=>{}),j.createRoot(document.getElementById("root")).render(jsx(P.StrictMode,{children:jsx(C,{loadingElement:e,children:r})})),o){let n=document.querySelector("link[rel~='icon']");if(n)n.href=o;else {let s=document.createElement("link");s.rel="icon",s.href=o,document.head.appendChild(s);}}}async function D({email:e,password:r}){return i("_system.user.signupWithPassword",{email:e,password:r})}async function $({email:e,password:r}){return i("_system.user.loginWithPassword",{email:e,password:r})}var C="useClient"in P?P.useClient(l):l;export{C as AppProvider,i as callMethod,k as getConfig,$ as loginWithPassword,z as renderApp,D as signupWithPassword,M as useLoader,W as useSession};//# sourceMappingURL=client.js.map
2
2
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../client/localStorage.ts","../client/errorHandler.ts","../client/method.ts","../config/client.ts","../client/session.ts","../client/AppProvider.tsx","../client/renderApp.tsx","../auth/client/index.ts","../client.ts"],"names":["getLocalStorageSession","sessionJson","e","setLocalStorageSession","session","errorHandler","error","methodName","setErrorHandler","handler","handleError","callMethod","args","call","endpoint","response","text","useLoader","stableArgs","useMemo","result","setResult","useState","useEffect","data","config","getConfig","key","_setConfig","configs","isInitialized","SESSION_HEARTBEAT_INTERVAL","time","currentUser","initSession","user","z","loopSessionHeartbeat","useSession","setUser","AppProvider","children","loadingElement","isLoading","setIsLoading","initConfig","jsx","Fragment","renderApp","routesElement","favicon","ReactDOM","React","link","newLink","signupWithPassword","email","password","loginWithPassword"],"mappings":"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","file":"client.js","sourcesContent":["export function getLocalStorageSession() {\n const sessionJson = localStorage.getItem('modelence.session');\n try {\n return sessionJson ? JSON.parse(sessionJson) : null;\n } catch (e) {\n console.error('Error parsing session from localStorage', e);\n return null;\n }\n}\n\nexport function setLocalStorageSession(session: object) {\n localStorage.setItem('modelence.session', JSON.stringify(session));\n}\n","export type ErrorHandler = (error: Error, methodName: string) => void;\n\nlet errorHandler: ErrorHandler = (error, methodName) => {\n throw new Error(`Error calling method '${methodName}': ${error.toString()}`);\n};\n\nexport function setErrorHandler(handler: ErrorHandler) {\n errorHandler = handler;\n}\n\nexport function handleError(error: Error, methodName: string) {\n return errorHandler(error, methodName);\n}\n","/*\n The \"use client\" directive is specifically for the Next.js layout component, which is rendered on the server by default.\n Because of this, we are explicitly marking it as a client component, so we can render this component on the client\n and properly initialize config on the client side.\n \n While this is specific to Next.js, it is simply ignored outside of Next.js and should not cause errors.\n*/\n\"use client\";\n\nimport { useState, useEffect, useMemo } from 'react';\nimport { getLocalStorageSession } from './localStorage';\nimport { handleError } from './errorHandler';\n\ntype Args = Record<string, unknown>;\n\ntype MethodResult<T> = {\n isLoading: boolean;\n error: Error | null;\n data: T | null;\n};\n\nexport async function callMethod<T = unknown>(methodName: string, args: Args = {}): Promise<T> {\n try {\n return await call<T>(`/api/_internal/method/${methodName}`, args);\n } catch (error) {\n handleError(error as Error, methodName);\n throw error;\n }\n}\n\nasync function call<T = unknown>(endpoint: string, args: Args): Promise<T> {\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n args,\n authToken: getLocalStorageSession()?.authToken,\n clientInfo: {\n screenWidth: window.screen.width,\n screenHeight: window.screen.height,\n windowWidth: window.innerWidth,\n windowHeight: window.innerHeight,\n pixelRatio: window.devicePixelRatio,\n orientation: window.screen.orientation?.type\n }\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(error);\n }\n\n const text = await response.text();\n return text ? JSON.parse(text) : undefined;\n}\n\nexport function useLoader<T>(methodName: string, args: Args = {}): MethodResult<T> {\n // Memoize the args object to maintain reference stability and prevent infinite re-renders\n const stableArgs = useMemo(() => args, [JSON.stringify(args)]);\n\n const [result, setResult] = useState<MethodResult<T>>({\n isLoading: true,\n error: null,\n data: null,\n });\n\n // TODO: switch to React Query (TanStack Query)\n useEffect(() => {\n const fetchData = async () => {\n try {\n const data = await callMethod<T>(methodName, stableArgs);\n setResult({ isLoading: false, error: null, data });\n } catch (error) {\n setResult({ isLoading: false, error: error as Error, data: null });\n }\n };\n\n fetchData();\n }, [methodName, stableArgs]);\n\n return result;\n}\n","import { ConfigKey, AppConfig } from './types';\n\nlet config: Record<ConfigKey, AppConfig> = {};\n\nexport function getConfig(key: ConfigKey) {\n return config[key]?.value;\n}\n\nexport function _setConfig(configs: Record<ConfigKey, AppConfig>) {\n config = configs;\n}\n","'use client';\n\nimport { z } from 'zod';\nimport { callMethod } from './method';\nimport { ConfigKey, AppConfig } from '../config/types';\nimport { _setConfig } from '../config/client';\nimport { useState, useEffect } from 'react';\nimport { setLocalStorageSession } from './localStorage';\nimport { time } from '../time';\n\ntype Configs = Record<ConfigKey, AppConfig>;\n\nlet isInitialized = false;\nconst SESSION_HEARTBEAT_INTERVAL = time.seconds(30);\n\nlet currentUser: {\n id: string;\n handle: string;\n} | null = null;\n\nexport async function initSession() {\n if (isInitialized) {\n return;\n }\n\n isInitialized = true;\n\n const { configs, session, user } = await callMethod<{ configs: Configs, session: object, user: object }>('_system.session.init');\n _setConfig(configs);\n setLocalStorageSession(session);\n currentUser = user ? Object.freeze(z.object({\n id: z.string(),\n handle: z.string(),\n }).parse(user)) : null;\n\n await loopSessionHeartbeat();\n}\n\nasync function loopSessionHeartbeat() {\n await callMethod('_system.session.heartbeat');\n setTimeout(loopSessionHeartbeat, SESSION_HEARTBEAT_INTERVAL);\n}\n\nexport function useSession() {\n const [user, setUser] = useState(currentUser);\n\n // TODO: re-fetch the user on demand\n useEffect(() => {\n // Fetch and update currentUser\n }, []);\n\n return { user };\n}\n","/*\n The \"use client\" directive is specifically for the Next.js layout component, which is rendered on the server by default.\n Because of this, we are explicitly marking it as a client component, so we can render this component on the client\n and properly initialize config on the client side.\n \n While this is specific to Next.js, it is simply ignored outside of Next.js and should not cause errors.\n*/\n\"use client\";\n\nimport React, { useState, useEffect, ReactNode } from 'react';\nimport { initSession } from './session';\n\ninterface AppProviderProps {\n children: ReactNode;\n loadingElement?: ReactNode;\n}\n\nexport function AppProvider({ children, loadingElement }: AppProviderProps) {\n const [isLoading, setIsLoading] = useState(true);\n\n useEffect(() => {\n async function initConfig() {\n await initSession();\n setIsLoading(false);\n }\n\n initConfig();\n }, []);\n\n if (isLoading) {\n return loadingElement ?? <div>Loading...</div>;\n }\n\n return <>{children}</>;\n}\n","import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport { AppProvider } from '../client';\nimport { setErrorHandler, ErrorHandler } from './errorHandler';\n\nexport function renderApp({ loadingElement, routesElement, favicon, errorHandler }: {\n loadingElement: React.ReactNode,\n routesElement: React.ReactNode,\n favicon?: string,\n errorHandler?: ErrorHandler\n}) {\n if (errorHandler) {\n setErrorHandler(errorHandler);\n }\n\n window.addEventListener('unload', () => {\n // The presence of any 'unload' event handler, even empty,\n // prevents bfcache in most browsers\n });\n\n ReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <AppProvider loadingElement={loadingElement}>\n {routesElement}\n </AppProvider>\n </React.StrictMode>\n );\n\n if (favicon) {\n const link = document.querySelector(\"link[rel~='icon']\") as HTMLLinkElement;\n if (!link) {\n const newLink = document.createElement('link');\n newLink.rel = 'icon';\n newLink.href = favicon;\n document.head.appendChild(newLink);\n } else {\n link.href = favicon;\n }\n }\n}\n","import { callMethod } from '../../client/method';\n\nexport async function signupWithPassword({ email, password }: { email: string, password: string }) {\n return callMethod('_system.user.signupWithPassword', { email, password });\n}\n\nexport async function loginWithPassword({ email, password }: { email: string, password: string }) {\n return callMethod('_system.user.loginWithPassword', { email, password });\n}\n","import React from 'react';\n\nimport { AppProvider as OriginalAppProvider } from './client/AppProvider';\n\nexport { getConfig } from './config/client';\n\nexport const AppProvider = 'useClient' in React\n // @ts-ignore: React.useClient only exists in Next.js\n ? React.useClient(OriginalAppProvider)\n : OriginalAppProvider;\n\nexport { renderApp } from './client/renderApp';\nexport { useLoader } from './client/method';\nexport { useSession } from './client/session';\nexport { signupWithPassword, loginWithPassword } from './auth/client';\n"]}
1
+ {"version":3,"sources":["../client/localStorage.ts","../client/errorHandler.ts","../client/method.ts","../config/client.ts","../client/session.ts","../client/AppProvider.tsx","../client/renderApp.tsx","../auth/client/index.ts","../client.ts"],"names":["getLocalStorageSession","sessionJson","e","setLocalStorageSession","session","errorHandler","error","methodName","setErrorHandler","handler","handleError","callMethod","args","call","endpoint","response","text","useLoader","stableArgs","useMemo","result","setResult","useState","useEffect","data","config","getConfig","key","_setConfig","configs","isInitialized","SESSION_HEARTBEAT_INTERVAL","time","currentUser","initSession","user","z","loopSessionHeartbeat","useSession","setUser","AppProvider","children","loadingElement","isLoading","setIsLoading","initConfig","jsx","Fragment","renderApp","routesElement","favicon","ReactDOM","React","link","newLink","signupWithPassword","email","password","loginWithPassword"],"mappings":"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","file":"client.js","sourcesContent":["export function getLocalStorageSession() {\n const sessionJson = localStorage.getItem('modelence.session');\n try {\n return sessionJson ? JSON.parse(sessionJson) : null;\n } catch (e) {\n console.error('Error parsing session from localStorage', e);\n return null;\n }\n}\n\nexport function setLocalStorageSession(session: object) {\n localStorage.setItem('modelence.session', JSON.stringify(session));\n}\n","export type ErrorHandler = (error: Error, methodName: string) => void;\n\nlet errorHandler: ErrorHandler = (error, methodName) => {\n throw new Error(`Error calling method '${methodName}': ${error.toString()}`);\n};\n\nexport function setErrorHandler(handler: ErrorHandler) {\n errorHandler = handler;\n}\n\nexport function handleError(error: Error, methodName: string) {\n return errorHandler(error, methodName);\n}\n","/*\n The \"use client\" directive is specifically for the Next.js layout component, which is rendered on the server by default.\n Because of this, we are explicitly marking it as a client component, so we can render this component on the client\n and properly initialize config on the client side.\n \n While this is specific to Next.js, it is simply ignored outside of Next.js and should not cause errors.\n*/\n\"use client\";\n\nimport { useState, useEffect, useMemo } from 'react';\nimport { getLocalStorageSession } from './localStorage';\nimport { handleError } from './errorHandler';\n\ntype Args = Record<string, unknown>;\n\ntype MethodResult<T> = {\n isLoading: boolean;\n error: Error | null;\n data: T | null;\n};\n\nexport async function callMethod<T = unknown>(methodName: string, args: Args = {}): Promise<T> {\n try {\n return await call<T>(`/api/_internal/method/${methodName}`, args);\n } catch (error) {\n handleError(error as Error, methodName);\n throw error;\n }\n}\n\nasync function call<T = unknown>(endpoint: string, args: Args): Promise<T> {\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n args,\n authToken: getLocalStorageSession()?.authToken,\n clientInfo: {\n screenWidth: window.screen.width,\n screenHeight: window.screen.height,\n windowWidth: window.innerWidth,\n windowHeight: window.innerHeight,\n pixelRatio: window.devicePixelRatio,\n orientation: window.screen.orientation?.type\n }\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(error);\n }\n\n const text = await response.text();\n return text ? JSON.parse(text) : undefined;\n}\n\nexport function useLoader<T>(methodName: string, args: Args = {}): MethodResult<T> {\n // Memoize the args object to maintain reference stability and prevent infinite re-renders\n const stableArgs = useMemo(() => args, [JSON.stringify(args)]);\n\n const [result, setResult] = useState<MethodResult<T>>({\n isLoading: true,\n error: null,\n data: null,\n });\n\n // TODO: switch to React Query (TanStack Query)\n useEffect(() => {\n const fetchData = async () => {\n try {\n const data = await callMethod<T>(methodName, stableArgs);\n setResult({ isLoading: false, error: null, data });\n } catch (error) {\n setResult({ isLoading: false, error: error as Error, data: null });\n }\n };\n\n fetchData();\n }, [methodName, stableArgs]);\n\n return result;\n}\n","import { ConfigKey, AppConfig } from './types';\n\nlet config: Record<ConfigKey, AppConfig> = {};\n\nexport function getConfig(key: ConfigKey) {\n return config[key]?.value;\n}\n\nexport function _setConfig(configs: Record<ConfigKey, AppConfig>) {\n config = configs;\n}\n","'use client';\n\nimport { z } from 'zod';\nimport { callMethod } from './method';\nimport { ConfigKey, AppConfig } from '../config/types';\nimport { _setConfig } from '../config/client';\nimport { useState, useEffect } from 'react';\nimport { setLocalStorageSession } from './localStorage';\nimport { time } from '../time';\n\ntype Configs = Record<ConfigKey, AppConfig>;\n\nlet isInitialized = false;\nconst SESSION_HEARTBEAT_INTERVAL = time.seconds(30);\n\nlet currentUser: {\n id: string;\n handle: string;\n} | null = null;\n\nexport async function initSession() {\n if (isInitialized) {\n return;\n }\n\n isInitialized = true;\n\n const { configs, session, user } = await callMethod<{ configs: Configs, session: object, user: object }>('_system.session.init');\n _setConfig(configs);\n setLocalStorageSession(session);\n currentUser = user ? Object.freeze(z.object({\n id: z.string(),\n handle: z.string(),\n }).parse(user)) : null;\n\n await loopSessionHeartbeat();\n}\n\nasync function loopSessionHeartbeat() {\n await callMethod('_system.session.heartbeat');\n setTimeout(loopSessionHeartbeat, SESSION_HEARTBEAT_INTERVAL);\n}\n\nexport function useSession() {\n const [user, setUser] = useState(currentUser);\n\n // TODO: re-fetch the user on demand\n useEffect(() => {\n // Fetch and update currentUser\n }, []);\n\n return { user };\n}\n","/*\n The \"use client\" directive is specifically for the Next.js layout component, which is rendered on the server by default.\n Because of this, we are explicitly marking it as a client component, so we can render this component on the client\n and properly initialize config on the client side.\n \n While this is specific to Next.js, it is simply ignored outside of Next.js and should not cause errors.\n*/\n\"use client\";\n\nimport React, { useState, useEffect, ReactNode } from 'react';\nimport { initSession } from './session';\n\ninterface AppProviderProps {\n children: ReactNode;\n loadingElement?: ReactNode;\n}\n\nexport function AppProvider({ children, loadingElement }: AppProviderProps) {\n const [isLoading, setIsLoading] = useState(true);\n\n useEffect(() => {\n async function initConfig() {\n await initSession();\n setIsLoading(false);\n }\n\n initConfig();\n }, []);\n\n if (isLoading) {\n return loadingElement ?? <div>Loading...</div>;\n }\n\n return <>{children}</>;\n}\n","import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport { AppProvider } from '../client';\nimport { setErrorHandler, ErrorHandler } from './errorHandler';\n\nexport function renderApp({ loadingElement, routesElement, favicon, errorHandler }: {\n loadingElement: React.ReactNode,\n routesElement: React.ReactNode,\n favicon?: string,\n errorHandler?: ErrorHandler\n}) {\n if (errorHandler) {\n setErrorHandler(errorHandler);\n }\n\n window.addEventListener('unload', () => {\n // The presence of any 'unload' event handler, even empty,\n // prevents bfcache in most browsers\n });\n\n ReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <AppProvider loadingElement={loadingElement}>\n {routesElement}\n </AppProvider>\n </React.StrictMode>\n );\n\n if (favicon) {\n const link = document.querySelector(\"link[rel~='icon']\") as HTMLLinkElement;\n if (!link) {\n const newLink = document.createElement('link');\n newLink.rel = 'icon';\n newLink.href = favicon;\n document.head.appendChild(newLink);\n } else {\n link.href = favicon;\n }\n }\n}\n","import { callMethod } from '../../client/method';\n\nexport async function signupWithPassword({ email, password }: { email: string, password: string }) {\n return callMethod('_system.user.signupWithPassword', { email, password });\n}\n\nexport async function loginWithPassword({ email, password }: { email: string, password: string }) {\n return callMethod('_system.user.loginWithPassword', { email, password });\n}\n","import React from 'react';\n\nimport { AppProvider as OriginalAppProvider } from './client/AppProvider';\n\nexport { getConfig } from './config/client';\n\nexport const AppProvider = 'useClient' in React\n // @ts-ignore: React.useClient only exists in Next.js\n ? React.useClient(OriginalAppProvider)\n : OriginalAppProvider;\n\nexport { renderApp } from './client/renderApp';\nexport { useLoader, callMethod } from './client/method';\nexport { useSession } from './client/session';\nexport { signupWithPassword, loginWithPassword } from './auth/client';\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "modelence",
4
- "version": "0.1.7",
4
+ "version": "0.1.8",
5
5
  "description": "Full-stack JavaScript platform for startups",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",