@joystick.js/node-canary 0.0.0-canary.377 → 0.0.0-canary.379

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.
@@ -1 +1 @@
1
- import a from"../databases/queries/accounts.js";import n from"./generate_password_reset_token.js";import i from"../settings/load.js";import d from"../email/send.js";import r from"../../lib/types.js";const c=i(),m=(e="")=>a("get_password_reset_token",{user_id:e}),l=(e="")=>a("user",{email_address:e}),u=async(e={})=>{const s=await l(e?.email_address||e?.emailAddress);if(!s)throw new Error(`A user with the email address ${e?.email_address||e?.emailAddress} could not be found.`);const o=await m(s?._id||s?.user_id)||await n(e.email_address||e.emailAddress),t=`${process.env.ROOT_URL||`http://localhost:${process.env.PORT}`}/reset-password/${o}`;return process.env.NODE_ENV==="development"&&console.log(`Reset Password URL: ${t}`),(r.is_function(process.joystick?.app_options?.accounts?.events?.onRecoverPassword)||r.is_function(process.joystick?.app_options?.accounts?.events?.on_recover_password))&&(process.joystick?.app_options?.accounts?.events?.onRecoverPassword||process.joystick?.app_options?.accounts?.events?.on_recover_password)(e?.email_address||e?.emailAddress),await d({to:e.email_address||e?.emailAddress,from:c?.config?.email?.from,subject:"Reset Your Password",template:"reset_password",props:{email_address:e.email_address||e?.emailAddress,url:t}}),!0};var y=u;export{y as default};
1
+ import o from"../databases/queries/accounts.js";import n from"./generate_password_reset_token.js";import i from"../settings/load.js";import d from"../email/send.js";import r from"../../lib/types.js";const c=i(),m=(e="")=>o("get_password_reset_token",{user_id:e}),l=(e="")=>o("user",{email_address:e}),u=async(e={})=>{const s=await l(e?.email_address||e?.emailAddress);if(!s)throw new Error(`A user with the email address ${e?.email_address||e?.emailAddress} could not be found.`);const t=await m(s?._id||s?.user_id)||await n(e.email_address||e.emailAddress),a=`${process.env.ROOT_URL||`http://localhost:${process.env.PORT}`}/reset-password/${t}`;return process.env.NODE_ENV==="development"&&console.log(`Reset Password URL: ${a}`),(r.is_function(process.joystick?.app_options?.accounts?.events?.onRecoverPassword)||r.is_function(process.joystick?.app_options?.accounts?.events?.on_recover_password))&&(process.joystick?.app_options?.accounts?.events?.onRecoverPassword||process.joystick?.app_options?.accounts?.events?.on_recover_password)(e?.email_address||e?.emailAddress),await d({to:e.email_address||e?.emailAddress,from:c?.config?.email?.from,subject:"Reset Your Password",template:"reset_password",props:{email_address:e.email_address||e?.emailAddress,url:a}}),t};var y=u;export{y as default};
@@ -1 +1 @@
1
- var i=null,c=0,l=(t={},e=null)=>{let o=new WebSocket(`ws://localhost:${window.__joystick_hmr_port__}/_joystick/hmr?${new URLSearchParams(t.query).toString()}`);i&&(clearInterval(i),i=null);let _={client:o,send:(n={})=>(t.queryParams&&(n={...n,...t.queryParams}),o.send(JSON.stringify(n)))};return o.addEventListener("open",()=>{console.log("[hmr] Listening for changes..."),c=0,e&&e(_)}),o.addEventListener("message",n=>{n?.data&&t.onMessage&&t.onMessage(JSON.parse(n.data),_)}),o.addEventListener("close",()=>{console.log("[hmr] Disconnected from server."),o=null,t.autoReconnect&&!i&&(i=setInterval(()=>{o=null,c<12?(l(t,e),console.log(`[hmr] Attempting to reconnect (${c+1}/12)...`),c+=1):(console.log("[hmr] Reconnection attempts exhausted. Server is unavailable."),clearInterval(i))},5e3))}),_},u=async()=>{let t=await d();window.joystick.mount(t,Object.assign({},window.__joystick_ssr_props__),document.getElementById("app"))},d=async()=>(await import(`${window.__joystick_page_url__}?v=${new Date().getTime()}`).catch(e=>{location.reload()}))?.default,p=async()=>(await import(`${window.__joystick_layout_url__}?v=${new Date().getTime()}`).catch(e=>{location.reload()}))?.default,y=async()=>{let t=await p(),e=await d();window.joystick.mount(t,Object.assign({page:e},window.__joystick_ssr_props__),document.getElementById("app"))},w=t=>{let e=document.createElement("link");e.setAttribute("rel","stylesheet"),e.setAttribute("href","/_joystick/index.css"),document.head.replaceChild(e,t)},g=(t={})=>{let e=document.createElement("script");e.setAttribute("type","text/javascript"),e.setAttribute("src","/_joystick/index.client.js"),t.parentNode.replaceChild(e,t)},j=l({autoReconnect:!0,query:{user_language:window?.__joystick_user__?.language||"",browser_language:navigator?.language||"",page_component_path:window.__joystick_page_url__?.replace("/_joystick/","")},onMessage:async(t={},e={})=>{if(console.log("HMR",t),t&&t.type&&t.type==="BUILD_ERROR")return location.reload();window.__joystick_hmr_update__=!0,window.__joystick_hmr_previous_tree__=[...window.joystick._internal.tree||[]],window.__joystick_hmr_previous_websockets__=[...window.joystick._internal.websockets||[]];let _=Object.assign({},{scrollTop:window.scrollY}),n=t&&t.type&&t.type==="FILE_CHANGE",r=!!window.__joystick_layout_url__&&!!window.__joystick_page_url__,s=document.head.querySelector('link[href="/_joystick/index.css"]'),a=document.body.querySelector('script[src="/_joystick/index.client.js"]');t?.index_html_changed&&location.reload(),t?.i18n&&(window.__joystick_i18n__=t?.i18n),t?.settings&&(window.__joystick_settings__=t?.settings,window.joystick.settings=t?.settings),a&&t?.index_client_changed&&g(a),s&&t?.index_css_changed&&w(s),n&&r&&y(e),n&&!r&&u(e),window.scrollTo(0,_.scrollTop),e.send&&e.send({type:"HMR_UPDATE_COMPLETE"})}}),m=j;export{m as default};
1
+ var i=null,c=0,l=(t={},e=null)=>{let o=new WebSocket(`ws://localhost:${window.__joystick_hmr_port__}/_joystick/hmr?${new URLSearchParams(t.query).toString()}`);i&&(clearInterval(i),i=null);let _={client:o,send:(n={})=>(t.queryParams&&(n={...n,...t.queryParams}),o.send(JSON.stringify(n)))};return o.addEventListener("open",()=>{console.log("[hmr] Listening for changes..."),c=0,e&&e(_)}),o.addEventListener("message",n=>{n?.data&&t.onMessage&&t.onMessage(JSON.parse(n.data),_)}),o.addEventListener("close",()=>{console.log("[hmr] Disconnected from server."),o=null,t.autoReconnect&&!i&&(i=setInterval(()=>{o=null,c<12?(l(t,e),console.log(`[hmr] Attempting to reconnect (${c+1}/12)...`),c+=1):(console.log("[hmr] Reconnection attempts exhausted. Server is unavailable."),clearInterval(i))},5e3))}),_},u=async()=>{let t=await d();window.joystick.mount(t,Object.assign({},window.__joystick_ssr_props__),document.getElementById("app"))},d=async()=>(await import(`${window.__joystick_page_url__}?v=${new Date().getTime()}`).catch(e=>{location.reload()}))?.default,p=async()=>(await import(`${window.__joystick_layout_url__}?v=${new Date().getTime()}`).catch(e=>{location.reload()}))?.default,y=async()=>{let t=await p(),e=await d();window.joystick.mount(t,Object.assign({page:e},window.__joystick_ssr_props__),document.getElementById("app"))},w=t=>{let e=document.createElement("link");e.setAttribute("rel","stylesheet"),e.setAttribute("href","/_joystick/index.css"),document.head.replaceChild(e,t)},g=(t={})=>{let e=document.createElement("script");e.setAttribute("type","text/javascript"),e.setAttribute("src","/_joystick/index.client.js"),t.parentNode.replaceChild(e,t)},j=l({autoReconnect:!0,query:{user_language:window?.__joystick_user__?.language||"",browser_language:navigator?.language||"",page_component_path:window.__joystick_page_url__?.replace("/_joystick/","")},onMessage:async(t={},e={})=>{if(console.log("WEBSOCKET MESSAGE",{message:t,websocket_client_connection:e}),t&&t.type&&t.type==="BUILD_ERROR")return location.reload();window.__joystick_hmr_update__=!0,window.__joystick_hmr_previous_tree__=[...window.joystick._internal.tree||[]],window.__joystick_hmr_previous_websockets__=[...window.joystick._internal.websockets||[]];let _=Object.assign({},{scrollTop:window.scrollY}),n=t&&t.type&&t.type==="FILE_CHANGE",r=!!window.__joystick_layout_url__&&!!window.__joystick_page_url__,s=document.head.querySelector('link[href="/_joystick/index.css"]'),a=document.body.querySelector('script[src="/_joystick/index.client.js"]');t?.index_html_changed&&location.reload(),t?.i18n&&(window.__joystick_i18n__=t?.i18n),t?.settings&&(window.__joystick_settings__=t?.settings,window.joystick.settings=t?.settings),a&&t?.index_client_changed&&g(a),s&&t?.index_css_changed&&w(s),n&&r&&y(e),n&&!r&&u(e),window.scrollTo(0,_.scrollTop),e.send&&e.send({type:"HMR_UPDATE_COMPLETE"})}}),m=j;export{m as default};
@@ -1 +1 @@
1
- import t from"../../../lib/types.js";const o=async(r="",e="",_=[])=>process.databases._users?.query(`CREATE UNIQUE INDEX IF NOT EXISTS ${r} ON ${e}(${_.join(", ")})`),s=async(r="",e="",_=[])=>process.databases._users?.query(`CREATE INDEX IF NOT EXISTS ${r} ON ${e}(${_.join(", ")})`),a={sessions:async()=>{await s("session_by_id","sessions",["session_id"]),await s("session_created_at","sessions",["created_at"])},users:async()=>{await s("user_by_email","users",["email_address"]),await s("user_by_username","users",["username"]),await s("user_by_user_id","users",["user_id"]),await s("user_session_by_token","users_sessions",["token"]),await s("user_password_reset_token_by_token","users_password_reset_tokens",["token"]),await s("user_password_reset_token_by_user_id_token","users_password_reset_tokens",["user_id","token"]),await s("user_role","users_roles",["role"]),await s("user_roles_by_user_id_role","users_roles",["user_id","role"]),await s("role","roles",["role"]),await o("user_roles","users_roles",["user_id","role"])}},i=async(r=[])=>{for(let e=0;e<r?.length;e+=1){const _=r[e];t.is_function(a[_])&&await a[_]()}};var u=i;export{u as default};
1
+ import o from"node-cron";import t from"../../../lib/types.js";import i from"./handle_cleanup_sessions.js";const n=async(r="",e="",_=[])=>process.databases._users?.query(`CREATE UNIQUE INDEX IF NOT EXISTS ${r} ON ${e}(${_.join(", ")})`),s=async(r="",e="",_=[])=>process.databases._users?.query(`CREATE INDEX IF NOT EXISTS ${r} ON ${e}(${_.join(", ")})`),a={sessions:async()=>{await s("session_by_id","sessions",["session_id"]),await s("session_created_at","sessions",["created_at"]),o.schedule("*/30 * * * * *",()=>{i()})},users:async()=>{await s("user_by_email","users",["email_address"]),await s("user_by_username","users",["username"]),await s("user_by_user_id","users",["user_id"]),await s("user_session_by_token","users_sessions",["token"]),await s("user_password_reset_token_by_token","users_password_reset_tokens",["token"]),await s("user_password_reset_token_by_user_id_token","users_password_reset_tokens",["user_id","token"]),await s("user_role","users_roles",["role"]),await s("user_roles_by_user_id_role","users_roles",["user_id","role"]),await s("role","roles",["role"]),await n("user_roles","users_roles",["user_id","role"])}},u=async(r=[])=>{for(let e=0;e<r?.length;e+=1){const _=r[e];t.is_function(a[_])&&await a[_]()}};var w=u;export{w as default};
@@ -0,0 +1 @@
1
+ const e=async()=>{await database.query("DELETE FROM sessions where created_at::timestamp <= timezone('utc', now() - interval '1 hour')")};var a=e;export{a as default};
@@ -1 +1 @@
1
- import n from"../../lib/types.js";const o=(a,i,l,t=null)=>{if(t&&n.is_object(t)){const e={"default-src":["'self'"],"child-src":["'self'"],"connect-src":["'self'","wss:"],"font-src":["'self'"],"frame-src":["'self'"],"img-src":["'self'"],"manifest-src":["'self'"],"media-src":["'self'"],"object-src":["'self'"],"script-src":["'self'"],"script-src-elem":["'self'"],"script-src-attr":["'self'"],"style-src":["'self'"],"style-src-elem":["'self'"],"style-src-attr":["'self'"],"worker-src":["'self'"],"base-uri":["'self'"],"navigate-to":["'self'"],"form-action":["'self'"]};process.env.NODE_ENV==="development"&&(e["script-src"].push("'unsafe-eval'"),e["connect-src"].push("ws:"));const r=Object.keys(e||{});for(let s=0;s<r?.length;s+=1){const c=r[s];e[c]=[...e[c]||[],...config?.unrestrictedOrigins||[],...config?.directives&&config?.directives[c]||[]]}const f=Object.keys(e||{}).map(s=>`${s} ${e[s].join(" ")}`)?.join("; ");i.setHeader("Content-Security-Policy",f)}l()};var m=o;export{m as default};
1
+ import n from"../../lib/types.js";const o=(a,l,i,s=null)=>{if(s&&n.is_object(s)){const e={"base-uri":["'self'"],"child-src":["'self'"],"connect-src":["'self'","wss:"],"default-src":["'self'"],"font-src":["'self'"],"form-action":["'self'"],"frame-src":["'self'"],"img-src":["'self'"],"manifest-src":["'self'"],"media-src":["'self'"],"navigate-to":["'self'"],"object-src":["'self'"],"script-src":["'self'"],"script-src-attr":["'self'"],"script-src-elem":["'self'"],"style-src":["'self'"],"style-src-attr":["'self'"],"style-src-elem":["'self'"],"worker-src":["'self'"]};process.env.NODE_ENV==="development"&&(e["script-src"].push("'unsafe-eval'"),e["connect-src"].push("ws:"));const c=Object.keys(e||{});for(let r=0;r<c?.length;r+=1){const t=c[r];e[t]=[...e[t]||[],...s?.unrestrictedOrigins||s?.unrestricted_origins||[],...s?.directives&&s?.directives[t]||[]]}const f=Object.keys(e||{}).map(r=>`${r} ${e[r].join(" ")}`)?.join("; ");l.setHeader("Content-Security-Policy",f)}i()};var m=o;export{m as default};
@@ -1 +1 @@
1
- import o from"fs";import p from"./dynamic_import.js";import _ from"../app/settings/load.js";import h from"./path_exists.js";import g from"./types.js";const d=_(),m=async(r="",a="",s="")=>{const t=await p(`${a}/i18n/${r}?v=${new Date().getTime()}`);if(t&&g.is_object(t)){const e=t[s];return e||t}return{}},$=(r="",a=[],s="")=>{let t=[];r&&t.push(r);const n=a?.filter(e=>!e?.includes("*"));return t.push(...n),t.push(d?.config?.i18n?.defaultLanguage),t?.flatMap(e=>{const i=[e];return e?.length===2&&i.push(`${e.substring(0,2)}-`),e?.length>2&&(i.push(`${e?.split("-")[0]}`),i.push(`${e?.split("-")[0]}-`)),i})?.map(e=>e[e.length-1]==="-"?new RegExp(s?`^${s}_${e}[A-Z]+.js`:`^${e}[A-Z]+.js`,"g"):new RegExp(s?`^${s}_${e}.js`:`^${e}.js`,"g"))},w=(r="")=>r.split(",")?.map(s=>s.split(";")[0]),b=async(r={})=>{const a=r?.is_email?`${r?.joystick_build_path}i18n/email`:`${r?.joystick_build_path}i18n`,s=await h(a)&&o.readdirSync(a)||[],t=r?.is_email?[]:w(r?.req?.headers["accept-language"]),n=$(r?.req?.context?.user?.language,t,r?.email_template_name);let e=null;for(let c=0;c<n.length;c+=1){const f=n[c],l=s.find(u=>!!u.match(f));if(l){e=l;break}}return(e?await m(e,r?.joystick_build_path,r?.render_component_path):null)||{}};var q=b;export{q as default};
1
+ import g from"fs";import p from"./dynamic_import.js";import _ from"../app/settings/load.js";import h from"./path_exists.js";import d from"./types.js";const c=_(),m=async(t="",n="",a="")=>{const r=await p(`${n}/i18n/${t}?v=${new Date().getTime()}`);if(r&&d.is_object(r)){const e=r[a];return e||r}return{}},$=(t="",n=[],a="")=>{let r=[];t&&r.push(t);const i=n?.filter(e=>!e?.includes("*"));return r.push(...i),(c?.config?.i18n?.defaultLanguage||c?.config?.i18n?.default_language)&&r.push(c?.config?.i18n?.defaultLanguage||c?.config?.i18n?.default_language),r?.flatMap(e=>{const s=[e];return e?.length===2&&s.push(`${e.substring(0,2)}-`),e?.length>2&&(s.push(`${e?.split("-")[0]}`),s.push(`${e?.split("-")[0]}-`)),s})?.map(e=>e[e.length-1]==="-"?new RegExp(a?`^${a}_${e}[A-Z]+.js`:`^${e}[A-Z]+.js`,"g"):new RegExp(a?`^${a}_${e}.js`:`^${e}.js`,"g"))},w=(t="")=>t.split(",")?.map(a=>a.split(";")[0]),b=async(t={})=>{const n=t?.is_email?`${t?.joystick_build_path}i18n/email`:`${t?.joystick_build_path}i18n`,a=await h(n)&&g.readdirSync(n)||[],r=t?.is_email?[]:w(t?.req?.headers["accept-language"]),i=$(t?.req?.context?.user?.language,r,t?.email_template_name);let e=null;for(let l=0;l<i.length;l+=1){const u=i[l],f=a.find(o=>!!o.match(u));if(f){e=f;break}}return(e?await m(e,t?.joystick_build_path,t?.render_component_path):null)||{}};var q=b;export{q as default};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@joystick.js/node-canary",
3
3
  "type": "module",
4
- "version": "0.0.0-canary.377",
4
+ "version": "0.0.0-canary.379",
5
5
  "description": "The Node.js framework for Joystick.",
6
6
  "main": "./dist/index.js",
7
7
  "scripts": {
@@ -52,7 +52,7 @@ const recover_password = async (recover_password_options = {}) => {
52
52
  },
53
53
  });
54
54
 
55
- return true;
55
+ return reset_token;
56
56
  };
57
57
 
58
58
  export default recover_password;
@@ -136,7 +136,7 @@ const hmr_client = (() =>
136
136
  page_component_path: window.__joystick_page_url__?.replace('/_joystick/', ''),
137
137
  },
138
138
  onMessage: async (message = {}, websocket_client_connection = {}) => {
139
- console.log('HMR', message);
139
+ console.log('WEBSOCKET MESSAGE', { message, websocket_client_connection });
140
140
  const is_build_error = message && message.type && message.type === "BUILD_ERROR";
141
141
 
142
142
  if (is_build_error) {
@@ -1,4 +1,6 @@
1
+ import cron from 'node-cron';
1
2
  import types from "../../../lib/types.js";
3
+ import handle_cleanup_sessions from "./handle_cleanup_sessions.js";
2
4
 
3
5
  const create_unique_index = async (index_name = '', table_name = '', table_columns = []) => {
4
6
  return process.databases._users?.query(`CREATE UNIQUE INDEX IF NOT EXISTS ${index_name} ON ${table_name}(${table_columns.join(', ')})`);
@@ -15,6 +17,11 @@ const indexes = {
15
17
  sessions: async () => {
16
18
  await create_index('session_by_id', 'sessions', ['session_id']);
17
19
  await create_index('session_created_at', 'sessions', ['created_at']);
20
+
21
+ // NOTE: Simulate a TTL index using cron to wipe out sessions older than 1 hour.
22
+ cron.schedule('*/30 * * * * *', () => {
23
+ handle_cleanup_sessions();
24
+ });
18
25
  },
19
26
  users: async () => {
20
27
  // users
@@ -0,0 +1,5 @@
1
+ const handle_cleanup_sessions = async () => {
2
+ await database.query(`DELETE FROM sessions where created_at::timestamp <= timezone('utc', now() - interval '1 hour')`);
3
+ };
4
+
5
+ export default handle_cleanup_sessions;
@@ -4,25 +4,25 @@ const csp_middleware = (_req, res, next, csp_config = null) => {
4
4
  if (csp_config && types.is_object(csp_config)) {
5
5
  // NOTE: Redefine for each request so it doesn't get stuck in memory.
6
6
  const directive_defaults = {
7
- 'default-src': ["'self'"],
7
+ 'base-uri': ["'self'"],
8
8
  'child-src': ["'self'"],
9
9
  'connect-src': ["'self'", "wss:"],
10
+ 'default-src': ["'self'"],
10
11
  'font-src': ["'self'"],
12
+ 'form-action': ["'self'"],
11
13
  'frame-src': ["'self'"],
12
14
  'img-src': ["'self'"],
13
15
  'manifest-src': ["'self'"],
14
16
  'media-src': ["'self'"],
17
+ 'navigate-to': ["'self'"],
15
18
  'object-src': ["'self'"],
16
19
  'script-src': ["'self'"],
17
- 'script-src-elem': ["'self'"],
18
20
  'script-src-attr': ["'self'"],
21
+ 'script-src-elem': ["'self'"],
19
22
  'style-src': ["'self'"],
20
- 'style-src-elem': ["'self'"],
21
23
  'style-src-attr': ["'self'"],
24
+ 'style-src-elem': ["'self'"],
22
25
  'worker-src': ["'self'"],
23
- 'base-uri': ["'self'"],
24
- 'navigate-to': ["'self'"],
25
- 'form-action': ["'self'"],
26
26
  };
27
27
 
28
28
  if (process.env.NODE_ENV === "development") {
@@ -36,8 +36,8 @@ const csp_middleware = (_req, res, next, csp_config = null) => {
36
36
  const directive = directive_names[i];
37
37
  directive_defaults[directive] = [
38
38
  ...(directive_defaults[directive] || []),
39
- ...(config?.unrestrictedOrigins || []),
40
- ...((config?.directives && config?.directives[directive]) || []),
39
+ ...(csp_config?.unrestrictedOrigins || csp_config?.unrestricted_origins || []),
40
+ ...((csp_config?.directives && csp_config?.directives[directive]) || []),
41
41
  ];
42
42
  }
43
43
 
@@ -30,7 +30,13 @@ const get_language_preference_regexes = (user_language = '', browser_languages =
30
30
  });
31
31
 
32
32
  language_preferences.push(...filtered_browser_languages);
33
- language_preferences.push(settings?.config?.i18n?.defaultLanguage);
33
+
34
+ if (settings?.config?.i18n?.defaultLanguage || settings?.config?.i18n?.default_language) {
35
+ language_preferences.push(
36
+ settings?.config?.i18n?.defaultLanguage ||
37
+ settings?.config?.i18n?.default_language
38
+ );
39
+ }
34
40
 
35
41
  return language_preferences?.flatMap((language) => {
36
42
  const variants = [language];