@hachej/boring-core 0.1.44 → 0.1.45

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.
@@ -9,7 +9,7 @@ import {
9
9
  registerRoutes,
10
10
  registerSettingsRoutes,
11
11
  registerWorkspaceRoutes
12
- } from "../../chunk-UM5SHYIS.js";
12
+ } from "../../chunk-FZICNVJW.js";
13
13
  import {
14
14
  PostgresUserStore,
15
15
  PostgresWorkspaceStore,
@@ -208,6 +208,13 @@ var FRONTEND_AUTH_PAGES_SPA_ONLY = /* @__PURE__ */ new Set([
208
208
  "/auth/callback/github",
209
209
  "/auth/callback/google"
210
210
  ]);
211
+ function resolveCoreLoadConfigOptions(options = {}, nodeEnv = process.env.NODE_ENV) {
212
+ return {
213
+ allowMissingSecrets: nodeEnv !== "production",
214
+ ...options.appRoot && !options.loadConfigOptions?.tomlPath ? { tomlPath: path.resolve(options.appRoot, "boring.app.toml") } : {},
215
+ ...options.loadConfigOptions
216
+ };
217
+ }
211
218
  function dedupeStrings(values) {
212
219
  return Array.from(new Set(values));
213
220
  }
@@ -526,10 +533,7 @@ async function createCoreWorkspaceAgentServer(options = {}) {
526
533
  );
527
534
  }
528
535
  assertCoreStaticPluginEntries(options.plugins);
529
- const config = options.config ?? await loadConfig({
530
- allowMissingSecrets: process.env.NODE_ENV !== "production",
531
- ...options.loadConfigOptions
532
- });
536
+ const config = options.config ?? await loadConfig(resolveCoreLoadConfigOptions(options));
533
537
  const { app, sql, db, userStore, workspaceStore } = await createCoreRuntime(config);
534
538
  const appRoot = options.appRoot;
535
539
  const serveFrontend = options.serveFrontend ?? (process.env.NODE_ENV !== "development" && Boolean(appRoot));
@@ -101,6 +101,30 @@ var SIXTEEN_MB = 16 * 1024 * 1024;
101
101
  var INSECURE_PLACEHOLDER_SECRET = "0000000000000000000000000000000000000000000000000000000000000000";
102
102
  var INSECURE_DATABASE_URL = "postgres://placeholder:placeholder@localhost:5432/placeholder";
103
103
  var INSECURE_ENCRYPTION_KEY = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
104
+ function formatDisplayName(name) {
105
+ const trimmed = name.trim().replace(/[<>]/g, "");
106
+ if (/^[A-Za-z0-9 ._-]+$/.test(trimmed)) return trimmed;
107
+ return `"${trimmed.replace(/["\\]/g, "\\$&")}"`;
108
+ }
109
+ function isDefaultBoringDisplayName(name) {
110
+ return name.toLowerCase().replace(/[\s._-]+/g, "") === "boringui";
111
+ }
112
+ function normalizeMailFrom(appName, rawFrom) {
113
+ const from = rawFrom.trim();
114
+ const addressWithDisplay = from.match(/^(.*?)\s*<([^>]+)>$/);
115
+ if (addressWithDisplay) {
116
+ const displayName = addressWithDisplay[1].trim().replace(/^"(.*)"$/, "$1");
117
+ const address = addressWithDisplay[2].trim();
118
+ if (!displayName || isDefaultBoringDisplayName(displayName)) {
119
+ return `${formatDisplayName(appName)} <${address}>`;
120
+ }
121
+ return from;
122
+ }
123
+ if (/^[^\s@<>]+@[^\s@<>]+$/.test(from)) {
124
+ return `${formatDisplayName(appName)} <${from}>`;
125
+ }
126
+ return from;
127
+ }
104
128
  function parseRateLimitOverrides(raw) {
105
129
  if (!raw) return void 0;
106
130
  try {
@@ -224,7 +248,18 @@ async function loadConfig(options) {
224
248
  ...toml.features?.invite_ttl_days != null && { inviteTtlDays: toml.features.invite_ttl_days }
225
249
  }
226
250
  };
227
- return validateConfig(raw);
251
+ const config = validateConfig(raw);
252
+ if (!config.auth.mail) return config;
253
+ return {
254
+ ...config,
255
+ auth: {
256
+ ...config.auth,
257
+ mail: {
258
+ ...config.auth.mail,
259
+ from: normalizeMailFrom(config.appName, config.auth.mail.from)
260
+ }
261
+ }
262
+ };
228
263
  }
229
264
  function validateConfig(raw) {
230
265
  const result = coreConfigSchema.safeParse(raw);
@@ -1423,6 +1458,7 @@ import { Button as Button4, Section as Section5, Text as Text5 } from "@react-em
1423
1458
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1424
1459
  function WorkspaceInvite({
1425
1460
  acceptUrl,
1461
+ appName,
1426
1462
  inviterName,
1427
1463
  workspaceName,
1428
1464
  role,
@@ -1432,7 +1468,7 @@ function WorkspaceInvite({
1432
1468
  Layout,
1433
1469
  {
1434
1470
  preview: `${inviterName} invited you to ${workspaceName}`,
1435
- appName: workspaceName,
1471
+ appName,
1436
1472
  children: /* @__PURE__ */ jsxs5(Section5, { style: content4, children: [
1437
1473
  /* @__PURE__ */ jsx5(Text5, { style: heading4, children: "You've been invited" }),
1438
1474
  /* @__PURE__ */ jsxs5(Text5, { style: paragraph4, children: [
@@ -1568,6 +1604,7 @@ async function renderMagicLink(data) {
1568
1604
  async function renderWorkspaceInvite(data) {
1569
1605
  const element = WorkspaceInvite({
1570
1606
  acceptUrl: data.acceptUrl,
1607
+ appName: data.appName,
1571
1608
  inviterName: data.inviterName,
1572
1609
  workspaceName: data.workspaceName,
1573
1610
  role: data.role,
@@ -2426,6 +2463,7 @@ var inviteRoutesPlugin = async (app, opts) => {
2426
2463
  const email = await renderWorkspaceInvite({
2427
2464
  to: parsed.data.email,
2428
2465
  acceptUrl,
2466
+ appName: app.config.appName,
2429
2467
  inviterName: request.user.name ?? request.user.email,
2430
2468
  workspaceName: workspace?.name ?? "Workspace",
2431
2469
  role: parsed.data.role,
@@ -326,6 +326,7 @@ declare function renderMagicLink(data: MagicLinkData): Promise<RenderedEmail>;
326
326
  interface WorkspaceInviteData {
327
327
  to: string;
328
328
  acceptUrl: string;
329
+ appName: string;
329
330
  inviterName: string;
330
331
  workspaceName: string;
331
332
  role: string;
@@ -24,7 +24,7 @@ import {
24
24
  requireWorkspaceMember,
25
25
  validateConfig,
26
26
  validatePasswordStrength
27
- } from "../chunk-UM5SHYIS.js";
27
+ } from "../chunk-FZICNVJW.js";
28
28
  import {
29
29
  InsufficientCreditError,
30
30
  PostgresMeteringStore,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-core",
3
- "version": "0.1.44",
3
+ "version": "0.1.45",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Foundation package for boring-ui-v2 apps: DB, auth, config, HTTP app factory, and frontend app shell.",
@@ -79,9 +79,9 @@
79
79
  "react-router-dom": "^7.14.2",
80
80
  "smol-toml": "^1.6.1",
81
81
  "zod": "^3.25.76",
82
- "@hachej/boring-ui-kit": "0.1.44",
83
- "@hachej/boring-workspace": "0.1.44",
84
- "@hachej/boring-agent": "0.1.44"
82
+ "@hachej/boring-ui-kit": "0.1.45",
83
+ "@hachej/boring-workspace": "0.1.45",
84
+ "@hachej/boring-agent": "0.1.45"
85
85
  },
86
86
  "devDependencies": {
87
87
  "@testing-library/jest-dom": "^6.9.1",