@lunora/auth 1.0.0-alpha.37 → 1.0.0-alpha.39

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.
Files changed (35) hide show
  1. package/dist/adapter.mjs +1 -48
  2. package/dist/audit.mjs +2 -102
  3. package/dist/email-guard.mjs +1 -71
  4. package/dist/index.d.mts +2 -2
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.mjs +1 -16
  7. package/dist/middleware.d.mts +1 -1
  8. package/dist/middleware.d.ts +1 -1
  9. package/dist/middleware.mjs +1 -56
  10. package/dist/packem_shared/DEFAULT_AUTH_BASE_PATH-kIwlEt8i.mjs +1 -0
  11. package/dist/packem_shared/LunoraAuthAdminError-BiNYZM9j.mjs +1 -0
  12. package/dist/packem_shared/authAuditHook-Dx3sqf3G.mjs +1 -0
  13. package/dist/packem_shared/compileMigrationsSql-ChiudSmt.mjs +1 -0
  14. package/dist/packem_shared/{create-auth.d-COcIS_KU.d.mts → create-auth.d-De6IOirt.d.mts} +1 -1
  15. package/dist/packem_shared/{create-auth.d-COcIS_KU.d.ts → create-auth.d-De6IOirt.d.ts} +1 -1
  16. package/dist/packem_shared/createAuth-DS6PL8Mb.mjs +1 -0
  17. package/dist/packem_shared/emailGateDatabaseHooks-DzBD1Qoq.mjs +1 -0
  18. package/dist/packem_shared/sessionPresets-DpEFjXKV.mjs +1 -0
  19. package/dist/plugins-client.mjs +1 -2
  20. package/dist/plugins.mjs +1 -22
  21. package/dist/schema.d.mts +1 -1
  22. package/dist/schema.d.ts +1 -1
  23. package/dist/schema.mjs +1 -62
  24. package/dist/sql-store.mjs +1 -184
  25. package/dist/store.mjs +1 -183
  26. package/dist/turnstile-middleware.mjs +1 -34
  27. package/dist/turnstile.mjs +1 -59
  28. package/package.json +2 -2
  29. package/dist/packem_shared/DEFAULT_AUTH_BASE_PATH-DjcUWEQl.mjs +0 -11
  30. package/dist/packem_shared/LunoraAuthAdminError-CReJPMkx.mjs +0 -513
  31. package/dist/packem_shared/authAuditHook-3OJKhpQV.mjs +0 -119
  32. package/dist/packem_shared/compileMigrationsSql-Dl5N8z5q.mjs +0 -29
  33. package/dist/packem_shared/createAuth-s4i7WhAh.mjs +0 -72
  34. package/dist/packem_shared/emailGateDatabaseHooks-BGS4uJM9.mjs +0 -64
  35. package/dist/packem_shared/sessionPresets-Dwwd74_J.mjs +0 -38
@@ -1,184 +1 @@
1
- const quoteId = (name) => `"${name.replaceAll('"', '""')}"`;
2
- const NEVER = { params: [], sql: "0" };
3
- const sided = (column, insensitive) => insensitive ? { column: `LOWER(${column})`, placeholder: "LOWER(?)" } : { column, placeholder: "?" };
4
- const patternFragment = (column, value, operator, insensitive) => {
5
- if (typeof value !== "string") {
6
- return NEVER;
7
- }
8
- const side = sided(column, insensitive);
9
- if (operator === "contains") {
10
- return { params: [value], sql: `instr(${side.column}, ${side.placeholder}) > 0` };
11
- }
12
- if (operator === "starts_with") {
13
- return { params: [value], sql: `instr(${side.column}, ${side.placeholder}) = 1` };
14
- }
15
- return { params: [value, value], sql: `substr(${side.column}, -length(?)) = ${side.placeholder}` };
16
- };
17
- const equalityFragment = (column, value, insensitive, negated) => {
18
- if (value === null) {
19
- return { params: [], sql: `${column} IS ${negated ? "NOT " : ""}NULL` };
20
- }
21
- const side = sided(column, insensitive);
22
- const symbol = negated ? "<>" : "=";
23
- return { params: [value], sql: `${side.column} ${symbol} ${side.placeholder}` };
24
- };
25
- const inFragment = (column, value, negated, insensitive) => {
26
- const values = Array.isArray(value) ? value : [];
27
- if (values.length === 0) {
28
- return { params: [], sql: negated ? "1" : "0" };
29
- }
30
- const side = sided(column, insensitive);
31
- const placeholders = values.map(() => side.placeholder).join(", ");
32
- return { params: [...values], sql: `${side.column} ${negated ? "NOT IN" : "IN"} (${placeholders})` };
33
- };
34
- const compileClause = (clause) => {
35
- const column = quoteId(clause.field);
36
- const { mode, operator, value } = clause;
37
- const insensitive = mode === "insensitive";
38
- switch (operator) {
39
- case "contains":
40
- case "ends_with":
41
- case "starts_with": {
42
- return patternFragment(column, value, operator, insensitive);
43
- }
44
- case "gt": {
45
- return { params: [value], sql: `${column} > ?` };
46
- }
47
- case "gte": {
48
- return { params: [value], sql: `${column} >= ?` };
49
- }
50
- case "in": {
51
- return inFragment(column, value, false, insensitive);
52
- }
53
- case "lt": {
54
- return { params: [value], sql: `${column} < ?` };
55
- }
56
- case "lte": {
57
- return { params: [value], sql: `${column} <= ?` };
58
- }
59
- case "ne": {
60
- return equalityFragment(column, value, insensitive, true);
61
- }
62
- case "not_in": {
63
- return inFragment(column, value, true, insensitive);
64
- }
65
- // "eq" and the default: null-aware equality.
66
- default: {
67
- return equalityFragment(column, value, insensitive, false);
68
- }
69
- }
70
- };
71
- const compileWhere = (where) => {
72
- if (where.length === 0) {
73
- return { params: [], sql: "" };
74
- }
75
- let accumulator = compileClause(where[0]);
76
- for (const clause of where.slice(1)) {
77
- const fragment = compileClause(clause);
78
- const connector = clause.connector === "OR" ? "OR" : "AND";
79
- accumulator = { params: [...accumulator.params, ...fragment.params], sql: `(${accumulator.sql} ${connector} ${fragment.sql})` };
80
- }
81
- return accumulator;
82
- };
83
- const whereSuffix = (fragment) => fragment.sql ? ` WHERE ${fragment.sql}` : "";
84
- const createSqlAuthStore = (executor) => {
85
- const selectRows = (model, where) => {
86
- const fragment = compileWhere(where);
87
- return executor.all(`SELECT * FROM ${quoteId(model)}${whereSuffix(fragment)}`, fragment.params);
88
- };
89
- return {
90
- consumeOne: async (model, where) => {
91
- const fragment = compileWhere(where);
92
- const table = quoteId(model);
93
- const [row] = await executor.all(
94
- `DELETE FROM ${table} WHERE rowid IN (SELECT rowid FROM ${table}${whereSuffix(fragment)} LIMIT 1) RETURNING *`,
95
- fragment.params
96
- );
97
- return row;
98
- },
99
- count: async (model, where) => {
100
- const fragment = compileWhere(where);
101
- const [row] = await executor.all(`SELECT COUNT(*) AS __count FROM ${quoteId(model)}${whereSuffix(fragment)}`, fragment.params);
102
- return Number(row?.["__count"] ?? 0);
103
- },
104
- create: async (model, data) => {
105
- const columns = Object.keys(data);
106
- const placeholders = columns.map(() => "?").join(", ");
107
- const sql = `INSERT INTO ${quoteId(model)} (${columns.map((column) => quoteId(column)).join(", ")}) VALUES (${placeholders})`;
108
- await executor.run(
109
- sql,
110
- columns.map((column) => data[column])
111
- );
112
- return { ...data };
113
- },
114
- incrementOne: async (model, where, increment, set) => {
115
- const table = quoteId(model);
116
- const incrementColumns = Object.keys(increment);
117
- const setColumns = set ? Object.keys(set) : [];
118
- const fragment = compileWhere(where);
119
- if (incrementColumns.length === 0 && setColumns.length === 0) {
120
- const [row2] = await executor.all(`SELECT * FROM ${table}${whereSuffix(fragment)} LIMIT 1`, fragment.params);
121
- return row2;
122
- }
123
- const assignments = [
124
- // COALESCE(col, 0) so a NULL counter advances from 0 rather than staying
125
- // NULL (`NULL + ? = NULL` in SQLite/D1) — matches the memory store, which
126
- // treats a non-numeric/absent counter as 0.
127
- ...incrementColumns.map((column) => `${quoteId(column)} = COALESCE(${quoteId(column)}, 0) + ?`),
128
- ...setColumns.map((column) => `${quoteId(column)} = ?`)
129
- ].join(", ");
130
- const [row] = await executor.all(
131
- `UPDATE ${table} SET ${assignments} WHERE rowid IN (SELECT rowid FROM ${table}${whereSuffix(fragment)} LIMIT 1) RETURNING *`,
132
- [...incrementColumns.map((column) => increment[column]), ...setColumns.map((column) => set[column]), ...fragment.params]
133
- );
134
- return row;
135
- },
136
- read: async (model, query) => {
137
- const fragment = compileWhere(query.where);
138
- const parameters = [...fragment.params];
139
- let sql = `SELECT * FROM ${quoteId(model)}${whereSuffix(fragment)}`;
140
- if (query.sortBy) {
141
- sql += ` ORDER BY ${quoteId(query.sortBy.field)} ${query.sortBy.direction === "asc" ? "ASC" : "DESC"}`;
142
- }
143
- if (query.limit !== void 0) {
144
- sql += " LIMIT ?";
145
- parameters.push(Math.trunc(query.limit));
146
- }
147
- if (query.offset) {
148
- sql += `${query.limit === void 0 ? " LIMIT -1" : ""} OFFSET ?`;
149
- parameters.push(Math.trunc(query.offset));
150
- }
151
- return executor.all(sql, parameters);
152
- },
153
- remove: async (model, where) => {
154
- const fragment = compileWhere(where);
155
- const deleted = await executor.all(`DELETE FROM ${quoteId(model)}${whereSuffix(fragment)} RETURNING *`, fragment.params);
156
- return deleted.length;
157
- },
158
- update: async (model, where, values) => {
159
- const columns = Object.keys(values);
160
- if (columns.length === 0) {
161
- return selectRows(model, where);
162
- }
163
- const assignments = columns.map((column) => `${quoteId(column)} = ?`).join(", ");
164
- const fragment = compileWhere(where);
165
- return executor.all(`UPDATE ${quoteId(model)} SET ${assignments}${whereSuffix(fragment)} RETURNING *`, [
166
- ...columns.map((column) => values[column]),
167
- ...fragment.params
168
- ]);
169
- }
170
- };
171
- };
172
- const d1Executor = (database) => {
173
- return {
174
- all: async (sql, parameters) => {
175
- const result = await database.prepare(sql).bind(...parameters).all();
176
- return result.results ?? [];
177
- },
178
- run: async (sql, parameters) => {
179
- await database.prepare(sql).bind(...parameters).run();
180
- }
181
- };
182
- };
183
-
184
- export { createSqlAuthStore, d1Executor };
1
+ const c=r=>`"${r.replaceAll('"','""')}"`,I={params:[],sql:"0"},E=(r,e)=>e?{column:`LOWER(${r})`,placeholder:"LOWER(?)"}:{column:r,placeholder:"?"},N=(r,e,s,n)=>{if(typeof e!="string")return I;const a=E(r,n);return s==="contains"?{params:[e],sql:`instr(${a.column}, ${a.placeholder}) > 0`}:s==="starts_with"?{params:[e],sql:`instr(${a.column}, ${a.placeholder}) = 1`}:{params:[e,e],sql:`substr(${a.column}, -length(?)) = ${a.placeholder}`}},R=(r,e,s,n)=>{if(e===null)return{params:[],sql:`${r} IS ${n?"NOT ":""}NULL`};const a=E(r,s),t=n?"<>":"=";return{params:[e],sql:`${a.column} ${t} ${a.placeholder}`}},T=(r,e,s,n)=>{const a=Array.isArray(e)?e:[];if(a.length===0)return{params:[],sql:s?"1":"0"};const t=E(r,n),l=a.map(()=>t.placeholder).join(", ");return{params:[...a],sql:`${t.column} ${s?"NOT IN":"IN"} (${l})`}},d=r=>{const e=c(r.field),{mode:s,operator:n,value:a}=r,t=s==="insensitive";switch(n){case"contains":case"ends_with":case"starts_with":return N(e,a,n,t);case"gt":return{params:[a],sql:`${e} > ?`};case"gte":return{params:[a],sql:`${e} >= ?`};case"in":return T(e,a,!1,t);case"lt":return{params:[a],sql:`${e} < ?`};case"lte":return{params:[a],sql:`${e} <= ?`};case"ne":return R(e,a,t,!0);case"not_in":return T(e,a,!0,t);default:return R(e,a,t,!1)}},p=r=>{if(r.length===0)return{params:[],sql:""};let e=d(r[0]);for(const s of r.slice(1)){const n=d(s),a=s.connector==="OR"?"OR":"AND";e={params:[...e.params,...n.params],sql:`(${e.sql} ${a} ${n.sql})`}}return e},$=r=>r.sql?` WHERE ${r.sql}`:"",f=r=>{const e=(s,n)=>{const a=p(n);return r.all(`SELECT * FROM ${c(s)}${$(a)}`,a.params)};return{consumeOne:async(s,n)=>{const a=p(n),t=c(s),[l]=await r.all(`DELETE FROM ${t} WHERE rowid IN (SELECT rowid FROM ${t}${$(a)} LIMIT 1) RETURNING *`,a.params);return l},count:async(s,n)=>{const a=p(n),[t]=await r.all(`SELECT COUNT(*) AS __count FROM ${c(s)}${$(a)}`,a.params);return Number(t?.__count??0)},create:async(s,n)=>{const a=Object.keys(n),t=a.map(()=>"?").join(", "),l=`INSERT INTO ${c(s)} (${a.map(o=>c(o)).join(", ")}) VALUES (${t})`;return await r.run(l,a.map(o=>n[o])),{...n}},incrementOne:async(s,n,a,t)=>{const l=c(s),o=Object.keys(a),i=t?Object.keys(t):[],m=p(n);if(o.length===0&&i.length===0){const[u]=await r.all(`SELECT * FROM ${l}${$(m)} LIMIT 1`,m.params);return u}const h=[...o.map(u=>`${c(u)} = COALESCE(${c(u)}, 0) + ?`),...i.map(u=>`${c(u)} = ?`)].join(", "),[O]=await r.all(`UPDATE ${l} SET ${h} WHERE rowid IN (SELECT rowid FROM ${l}${$(m)} LIMIT 1) RETURNING *`,[...o.map(u=>a[u]),...i.map(u=>t[u]),...m.params]);return O},read:async(s,n)=>{const a=p(n.where),t=[...a.params];let l=`SELECT * FROM ${c(s)}${$(a)}`;return n.sortBy&&(l+=` ORDER BY ${c(n.sortBy.field)} ${n.sortBy.direction==="asc"?"ASC":"DESC"}`),n.limit!==void 0&&(l+=" LIMIT ?",t.push(Math.trunc(n.limit))),n.offset&&(l+=`${n.limit===void 0?" LIMIT -1":""} OFFSET ?`,t.push(Math.trunc(n.offset))),r.all(l,t)},remove:async(s,n)=>{const a=p(n);return(await r.all(`DELETE FROM ${c(s)}${$(a)} RETURNING *`,a.params)).length},update:async(s,n,a)=>{const t=Object.keys(a);if(t.length===0)return e(s,n);const l=t.map(i=>`${c(i)} = ?`).join(", "),o=p(n);return r.all(`UPDATE ${c(s)} SET ${l}${$(o)} RETURNING *`,[...t.map(i=>a[i]),...o.params])}}},q=r=>({all:async(e,s)=>(await r.prepare(e).bind(...s).all()).results??[],run:async(e,s)=>{await r.prepare(e).bind(...s).run()}});export{f as createSqlAuthStore,q as d1Executor};
package/dist/store.mjs CHANGED
@@ -1,183 +1 @@
1
- const asString = (value) => typeof value === "string" ? value : void 0;
2
- const isNullish = (value) => value === void 0 || value === null;
3
- const looseEquals = (left, right, insensitive) => {
4
- if (insensitive) {
5
- const a = asString(left);
6
- const b = asString(right);
7
- if (a !== void 0 && b !== void 0) {
8
- return a.toLowerCase() === b.toLowerCase();
9
- }
10
- }
11
- return left === right;
12
- };
13
- const matchesPattern = (cell, value, operator, insensitive) => {
14
- const haystack = asString(cell);
15
- const needle = asString(value);
16
- if (haystack === void 0 || needle === void 0) {
17
- return false;
18
- }
19
- const [a, b] = insensitive ? [haystack.toLowerCase(), needle.toLowerCase()] : [haystack, needle];
20
- if (operator === "contains") {
21
- return a.includes(b);
22
- }
23
- return operator === "starts_with" ? a.startsWith(b) : a.endsWith(b);
24
- };
25
- const evaluateClause = (row, clause) => {
26
- const { field, mode, operator, value } = clause;
27
- const cell = row[field];
28
- const insensitive = mode === "insensitive";
29
- switch (operator) {
30
- case "contains":
31
- case "ends_with":
32
- case "starts_with": {
33
- return matchesPattern(cell, value, operator, insensitive);
34
- }
35
- case "gt": {
36
- return !isNullish(value) && cell > value;
37
- }
38
- case "gte": {
39
- return !isNullish(value) && cell >= value;
40
- }
41
- case "in": {
42
- return Array.isArray(value) && value.some((entry) => looseEquals(cell, entry, insensitive));
43
- }
44
- case "lt": {
45
- return !isNullish(value) && cell < value;
46
- }
47
- case "lte": {
48
- return !isNullish(value) && cell <= value;
49
- }
50
- case "ne": {
51
- return !looseEquals(cell, value, insensitive);
52
- }
53
- case "not_in": {
54
- return Array.isArray(value) && !value.some((entry) => looseEquals(cell, entry, insensitive));
55
- }
56
- // "eq" and the default: null-aware equality.
57
- default: {
58
- return isNullish(value) ? isNullish(cell) : looseEquals(cell, value, insensitive);
59
- }
60
- }
61
- };
62
- const compareCells = (a, b) => {
63
- if (typeof a === "string" && typeof b === "string") {
64
- return a.localeCompare(b);
65
- }
66
- const left = Number(a);
67
- const right = Number(b);
68
- if (left < right) {
69
- return -1;
70
- }
71
- return left > right ? 1 : 0;
72
- };
73
- const sortRows = (rows, sortBy) => {
74
- const direction = sortBy.direction === "asc" ? 1 : -1;
75
- return rows.toSorted((left, right) => {
76
- const a = left[sortBy.field];
77
- const b = right[sortBy.field];
78
- if (isNullish(a) && isNullish(b)) {
79
- return 0;
80
- }
81
- if (isNullish(a)) {
82
- return -direction;
83
- }
84
- if (isNullish(b)) {
85
- return direction;
86
- }
87
- return compareCells(a, b) * direction;
88
- });
89
- };
90
- const matchesWhere = (row, where) => {
91
- let result = true;
92
- for (const [index, clause] of where.entries()) {
93
- const clauseResult = evaluateClause(row, clause);
94
- if (index === 0) {
95
- result = clauseResult;
96
- } else if (clause.connector === "OR") {
97
- result = result || clauseResult;
98
- } else {
99
- result = result && clauseResult;
100
- }
101
- }
102
- return result;
103
- };
104
- const createMemoryAuthStore = () => {
105
- const tables = /* @__PURE__ */ new Map();
106
- const tableOf = (model) => {
107
- const existing = tables.get(model);
108
- if (existing) {
109
- return existing;
110
- }
111
- const created = [];
112
- tables.set(model, created);
113
- return created;
114
- };
115
- return {
116
- consumeOne: (model, where) => {
117
- const table = tableOf(model);
118
- const index = table.findIndex((row2) => matchesWhere(row2, where));
119
- if (index === -1) {
120
- return Promise.resolve(void 0);
121
- }
122
- const [row] = table.splice(index, 1);
123
- return Promise.resolve(row ? { ...row } : void 0);
124
- },
125
- count: (model, where) => Promise.resolve(tableOf(model).filter((row) => matchesWhere(row, where)).length),
126
- create: (model, data) => {
127
- const row = { ...data };
128
- tableOf(model).push(row);
129
- return Promise.resolve({ ...row });
130
- },
131
- incrementOne: (model, where, increment, set) => {
132
- const row = tableOf(model).find((candidate) => matchesWhere(candidate, where));
133
- if (!row) {
134
- return Promise.resolve(void 0);
135
- }
136
- for (const [field, delta] of Object.entries(increment)) {
137
- row[field] = (typeof row[field] === "number" ? row[field] : 0) + delta;
138
- }
139
- if (set) {
140
- Object.assign(row, set);
141
- }
142
- return Promise.resolve({ ...row });
143
- },
144
- read: (model, query) => {
145
- let rows = tableOf(model).filter((row) => matchesWhere(row, query.where));
146
- if (query.sortBy) {
147
- rows = sortRows(rows, query.sortBy);
148
- }
149
- if (query.offset) {
150
- rows = rows.slice(query.offset);
151
- }
152
- if (query.limit !== void 0) {
153
- rows = rows.slice(0, query.limit);
154
- }
155
- return Promise.resolve(
156
- rows.map((row) => {
157
- return { ...row };
158
- })
159
- );
160
- },
161
- remove: (model, where) => {
162
- const table = tableOf(model);
163
- const kept = table.filter((row) => !matchesWhere(row, where));
164
- const removed = table.length - kept.length;
165
- table.length = 0;
166
- table.push(...kept);
167
- return Promise.resolve(removed);
168
- },
169
- update: (model, where, values) => {
170
- const matched = tableOf(model).filter((row) => matchesWhere(row, where));
171
- for (const row of matched) {
172
- Object.assign(row, values);
173
- }
174
- return Promise.resolve(
175
- matched.map((row) => {
176
- return { ...row };
177
- })
178
- );
179
- }
180
- };
181
- };
182
-
183
- export { createMemoryAuthStore, matchesWhere };
1
+ const m=i=>typeof i=="string"?i:void 0,a=i=>i==null,f=(i,n,r)=>{if(r){const o=m(i),t=m(n);if(o!==void 0&&t!==void 0)return o.toLowerCase()===t.toLowerCase()}return i===n},d=(i,n,r,o)=>{const t=m(i),e=m(n);if(t===void 0||e===void 0)return!1;const[s,c]=o?[t.toLowerCase(),e.toLowerCase()]:[t,e];return r==="contains"?s.includes(c):r==="starts_with"?s.startsWith(c):s.endsWith(c)},v=(i,n)=>{const{field:r,mode:o,operator:t,value:e}=n,s=i[r],c=o==="insensitive";switch(t){case"contains":case"ends_with":case"starts_with":return d(s,e,t,c);case"gt":return!a(e)&&s>e;case"gte":return!a(e)&&s>=e;case"in":return Array.isArray(e)&&e.some(l=>f(s,l,c));case"lt":return!a(e)&&s<e;case"lte":return!a(e)&&s<=e;case"ne":return!f(s,e,c);case"not_in":return Array.isArray(e)&&!e.some(l=>f(s,l,c));default:return a(e)?a(s):f(s,e,c)}},h=(i,n)=>{if(typeof i=="string"&&typeof n=="string")return i.localeCompare(n);const r=Number(i),o=Number(n);return r<o?-1:r>o?1:0},p=(i,n)=>{const r=n.direction==="asc"?1:-1;return i.toSorted((o,t)=>{const e=o[n.field],s=t[n.field];return a(e)&&a(s)?0:a(e)?-r:a(s)?r:h(e,s)*r})},u=(i,n)=>{let r=!0;for(const[o,t]of n.entries()){const e=v(i,t);o===0?r=e:t.connector==="OR"?r=r||e:r=r&&e}return r},g=()=>{const i=new Map,n=r=>{const o=i.get(r);if(o)return o;const t=[];return i.set(r,t),t};return{consumeOne:(r,o)=>{const t=n(r),e=t.findIndex(c=>u(c,o));if(e===-1)return Promise.resolve(void 0);const[s]=t.splice(e,1);return Promise.resolve(s?{...s}:void 0)},count:(r,o)=>Promise.resolve(n(r).filter(t=>u(t,o)).length),create:(r,o)=>{const t={...o};return n(r).push(t),Promise.resolve({...t})},incrementOne:(r,o,t,e)=>{const s=n(r).find(c=>u(c,o));if(!s)return Promise.resolve(void 0);for(const[c,l]of Object.entries(t))s[c]=(typeof s[c]=="number"?s[c]:0)+l;return e&&Object.assign(s,e),Promise.resolve({...s})},read:(r,o)=>{let t=n(r).filter(e=>u(e,o.where));return o.sortBy&&(t=p(t,o.sortBy)),o.offset&&(t=t.slice(o.offset)),o.limit!==void 0&&(t=t.slice(0,o.limit)),Promise.resolve(t.map(e=>({...e})))},remove:(r,o)=>{const t=n(r),e=t.filter(c=>!u(c,o)),s=t.length-e.length;return t.length=0,t.push(...e),Promise.resolve(s)},update:(r,o,t)=>{const e=n(r).filter(s=>u(s,o));for(const s of e)Object.assign(s,t);return Promise.resolve(e.map(s=>({...s})))}}};export{g as createMemoryAuthStore,u as matchesWhere};
@@ -1,34 +1 @@
1
- import { LunoraError } from '@lunora/errors';
2
- import { verifyTurnstile } from './turnstile.mjs';
3
-
4
- const verifyTurnstileMiddleware = (options) => async ({ ctx, next }) => {
5
- const token = options.token(ctx);
6
- if (token === void 0 || token === "") {
7
- throw new LunoraError("FORBIDDEN", options.message ?? "turnstile token missing");
8
- }
9
- let result;
10
- try {
11
- result = await verifyTurnstile({
12
- expectedAction: options.expectedAction,
13
- expectedHostname: options.expectedHostname,
14
- fetch: options.fetch,
15
- remoteip: options.remoteip?.(ctx),
16
- secret: options.secret,
17
- token
18
- });
19
- } catch (error) {
20
- console.error(`@lunora/auth: verifyTurnstileMiddleware siteverify threw; ${options.failOpen ? "failing open" : "failing closed"}`, error);
21
- if (options.failOpen) {
22
- return next();
23
- }
24
- throw new LunoraError("FORBIDDEN", options.message ?? "turnstile verification unavailable", { cause: error });
25
- }
26
- if (!result.success || options.validate !== void 0 && !options.validate(result)) {
27
- throw new LunoraError("FORBIDDEN", options.message ?? "turnstile verification failed", {
28
- data: result.errorCodes.length > 0 ? { errorCodes: result.errorCodes } : void 0
29
- });
30
- }
31
- return next();
32
- };
33
-
34
- export { verifyTurnstileMiddleware };
1
+ import{LunoraError as i}from"@lunora/errors";import{verifyTurnstile as a}from"./turnstile.mjs";const d=e=>async({ctx:o,next:n})=>{const r=e.token(o);if(r===void 0||r==="")throw new i("FORBIDDEN",e.message??"turnstile token missing");let t;try{t=await a({expectedAction:e.expectedAction,expectedHostname:e.expectedHostname,fetch:e.fetch,remoteip:e.remoteip?.(o),secret:e.secret,token:r})}catch(s){if(console.error(`@lunora/auth: verifyTurnstileMiddleware siteverify threw; ${e.failOpen?"failing open":"failing closed"}`,s),e.failOpen)return n();throw new i("FORBIDDEN",e.message??"turnstile verification unavailable",{cause:s})}if(!t.success||e.validate!==void 0&&!e.validate(t))throw new i("FORBIDDEN",e.message??"turnstile verification failed",{data:t.errorCodes.length>0?{errorCodes:t.errorCodes}:void 0});return n()};export{d as verifyTurnstileMiddleware};
@@ -1,59 +1 @@
1
- import { LunoraError } from '@lunora/errors';
2
-
3
- const TURNSTILE_VERIFY_ENDPOINT = "https://challenges.cloudflare.com/turnstile/v0/siteverify";
4
- const asString = (value) => typeof value === "string" ? value : void 0;
5
- const asStringArray = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
6
- const verifyTurnstile = async ({
7
- expectedAction,
8
- expectedHostname,
9
- fetch = globalThis.fetch,
10
- remoteip,
11
- secret,
12
- token
13
- }) => {
14
- const body = new URLSearchParams({ response: token, secret });
15
- if (remoteip !== void 0 && remoteip !== "") {
16
- body.set("remoteip", remoteip);
17
- }
18
- let response;
19
- try {
20
- response = await fetch(TURNSTILE_VERIFY_ENDPOINT, {
21
- body: body.toString(),
22
- headers: { "content-type": "application/x-www-form-urlencoded" },
23
- method: "POST"
24
- });
25
- } catch (error) {
26
- throw new LunoraError("SERVICE_UNAVAILABLE", "turnstile siteverify request failed", { cause: error, status: 503 });
27
- }
28
- if (!response.ok) {
29
- throw new LunoraError("SERVICE_UNAVAILABLE", `turnstile siteverify returned ${String(response.status)}`, { status: 503 });
30
- }
31
- let raw;
32
- try {
33
- raw = await response.json();
34
- } catch (error) {
35
- throw new LunoraError("SERVICE_UNAVAILABLE", "turnstile siteverify returned a non-JSON body", { cause: error, status: 503 });
36
- }
37
- const action = asString(raw.action);
38
- const hostname = asString(raw.hostname);
39
- const errorCodes = asStringArray(raw["error-codes"]);
40
- let success = raw.success === true;
41
- if (success && expectedHostname !== void 0 && hostname !== expectedHostname) {
42
- success = false;
43
- errorCodes.push("hostname-mismatch");
44
- }
45
- if (success && expectedAction !== void 0 && action !== expectedAction) {
46
- success = false;
47
- errorCodes.push("action-mismatch");
48
- }
49
- return {
50
- action,
51
- cdata: asString(raw.cdata),
52
- challengeTs: asString(raw.challenge_ts),
53
- errorCodes,
54
- hostname,
55
- success
56
- };
57
- };
58
-
59
- export { TURNSTILE_VERIFY_ENDPOINT, verifyTurnstile };
1
+ import{LunoraError as l}from"@lunora/errors";const y="https://challenges.cloudflare.com/turnstile/v0/siteverify",o=t=>typeof t=="string"?t:void 0,w=t=>Array.isArray(t)?t.filter(r=>typeof r=="string"):[],A=async({expectedAction:t,expectedHostname:r,fetch:f=globalThis.fetch,remoteip:n,secret:m,token:p})=>{const h=new URLSearchParams({response:p,secret:m});n!==void 0&&n!==""&&h.set("remoteip",n);let a;try{a=await f(y,{body:h.toString(),headers:{"content-type":"application/x-www-form-urlencoded"},method:"POST"})}catch(c){throw new l("SERVICE_UNAVAILABLE","turnstile siteverify request failed",{cause:c,status:503})}if(!a.ok)throw new l("SERVICE_UNAVAILABLE",`turnstile siteverify returned ${String(a.status)}`,{status:503});let e;try{e=await a.json()}catch(c){throw new l("SERVICE_UNAVAILABLE","turnstile siteverify returned a non-JSON body",{cause:c,status:503})}const u=o(e.action),d=o(e.hostname),i=w(e["error-codes"]);let s=e.success===!0;return s&&r!==void 0&&d!==r&&(s=!1,i.push("hostname-mismatch")),s&&t!==void 0&&u!==t&&(s=!1,i.push("action-mismatch")),{action:u,cdata:o(e.cdata),challengeTs:o(e.challenge_ts),errorCodes:i,hostname:d,success:s}};export{y as TURNSTILE_VERIFY_ENDPOINT,A as verifyTurnstile};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/auth",
3
- "version": "1.0.0-alpha.37",
3
+ "version": "1.0.0-alpha.39",
4
4
  "description": "Auth for Lunora — a thin better-auth wrapper: email/password, OAuth, plugins, D1-backed",
5
5
  "keywords": [
6
6
  "auth",
@@ -92,7 +92,7 @@
92
92
  "dependencies": {
93
93
  "@better-auth/passkey": "^1.6.23",
94
94
  "@lunora/errors": "1.0.0-alpha.8",
95
- "@lunora/server": "1.0.0-alpha.31",
95
+ "@lunora/server": "1.0.0-alpha.33",
96
96
  "@lunora/values": "1.0.0-alpha.11",
97
97
  "@visulima/disposable-email-domains": "1.0.1",
98
98
  "@visulima/email-verifier": "1.0.1",
@@ -1,11 +0,0 @@
1
- const DEFAULT_AUTH_BASE_PATH = "/api/auth";
2
- const handleAuthRequest = async (auth, request, basePath = DEFAULT_AUTH_BASE_PATH) => {
3
- const url = new URL(request.url);
4
- const base = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
5
- if (url.pathname !== base && !url.pathname.startsWith(`${base}/`)) {
6
- return void 0;
7
- }
8
- return auth.handler(request);
9
- };
10
-
11
- export { DEFAULT_AUTH_BASE_PATH, handleAuthRequest };