@technomoron/mail-magic 1.0.34 → 1.0.35

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/CHANGES CHANGED
@@ -1,3 +1,14 @@
1
+ Version 1.0.35 (2026-02-17)
2
+
3
+ - Enforce deterministic locale resolution for transactional template sends:
4
+ requested locale first, then root fallback (`locale=''`) only.
5
+ - Enforce the same deterministic locale resolution for template-scoped asset uploads
6
+ (`POST /api/v1/assets`) for both `tx` and `form` template types.
7
+ - Remove non-deterministic fallback to arbitrary locale records when requested/root
8
+ locales are missing.
9
+ - Add regression tests covering deterministic locale fallback and missing-locale
10
+ behavior for both transactional sends and template asset upload resolution.
11
+
1
12
  Version 1.0.34 (2026-02-10)
2
13
 
3
14
  - Ensure inline form template assets (CID) are actually attached when delivering public form submissions.
@@ -22,11 +22,9 @@ export class AssetAPI extends ApiModule {
22
22
  }
23
23
  const templateType = templateTypeRaw.toLowerCase();
24
24
  const domainId = apireq.domain.domain_id;
25
- const deflocale = this.server.storage.deflocale || '';
26
25
  if (templateType === 'tx') {
27
26
  const template = (await api_txmail.findOne({ where: { name: templateName, domain_id: domainId, locale } })) ||
28
- (await api_txmail.findOne({ where: { name: templateName, domain_id: domainId, locale: deflocale } })) ||
29
- (await api_txmail.findOne({ where: { name: templateName, domain_id: domainId } }));
27
+ (await api_txmail.findOne({ where: { name: templateName, domain_id: domainId, locale: '' } }));
30
28
  if (!template) {
31
29
  throw new ApiError({
32
30
  code: 404,
@@ -43,8 +41,7 @@ export class AssetAPI extends ApiModule {
43
41
  }
44
42
  if (templateType === 'form') {
45
43
  const form = (await api_form.findOne({ where: { idname: templateName, domain_id: domainId, locale } })) ||
46
- (await api_form.findOne({ where: { idname: templateName, domain_id: domainId, locale: deflocale } })) ||
47
- (await api_form.findOne({ where: { idname: templateName, domain_id: domainId } }));
44
+ (await api_form.findOne({ where: { idname: templateName, domain_id: domainId, locale: '' } }));
48
45
  if (!form) {
49
46
  throw new ApiError({
50
47
  code: 404,
@@ -100,13 +100,11 @@ export class MailerAPI extends ApiModule {
100
100
  throw new ApiError({ code: 400, message: 'Invalid email address(es): ' + invalid.join(',') });
101
101
  }
102
102
  let template = null;
103
- const deflocale = this.server.storage.deflocale || '';
104
103
  const domain_id = apireq.domain.domain_id;
105
104
  try {
106
105
  template =
107
106
  (await api_txmail.findOne({ where: { name, domain_id, locale } })) ||
108
- (await api_txmail.findOne({ where: { name, domain_id, locale: deflocale } })) ||
109
- (await api_txmail.findOne({ where: { name, domain_id } }));
107
+ (await api_txmail.findOne({ where: { name, domain_id, locale: '' } }));
110
108
  }
111
109
  catch (error) {
112
110
  throw new ApiError({
@@ -7,13 +7,15 @@ import { startMailMagicServer } from '../index.js';
7
7
  const args = process.argv.slice(2);
8
8
  function usage(exitCode = 0) {
9
9
  const out = exitCode === 0 ? process.stdout : process.stderr;
10
- out.write(`Usage: mail-magic [--env PATH]\n\n` +
10
+ out.write(`Usage: mail-magic [--env PATH] [--config DIR]\n\n` +
11
11
  `Options:\n` +
12
12
  ` -e, --env PATH Path to .env (defaults to ./.env)\n` +
13
+ ` -c, --config DIR Config directory (overrides CONFIG_PATH)\n` +
13
14
  ` -h, --help Show this help\n`);
14
15
  process.exit(exitCode);
15
16
  }
16
17
  let envPath;
18
+ let configPath;
17
19
  for (let i = 0; i < args.length; i += 1) {
18
20
  const arg = args[i];
19
21
  if (arg === '-h' || arg === '--help') {
@@ -29,10 +31,24 @@ for (let i = 0; i < args.length; i += 1) {
29
31
  i += 1;
30
32
  continue;
31
33
  }
34
+ if (arg === '-c' || arg === '--config') {
35
+ const next = args[i + 1];
36
+ if (!next) {
37
+ console.error('Error: --config requires a directory');
38
+ usage(1);
39
+ }
40
+ configPath = next;
41
+ i += 1;
42
+ continue;
43
+ }
32
44
  if (arg.startsWith('--env=')) {
33
45
  envPath = arg.slice('--env='.length);
34
46
  continue;
35
47
  }
48
+ if (arg.startsWith('--config=')) {
49
+ configPath = arg.slice('--config='.length);
50
+ continue;
51
+ }
36
52
  console.error(`Error: unknown option ${arg}`);
37
53
  usage(1);
38
54
  }
@@ -41,6 +57,19 @@ if (!fs.existsSync(resolvedEnvPath)) {
41
57
  console.error(`Error: env file not found at ${resolvedEnvPath}`);
42
58
  process.exit(1);
43
59
  }
60
+ let resolvedConfigPath;
61
+ if (configPath) {
62
+ // Resolve the config dir relative to the .env directory (we chdir there next).
63
+ resolvedConfigPath = path.resolve(path.dirname(resolvedEnvPath), configPath);
64
+ if (!fs.existsSync(resolvedConfigPath)) {
65
+ console.error(`Error: config dir not found at ${resolvedConfigPath}`);
66
+ process.exit(1);
67
+ }
68
+ if (!fs.statSync(resolvedConfigPath).isDirectory()) {
69
+ console.error(`Error: config path is not a directory: ${resolvedConfigPath}`);
70
+ process.exit(1);
71
+ }
72
+ }
44
73
  process.chdir(path.dirname(resolvedEnvPath));
45
74
  const result = dotenv.config({ path: resolvedEnvPath });
46
75
  if (result.error) {
@@ -50,7 +79,8 @@ if (result.error) {
50
79
  }
51
80
  async function main() {
52
81
  try {
53
- const { store, vars } = await startMailMagicServer();
82
+ const envOverrides = resolvedConfigPath ? { CONFIG_PATH: resolvedConfigPath } : {};
83
+ const { store, vars } = await startMailMagicServer({}, envOverrides);
54
84
  console.log(`Using config path: ${store.configpath}`);
55
85
  console.log(`mail-magic server listening on ${vars.API_HOST}:${vars.API_PORT}`);
56
86
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@technomoron/mail-magic",
3
- "version": "1.0.34",
3
+ "version": "1.0.35",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1 +0,0 @@
1
- export * from '../util/form-replyto.js';
@@ -1 +0,0 @@
1
- export * from '../util/form-submission.js';