@dyrected/core 2.5.16 → 2.5.18

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/server.cjs CHANGED
@@ -269,19 +269,27 @@ async function verifyPassword(plain, stored) {
269
269
  }
270
270
 
271
271
  // src/utils/hooks.ts
272
- async function runCollectionHooks(hooks, args) {
272
+ async function runCollectionHooks(hooks, args, options = {}) {
273
273
  if (!hooks || hooks.length === 0) {
274
274
  return args.data ?? args.doc ?? void 0;
275
275
  }
276
276
  let currentPayload = args.data ?? args.doc ?? void 0;
277
277
  for (const hook of hooks) {
278
- const result = await hook({
279
- ...args,
280
- data: args.data !== void 0 ? currentPayload : void 0,
281
- doc: args.doc !== void 0 ? currentPayload : void 0
282
- });
283
- if (result !== void 0) {
284
- currentPayload = result;
278
+ try {
279
+ const result = await hook({
280
+ ...args,
281
+ data: args.data !== void 0 ? currentPayload : void 0,
282
+ doc: args.doc !== void 0 ? currentPayload : void 0
283
+ });
284
+ if (result !== void 0) {
285
+ currentPayload = result;
286
+ }
287
+ } catch (err) {
288
+ if (options.isolated) {
289
+ console.error("[dyrected/core] Side-effect hook failed (error isolated \u2014 DB write was successful):", err);
290
+ } else {
291
+ throw err;
292
+ }
285
293
  }
286
294
  }
287
295
  return currentPayload;
@@ -554,7 +562,7 @@ var CollectionController = class {
554
562
  user,
555
563
  req: c.req,
556
564
  operation: "create"
557
- });
565
+ }, { isolated: true });
558
566
  const readDoc = await runCollectionHooks(this.collection.hooks?.afterRead, {
559
567
  doc,
560
568
  req: c.req,
@@ -612,7 +620,7 @@ var CollectionController = class {
612
620
  user,
613
621
  req: c.req,
614
622
  operation: "create"
615
- });
623
+ }, { isolated: true });
616
624
  const readDoc = await runCollectionHooks(this.collection.hooks?.afterRead, {
617
625
  doc,
618
626
  req: c.req,
@@ -670,7 +678,7 @@ var CollectionController = class {
670
678
  user,
671
679
  req: c.req,
672
680
  operation: "update"
673
- });
681
+ }, { isolated: true });
674
682
  const readDoc = await runCollectionHooks(this.collection.hooks?.afterRead, {
675
683
  doc,
676
684
  req: c.req,
@@ -785,7 +793,7 @@ var CollectionController = class {
785
793
  doc,
786
794
  user,
787
795
  req: c.req
788
- });
796
+ }, { isolated: true });
789
797
  return c.json({ message: "Deleted" });
790
798
  }
791
799
  async deleteMany(c) {
@@ -842,7 +850,7 @@ var CollectionController = class {
842
850
  doc,
843
851
  user,
844
852
  req: c.req
845
- });
853
+ }, { isolated: true });
846
854
  } catch (err) {
847
855
  failed.push({ id, error: err?.message ?? "Unknown error" });
848
856
  }
@@ -944,7 +952,7 @@ var GlobalController = class {
944
952
  user,
945
953
  req: c.req,
946
954
  operation: "update"
947
- });
955
+ }, { isolated: true });
948
956
  const readDoc = await runCollectionHooks(this.global.hooks?.afterRead, {
949
957
  doc: updated,
950
958
  req: c.req,
@@ -1176,11 +1184,37 @@ function buildWelcomeEmail(config, args) {
1176
1184
  return {
1177
1185
  subject: custom?.subject ?? "Welcome \u2014 your account is ready",
1178
1186
  html: custom?.html ?? `
1179
- <div style="font-family:sans-serif;max-width:600px;margin:0 auto">
1180
- <h2>Welcome!</h2>
1181
- <p>Your account has been created. You can now log in with:</p>
1182
- <p><strong>${args.email}</strong></p>
1183
- </div>`
1187
+ <table cellpadding="0" cellspacing="0" border="0" style="width:100%;background-color:#f9fafb;table-layout:fixed">
1188
+ <tr>
1189
+ <td align="center" style="padding:40px 16px">
1190
+ <table cellpadding="0" cellspacing="0" border="0" style="width:100%;max-width:600px;background-color:#ffffff;border-radius:12px;border:1px solid #e5e7eb;table-layout:fixed">
1191
+ <tr>
1192
+ <td style="padding:32px 32px 0">
1193
+ <p style="margin:0 0 4px;font-size:12px;font-weight:600;color:#6b7280;font-family:sans-serif;text-transform:uppercase;letter-spacing:0.05em">Dyrected</p>
1194
+ <h1 style="margin:0 0 24px;font-size:22px;font-weight:700;color:#111827;font-family:sans-serif">Welcome!</h1>
1195
+ </td>
1196
+ </tr>
1197
+ <tr>
1198
+ <td style="padding:0 32px">
1199
+ <p style="margin:0 0 12px;font-size:14px;color:#4b5563;line-height:1.6;font-family:sans-serif">Your account has been created. You can now log in with:</p>
1200
+ <table cellpadding="0" cellspacing="0" border="0" style="width:100%;background-color:#f3f4f6;border-radius:6px;table-layout:fixed">
1201
+ <tr>
1202
+ <td style="padding:12px 16px;font-size:14px;font-weight:600;color:#111827;font-family:sans-serif;word-break:break-all">
1203
+ ${args.email}
1204
+ </td>
1205
+ </tr>
1206
+ </table>
1207
+ </td>
1208
+ </tr>
1209
+ <tr>
1210
+ <td style="padding:32px">
1211
+ <p style="margin:0;font-size:12px;color:#9ca3af;font-family:sans-serif">If you didn't create this account, you can safely ignore this email.</p>
1212
+ </td>
1213
+ </tr>
1214
+ </table>
1215
+ </td>
1216
+ </tr>
1217
+ </table>`
1184
1218
  };
1185
1219
  }
1186
1220
  function buildInviteEmail(config, args) {
@@ -1188,24 +1222,89 @@ function buildInviteEmail(config, args) {
1188
1222
  return {
1189
1223
  subject: custom?.subject ?? "You've been invited",
1190
1224
  html: custom?.html ?? `
1191
- <div style="font-family:sans-serif;max-width:600px;margin:0 auto">
1192
- <h2>You've been invited</h2>
1193
- ${args.invitedByEmail ? `<p>Invited by <strong>${args.invitedByEmail}</strong>.</p>` : ""}
1194
- <p>Use the token below to accept your invitation. It expires in 7 days.</p>
1195
- <pre style="background:#f4f4f4;padding:12px;border-radius:4px;word-break:break-all">${args.token}</pre>
1196
- </div>`
1225
+ <table cellpadding="0" cellspacing="0" border="0" style="width:100%;background-color:#f9fafb;table-layout:fixed">
1226
+ <tr>
1227
+ <td align="center" style="padding:40px 16px">
1228
+ <table cellpadding="0" cellspacing="0" border="0" style="width:100%;max-width:600px;background-color:#ffffff;border-radius:12px;border:1px solid #e5e7eb;table-layout:fixed">
1229
+ <tr>
1230
+ <td style="padding:32px 32px 0">
1231
+ <p style="margin:0 0 4px;font-size:12px;font-weight:600;color:#6b7280;font-family:sans-serif;text-transform:uppercase;letter-spacing:0.05em">Dyrected</p>
1232
+ <h1 style="margin:0 0 24px;font-size:22px;font-weight:700;color:#111827;font-family:sans-serif">You've been invited</h1>
1233
+ </td>
1234
+ </tr>
1235
+ <tr>
1236
+ <td style="padding:0 32px">
1237
+ ${args.invitedByEmail ? `<p style="margin:0 0 12px;font-size:14px;color:#4b5563;line-height:1.6;font-family:sans-serif">You were invited by <strong style="color:#111827">${args.invitedByEmail}</strong>.</p>` : ""}
1238
+ <p style="margin:0 0 16px;font-size:14px;color:#4b5563;line-height:1.6;font-family:sans-serif">Use the token below to accept your invitation. It expires in 7 days.</p>
1239
+ <table cellpadding="0" cellspacing="0" border="0" style="width:100%;background-color:#f3f4f6;border-radius:6px;table-layout:fixed">
1240
+ <tr>
1241
+ <td style="padding:12px 16px;font-family:monospace;font-size:12px;color:#374151;word-break:break-all;white-space:normal;line-height:1.4">
1242
+ ${args.token}
1243
+ </td>
1244
+ </tr>
1245
+ </table>
1246
+ </td>
1247
+ </tr>
1248
+ <tr>
1249
+ <td style="padding:32px">
1250
+ <p style="margin:0;font-size:12px;color:#9ca3af;font-family:sans-serif">If you weren't expecting this invitation, you can safely ignore this email.</p>
1251
+ </td>
1252
+ </tr>
1253
+ </table>
1254
+ </td>
1255
+ </tr>
1256
+ </table>`
1197
1257
  };
1198
1258
  }
1199
1259
  function buildResetPasswordEmail(config, args) {
1200
1260
  const custom = config.email?.templates?.resetPassword?.(args);
1261
+ const resetLink = args.url;
1201
1262
  return {
1202
1263
  subject: custom?.subject ?? "Reset your password",
1203
1264
  html: custom?.html ?? `
1204
- <div style="font-family:sans-serif;max-width:600px;margin:0 auto">
1205
- <h2>Reset your password</h2>
1206
- <p>Use the token below to reset your password. It expires in 1 hour.</p>
1207
- <pre style="background:#f4f4f4;padding:12px;border-radius:4px;word-break:break-all">${args.token}</pre>
1208
- </div>`
1265
+ <table cellpadding="0" cellspacing="0" border="0" style="width:100%;background-color:#f9fafb;table-layout:fixed">
1266
+ <tr>
1267
+ <td align="center" style="padding:40px 16px">
1268
+ <table cellpadding="0" cellspacing="0" border="0" style="width:100%;max-width:600px;background-color:#ffffff;border-radius:12px;border:1px solid #e5e7eb;table-layout:fixed">
1269
+ <tr>
1270
+ <td style="padding:32px 32px 0">
1271
+ <p style="margin:0 0 4px;font-size:12px;font-weight:600;color:#6b7280;font-family:sans-serif;text-transform:uppercase;letter-spacing:0.05em">Dyrected</p>
1272
+ <h1 style="margin:0 0 24px;font-size:22px;font-weight:700;color:#111827;font-family:sans-serif">Reset your password</h1>
1273
+ </td>
1274
+ </tr>
1275
+ <tr>
1276
+ <td style="padding:0 32px">
1277
+ <p style="margin:0 0 24px;font-size:14px;color:#4b5563;line-height:1.6;font-family:sans-serif">We received a request to reset your password. Use the button below to set a new password. It will expire in 1 hour.</p>
1278
+ ${resetLink ? `
1279
+ <table cellpadding="0" cellspacing="0" border="0" style="margin-bottom:24px">
1280
+ <tr>
1281
+ <td style="border-radius:6px;background-color:#111827">
1282
+ <a href="${resetLink}" style="display:inline-block;padding:12px 28px;font-size:14px;font-weight:600;color:#ffffff;text-decoration:none;font-family:sans-serif;border-radius:6px">
1283
+ Reset Password
1284
+ </a>
1285
+ </td>
1286
+ </tr>
1287
+ </table>
1288
+ ` : ""}
1289
+ <p style="margin:0 0 8px;font-size:12px;color:#9ca3af;font-family:sans-serif">Or copy and paste this token manually in the admin dashboard:</p>
1290
+ <table cellpadding="0" cellspacing="0" border="0" style="width:100%;background-color:#f3f4f6;border-radius:6px;table-layout:fixed">
1291
+ <tr>
1292
+ <td style="padding:12px 16px;font-family:monospace;font-size:12px;color:#374151;word-break:break-all;white-space:normal;line-height:1.4">
1293
+ ${args.token}
1294
+ </td>
1295
+ </tr>
1296
+ </table>
1297
+ </td>
1298
+ </tr>
1299
+ <tr>
1300
+ <td style="padding:32px">
1301
+ <p style="margin:0;font-size:12px;color:#9ca3af;font-family:sans-serif">If you didn't request a password reset, you can safely ignore this email.</p>
1302
+ </td>
1303
+ </tr>
1304
+ </table>
1305
+ </td>
1306
+ </tr>
1307
+ </table>`
1209
1308
  };
1210
1309
  }
1211
1310
  function buildPasswordChangedEmail(config, args) {
@@ -1213,11 +1312,44 @@ function buildPasswordChangedEmail(config, args) {
1213
1312
  return {
1214
1313
  subject: custom?.subject ?? "Your password has been changed",
1215
1314
  html: custom?.html ?? `
1216
- <div style="font-family:sans-serif;max-width:600px;margin:0 auto">
1217
- <h2>Password changed</h2>
1218
- <p>The password for <strong>${args.email}</strong> was just changed.</p>
1219
- <p>If you did not make this change, please contact support immediately.</p>
1220
- </div>`
1315
+ <table cellpadding="0" cellspacing="0" border="0" style="width:100%;background-color:#f9fafb;table-layout:fixed">
1316
+ <tr>
1317
+ <td align="center" style="padding:40px 16px">
1318
+ <table cellpadding="0" cellspacing="0" border="0" style="width:100%;max-width:600px;background-color:#ffffff;border-radius:12px;border:1px solid #e5e7eb;table-layout:fixed">
1319
+ <tr>
1320
+ <td style="padding:32px 32px 0">
1321
+ <p style="margin:0 0 4px;font-size:12px;font-weight:600;color:#6b7280;font-family:sans-serif;text-transform:uppercase;letter-spacing:0.05em">Dyrected</p>
1322
+ <h1 style="margin:0 0 24px;font-size:22px;font-weight:700;color:#111827;font-family:sans-serif">Password changed</h1>
1323
+ </td>
1324
+ </tr>
1325
+ <tr>
1326
+ <td style="padding:0 32px">
1327
+ <p style="margin:0 0 12px;font-size:14px;color:#4b5563;line-height:1.6;font-family:sans-serif">The password for your account was just changed:</p>
1328
+ <table cellpadding="0" cellspacing="0" border="0" style="width:100%;background-color:#f3f4f6;border-radius:6px;table-layout:fixed">
1329
+ <tr>
1330
+ <td style="padding:12px 16px;font-size:14px;font-weight:600;color:#111827;font-family:sans-serif;word-break:break-all">
1331
+ ${args.email}
1332
+ </td>
1333
+ </tr>
1334
+ </table>
1335
+ <table cellpadding="0" cellspacing="0" border="0" style="width:100%;margin-top:16px;background-color:#fef2f2;border-radius:6px;border:1px solid #fecaca;table-layout:fixed">
1336
+ <tr>
1337
+ <td style="padding:12px 16px;font-size:13px;color:#b91c1c;line-height:1.5;font-family:sans-serif">
1338
+ If you did not make this change, please contact support immediately.
1339
+ </td>
1340
+ </tr>
1341
+ </table>
1342
+ </td>
1343
+ </tr>
1344
+ <tr>
1345
+ <td style="padding:32px">
1346
+ <p style="margin:0;font-size:12px;color:#9ca3af;font-family:sans-serif">This is an automated security notification.</p>
1347
+ </td>
1348
+ </tr>
1349
+ </table>
1350
+ </td>
1351
+ </tr>
1352
+ </table>`
1221
1353
  };
1222
1354
  }
1223
1355
 
@@ -1378,8 +1510,10 @@ var AuthController = class {
1378
1510
  { sub: user.id, email: user.email, collection: this.collection.slug, purpose: "reset" },
1379
1511
  "1h"
1380
1512
  );
1513
+ const resetUrl = body?.resetUrl;
1514
+ const url = resetUrl ? `${resetUrl}${resetUrl.includes("?") ? "&" : "?"}token=${encodeURIComponent(resetToken)}` : void 0;
1381
1515
  try {
1382
- const { subject, html } = buildResetPasswordEmail(config, { token: resetToken });
1516
+ const { subject, html } = buildResetPasswordEmail(config, { token: resetToken, url });
1383
1517
  await sendEmail(config, { to: user.email, subject, html });
1384
1518
  } catch (err) {
1385
1519
  console.error("[dyrected/core] Failed to send password reset email:", err);
package/dist/server.d.cts CHANGED
@@ -1,9 +1,9 @@
1
- import { p as DyrectedContext, D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig } from './app-DO1s9YW1.cjs';
2
- export { M as createDyrectedApp } from './app-DO1s9YW1.cjs';
1
+ import { p as DyrectedContext, D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig } from './app-D0ffogDd.cjs';
2
+ export { M as createDyrectedApp } from './app-D0ffogDd.cjs';
3
3
  import * as hono from 'hono';
4
4
  import { Hono, Context } from 'hono';
5
- import * as hono_utils_types from 'hono/utils/types';
6
5
  import * as hono_utils_http_status from 'hono/utils/http-status';
6
+ import * as hono_utils_types from 'hono/utils/types';
7
7
  import 'hono/types';
8
8
 
9
9
  /**
@@ -43,7 +43,7 @@ declare class AuthController {
43
43
  }, 400, "json">) | (Response & hono.TypedResponse<{
44
44
  token: string;
45
45
  user: {
46
- [x: string]: hono_utils_types.JSONValue;
46
+ [x: string]: any;
47
47
  id: string;
48
48
  };
49
49
  }, hono_utils_http_status.ContentfulStatusCode, "json">)>;
@@ -58,7 +58,7 @@ declare class AuthController {
58
58
  }, 401, "json">) | (Response & hono.TypedResponse<{
59
59
  token: string;
60
60
  user: {
61
- [x: string]: hono_utils_types.JSONValue;
61
+ [x: string]: any;
62
62
  };
63
63
  }, hono_utils_http_status.ContentfulStatusCode, "json">)>;
64
64
  logout(c: Context<DyrectedContext>): Promise<Response & hono.TypedResponse<{
@@ -74,7 +74,7 @@ declare class AuthController {
74
74
  error: true;
75
75
  message: string;
76
76
  }, 404, "json">) | (Response & hono.TypedResponse<{
77
- [x: string]: hono_utils_types.JSONValue;
77
+ [x: string]: any;
78
78
  id: string;
79
79
  }, hono_utils_http_status.ContentfulStatusCode, "json">)>;
80
80
  refreshToken(c: Context<DyrectedContext>): Promise<(Response & hono.TypedResponse<{
@@ -127,7 +127,7 @@ declare class AuthController {
127
127
  }, 409, "json">) | (Response & hono.TypedResponse<{
128
128
  token: string;
129
129
  user: {
130
- [x: string]: hono_utils_types.JSONValue;
130
+ [x: string]: any;
131
131
  id: string;
132
132
  };
133
133
  }, 201, "json">)>;
@@ -140,7 +140,7 @@ declare class CollectionController {
140
140
  message: string;
141
141
  }, 500, "json">) | (Response & hono.TypedResponse<{
142
142
  docs: {
143
- [x: string]: hono_utils_types.JSONValue;
143
+ [x: string]: any;
144
144
  }[];
145
145
  total: number;
146
146
  limit: number;
@@ -240,12 +240,12 @@ declare class MediaController {
240
240
  }, 500, "json">) | (Response & hono.TypedResponse<{
241
241
  message: string;
242
242
  }, 400, "json">) | (Response & hono.TypedResponse<{
243
- [x: string]: hono_utils_types.JSONValue;
243
+ [x: string]: any;
244
244
  id: string;
245
245
  }, 201, "json">)>;
246
246
  find(c: Context<DyrectedContext>): Promise<(Response & hono.TypedResponse<{
247
247
  docs: {
248
- [x: string]: hono_utils_types.JSONValue;
248
+ [x: string]: any;
249
249
  }[];
250
250
  total: number;
251
251
  limit: number;
package/dist/server.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { p as DyrectedContext, D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig } from './app-DO1s9YW1.js';
2
- export { M as createDyrectedApp } from './app-DO1s9YW1.js';
1
+ import { p as DyrectedContext, D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig } from './app-D0ffogDd.js';
2
+ export { M as createDyrectedApp } from './app-D0ffogDd.js';
3
3
  import * as hono from 'hono';
4
4
  import { Hono, Context } from 'hono';
5
- import * as hono_utils_types from 'hono/utils/types';
6
5
  import * as hono_utils_http_status from 'hono/utils/http-status';
6
+ import * as hono_utils_types from 'hono/utils/types';
7
7
  import 'hono/types';
8
8
 
9
9
  /**
@@ -43,7 +43,7 @@ declare class AuthController {
43
43
  }, 400, "json">) | (Response & hono.TypedResponse<{
44
44
  token: string;
45
45
  user: {
46
- [x: string]: hono_utils_types.JSONValue;
46
+ [x: string]: any;
47
47
  id: string;
48
48
  };
49
49
  }, hono_utils_http_status.ContentfulStatusCode, "json">)>;
@@ -58,7 +58,7 @@ declare class AuthController {
58
58
  }, 401, "json">) | (Response & hono.TypedResponse<{
59
59
  token: string;
60
60
  user: {
61
- [x: string]: hono_utils_types.JSONValue;
61
+ [x: string]: any;
62
62
  };
63
63
  }, hono_utils_http_status.ContentfulStatusCode, "json">)>;
64
64
  logout(c: Context<DyrectedContext>): Promise<Response & hono.TypedResponse<{
@@ -74,7 +74,7 @@ declare class AuthController {
74
74
  error: true;
75
75
  message: string;
76
76
  }, 404, "json">) | (Response & hono.TypedResponse<{
77
- [x: string]: hono_utils_types.JSONValue;
77
+ [x: string]: any;
78
78
  id: string;
79
79
  }, hono_utils_http_status.ContentfulStatusCode, "json">)>;
80
80
  refreshToken(c: Context<DyrectedContext>): Promise<(Response & hono.TypedResponse<{
@@ -127,7 +127,7 @@ declare class AuthController {
127
127
  }, 409, "json">) | (Response & hono.TypedResponse<{
128
128
  token: string;
129
129
  user: {
130
- [x: string]: hono_utils_types.JSONValue;
130
+ [x: string]: any;
131
131
  id: string;
132
132
  };
133
133
  }, 201, "json">)>;
@@ -140,7 +140,7 @@ declare class CollectionController {
140
140
  message: string;
141
141
  }, 500, "json">) | (Response & hono.TypedResponse<{
142
142
  docs: {
143
- [x: string]: hono_utils_types.JSONValue;
143
+ [x: string]: any;
144
144
  }[];
145
145
  total: number;
146
146
  limit: number;
@@ -240,12 +240,12 @@ declare class MediaController {
240
240
  }, 500, "json">) | (Response & hono.TypedResponse<{
241
241
  message: string;
242
242
  }, 400, "json">) | (Response & hono.TypedResponse<{
243
- [x: string]: hono_utils_types.JSONValue;
243
+ [x: string]: any;
244
244
  id: string;
245
245
  }, 201, "json">)>;
246
246
  find(c: Context<DyrectedContext>): Promise<(Response & hono.TypedResponse<{
247
247
  docs: {
248
- [x: string]: hono_utils_types.JSONValue;
248
+ [x: string]: any;
249
249
  }[];
250
250
  total: number;
251
251
  limit: number;
package/dist/server.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  PreviewController,
7
7
  createDyrectedApp,
8
8
  registerRoutes
9
- } from "./chunk-2JMA3M5S.js";
9
+ } from "./chunk-TUUHGLB5.js";
10
10
  export {
11
11
  AuthController,
12
12
  CollectionController,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dyrected/core",
3
- "version": "2.5.16",
3
+ "version": "2.5.18",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",