arcway 0.4.16 → 0.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcway",
3
- "version": "0.4.16",
3
+ "version": "0.4.18",
4
4
  "description": "A convention-based framework for building modular monoliths with strict domain boundaries.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,4 +1,5 @@
1
1
  import path from 'node:path';
2
+ import { normalizePort } from '../port.js';
2
3
 
3
4
  const DEFAULTS = {
4
5
  sqliteFilename: '.build/db/arcway.db',
@@ -15,6 +16,12 @@ function resolve(config, { rootDir } = {}) {
15
16
  const db = { ...DEFAULTS, ...config.database };
16
17
  // Resolve friendly client names to actual knex driver names
17
18
  db.client = CLIENT_MAP[db.client] ?? db.client;
19
+ if (db.connection && typeof db.connection === 'object' && db.connection.port !== undefined) {
20
+ db.connection = {
21
+ ...db.connection,
22
+ port: normalizePort(db.connection.port, 'database.connection.port'),
23
+ };
24
+ }
18
25
  if (db.dir && !path.isAbsolute(db.dir)) {
19
26
  db.dir = path.resolve(rootDir, db.dir);
20
27
  }
@@ -1,4 +1,5 @@
1
1
  import { normalizeDurationDays, normalizeDurationSeconds } from '../duration.js';
2
+ import { normalizePort } from '../port.js';
2
3
 
3
4
  const DEFAULTS = {
4
5
  driver: 'console',
@@ -8,6 +9,12 @@ const DEFAULTS = {
8
9
  function resolve(config) {
9
10
  if (!config.mail) return config;
10
11
  const mail = { ...DEFAULTS, ...config.mail };
12
+ if (mail.smtp?.port !== undefined) {
13
+ mail.smtp = {
14
+ ...mail.smtp,
15
+ port: normalizePort(mail.smtp.port, 'mail.smtp.port'),
16
+ };
17
+ }
11
18
  if (mail.inbound?.imap?.pollIntervalSeconds !== undefined) {
12
19
  mail.inbound.imap.pollIntervalSeconds = normalizeDurationSeconds(
13
20
  mail.inbound.imap.pollIntervalSeconds,
@@ -72,6 +72,13 @@ function resolve(config, { rootDir } = {}) {
72
72
  ...(hmr ? { hmr } : {}),
73
73
  },
74
74
  };
75
+ if (
76
+ pages.language != null &&
77
+ (typeof pages.language !== 'string' ||
78
+ !/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/.test(pages.language))
79
+ ) {
80
+ throw new TypeError('Invalid config: pages.language must be a valid language tag');
81
+ }
75
82
  if (pages.rewrite != null) {
76
83
  if (
77
84
  typeof pages.rewrite !== 'object' ||
@@ -1,14 +1,15 @@
1
1
  import { resolveSessionConfig } from '../../session/index.js';
2
2
 
3
3
  function resolve(config, { mode } = {}) {
4
- if (!config.session) return config;
4
+ if (config.session === false) return { ...config, session: undefined };
5
5
  const vaultSession = config.vault?.values?.session;
6
+ if (config.session == null && !vaultSession) return config;
6
7
  const sessionKeyring = config.vault?.keyring?.map((entry) => ({
7
8
  id: entry.id,
8
9
  password: entry.secrets.session,
9
10
  }));
10
11
  const sessionInput = {
11
- ...config.session,
12
+ ...(config.session ?? {}),
12
13
  password: vaultSession,
13
14
  keyring: sessionKeyring,
14
15
  };
@@ -0,0 +1,10 @@
1
+ function normalizePort(value, name) {
2
+ if (value === undefined || value === null || value === '') return value;
3
+ const port = typeof value === 'string' && /^\d+$/.test(value) ? Number(value) : value;
4
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
5
+ throw new TypeError(`Invalid config: ${name} must be an integer from 1 to 65535`);
6
+ }
7
+ return port;
8
+ }
9
+
10
+ export { normalizePort };
@@ -35,6 +35,7 @@ function createPagesHandler(options) {
35
35
  let manifestPath = path.join(outDir, 'pages-manifest.json');
36
36
  const sessionConfig = options.session;
37
37
  const appContext = options.appContext ?? null;
38
+ const documentLanguage = options.documentLanguage;
38
39
  const rewrite = options.rewrite ?? null;
39
40
  const mode = options.mode ?? 'production';
40
41
  const devMode = mode === 'development';
@@ -141,6 +142,7 @@ function createPagesHandler(options) {
141
142
  manifest,
142
143
  cacheVersion,
143
144
  projectReact,
145
+ documentLanguage,
144
146
  );
145
147
  } else if (!res.headersSent) {
146
148
  res.writeHead(500, getHtmlHeaders());
@@ -225,6 +227,7 @@ function createPagesHandler(options) {
225
227
  componentCache,
226
228
  cacheVersion,
227
229
  projectReact,
230
+ documentLanguage,
228
231
  );
229
232
  return true;
230
233
  }
@@ -315,6 +318,7 @@ function createPagesHandler(options) {
315
318
  status: loaderResult?.status,
316
319
  headers: loaderResult?.headers,
317
320
  },
321
+ documentLanguage,
318
322
  );
319
323
  } catch (err) {
320
324
  await renderRuntimeError(err, res);
@@ -333,6 +337,7 @@ function createPagesHandler(options) {
333
337
  manifest,
334
338
  cacheVersion,
335
339
  projectReact,
340
+ documentLanguage,
336
341
  );
337
342
  } else {
338
343
  res.writeHead(404, getHtmlHeaders());
@@ -363,6 +368,7 @@ async function renderDevBuildError(
363
368
  componentCache,
364
369
  cacheVersion,
365
370
  projectReact,
371
+ documentLanguage,
366
372
  ) {
367
373
  const errorMessage = err instanceof Error ? err.stack || err.message : String(err);
368
374
  if (manifest.errorBundle && !res.headersSent) {
@@ -376,6 +382,7 @@ async function renderDevBuildError(
376
382
  manifest,
377
383
  cacheVersion,
378
384
  projectReact,
385
+ documentLanguage,
379
386
  );
380
387
  return;
381
388
  }
@@ -55,6 +55,7 @@ class PagesRouter {
55
55
  ...(isDev ? { outDir } : { resolveOutDir }),
56
56
  session: config.session,
57
57
  appContext: this.appContext,
58
+ documentLanguage: config.pages?.language,
58
59
  rewrite: config.pages?.rewrite,
59
60
  mode,
60
61
  viteDev,
@@ -130,10 +130,18 @@ window.__vite_plugin_react_preamble_installed__ = true;
130
130
  `<script type="module" src="${route.clientBundle}"></script>`,
131
131
  ].join('\n');
132
132
  }
133
- function buildHtmlShell({ headHtml, fontPreloadTags, cssLinkTag, bodysuffix }) {
133
+ function buildHtmlShell({
134
+ headHtml,
135
+ fontPreloadTags,
136
+ cssLinkTag,
137
+ bodysuffix,
138
+ documentLanguage,
139
+ }) {
140
+ const languageAttribute = documentLanguage ? ` lang="${documentLanguage}"` : '';
141
+
134
142
  return {
135
143
  head: `<!DOCTYPE html>
136
- <html>
144
+ <html${languageAttribute}>
137
145
  <head>
138
146
  <meta charset="utf-8" />
139
147
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
@@ -165,6 +173,7 @@ async function renderPage(
165
173
  onRenderFailure = null,
166
174
  pageProps = params,
167
175
  response = {},
176
+ documentLanguage,
168
177
  ) {
169
178
  const { createElement, renderToPipeableStream } = react;
170
179
  const bundlePath = path.join(outDir, route.serverBundle);
@@ -243,6 +252,7 @@ async function renderPage(
243
252
  ${hmrTag}
244
253
  ${scriptTags}
245
254
  ${liveReloadTag}`,
255
+ documentLanguage,
246
256
  });
247
257
  res.write(shell.head);
248
258
  pass = new PassThrough();
@@ -310,6 +320,7 @@ async function renderErrorPage(
310
320
  manifest,
311
321
  cacheVersion,
312
322
  react,
323
+ documentLanguage,
313
324
  ) {
314
325
  const { createElement, renderToPipeableStream } = react;
315
326
  const fullPath = path.join(outDir, bundlePath);
@@ -349,7 +360,12 @@ async function renderErrorPage(
349
360
  if (res.headersSent || closed) return;
350
361
  const headHtml = renderHeadToString(headData);
351
362
  res.writeHead(statusCode, getHtmlHeaders());
352
- const shell = buildHtmlShell({ headHtml, fontPreloadTags, cssLinkTag });
363
+ const shell = buildHtmlShell({
364
+ headHtml,
365
+ fontPreloadTags,
366
+ cssLinkTag,
367
+ documentLanguage,
368
+ });
353
369
  res.write(shell.head);
354
370
  pass = new PassThrough();
355
371
  pass.on('data', (chunk) => {
@@ -224,7 +224,7 @@ function getViteServerOptions(config, hmrServer) {
224
224
  const hmr = config?.pages?.vite?.hmr;
225
225
  return {
226
226
  middlewareMode: true,
227
- ...(hmr ? { hmr: { ...hmr, ...(hmrServer ? { server: hmrServer } : {}) } } : {}),
227
+ hmr: { ...hmr, server: hmrServer },
228
228
  };
229
229
  }
230
230
 
@@ -239,7 +239,7 @@ async function createViteHmrServer(log, { host = '0.0.0.0', port = 24678 } = {})
239
239
 
240
240
  async function createViteDevRouter({ rootDir, log, config }) {
241
241
  const appAliases = resolveAppAliases(rootDir);
242
- const hmrServer = config?.pages?.vite?.hmr ? await createViteHmrServer(log) : null;
242
+ const hmrServer = await createViteHmrServer(log);
243
243
  let vite;
244
244
  try {
245
245
  vite = await createViteServer({