arcway 0.3.0 → 0.3.1

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.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "A convention-based framework for building modular monoliths with strict domain boundaries.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -34,10 +34,19 @@ const SERVER_ONLY_PACKAGES = new Set([
34
34
  'commander',
35
35
  'glob',
36
36
  'esbuild',
37
+ 'vite',
38
+ '@vitejs/plugin-react',
39
+ '@babel/core',
40
+ '@babel/preset-typescript',
41
+ '@tailwindcss/node',
42
+ '@tailwindcss/vite',
37
43
  'postcss',
38
44
  '@tailwindcss/postcss',
39
45
  'tailwindcss',
40
46
  '@tailwindcss/oxide',
47
+ 'playwright',
48
+ 'playwright-core',
49
+ 'chromium-bidi',
41
50
  'tsx',
42
51
  'cache-manager',
43
52
  'rate-limiter-flexible',
@@ -3,7 +3,7 @@ import { discoverModules } from '../discovery.js';
3
3
  async function runSeeds(db, seedsDir) {
4
4
  const entries = await discoverModules(seedsDir, { label: 'seed file' });
5
5
  const results = [];
6
- for (const { name, filePath, module } of entries) {
6
+ for (const { name, module } of entries) {
7
7
  const seedFn = module.default;
8
8
  if (typeof seedFn !== 'function') {
9
9
  throw new Error(`Seed file "${name}" must export a default function`);
@@ -1,4 +1,3 @@
1
- import path from 'node:path';
2
1
  import { discoverModules } from '../discovery.js';
3
2
  import { buildContext } from '../context.js';
4
3
 
@@ -64,7 +63,7 @@ class EventHandler {
64
63
  const groupName =
65
64
  consumerGroup === false
66
65
  ? undefined
67
- : consumerGroup ?? `listener:${relativePath}:${items.length > 1 ? i : 0}`;
66
+ : (consumerGroup ?? `listener:${relativePath}:${items.length > 1 ? i : 0}`);
68
67
  this._events.subscribe(
69
68
  event,
70
69
  (payload, _eventName) => {
@@ -75,7 +74,9 @@ class EventHandler {
75
74
  );
76
75
  this._listeners.push({ event, fileName: relativePath });
77
76
  }
78
- this._log?.info(` ${relativePath} → ${event}${items.length > 1 ? ` (${items.length} listeners)` : ''}`);
77
+ this._log?.info(
78
+ ` ${relativePath} → ${event}${items.length > 1 ? ` (${items.length} listeners)` : ''}`,
79
+ );
79
80
  }
80
81
  }
81
82
 
@@ -1,6 +1,5 @@
1
1
  import { Worker } from 'node:worker_threads';
2
2
  import { fileURLToPath } from 'node:url';
3
- import path from 'node:path';
4
3
 
5
4
  const WORKER_ENTRY_URL = new URL('./worker-entry.js', import.meta.url);
6
5
 
@@ -210,7 +209,10 @@ class WorkerPool {
210
209
  resolve();
211
210
  };
212
211
  const timer = setTimeout(() => {
213
- worker.terminate().catch(() => {}).finally(done);
212
+ worker
213
+ .terminate()
214
+ .catch(() => {})
215
+ .finally(done);
214
216
  }, gracefulExitMs);
215
217
  if (typeof timer.unref === 'function') timer.unref();
216
218
  worker.once('exit', done);
@@ -219,7 +221,10 @@ class WorkerPool {
219
221
  worker.postMessage({ id: 0, task: { __shutdown: true } });
220
222
  } catch {
221
223
  // Worker already down or channel closed — terminate to be safe.
222
- worker.terminate().catch(() => {}).finally(done);
224
+ worker
225
+ .terminate()
226
+ .catch(() => {})
227
+ .finally(done);
223
228
  }
224
229
  });
225
230
  }
@@ -1,7 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { createMcpRuntime } from './runtime.js';
3
- import { createDebugHandler, isDebugRequest } from './debug-api.js';
4
- import { startMcpServer } from './server.js';
3
+ import { createDebugHandler } from './debug-api.js';
5
4
 
6
5
  const DEBUG_PREFIX = '/_mcp';
7
6
 
@@ -1,4 +1,3 @@
1
- import path from 'node:path';
2
1
  import { z } from 'zod';
3
2
  import { makeConfig } from '#server/config/loader.js';
4
3
  import { discoverRoutes } from '#server/router/routes.js';
@@ -44,7 +44,7 @@ async function hashFileContent(filePath) {
44
44
  }
45
45
  }
46
46
 
47
- function resolveInputPath(p, rootDir) {
47
+ function resolveInputPath(p) {
48
48
  if (path.isAbsolute(p)) return p;
49
49
  // esbuild metafile paths may be relative to cwd; try that first, then rootDir.
50
50
  const abs = path.resolve(p);
@@ -473,9 +473,7 @@ async function pruneStaleCache({ rootDir, kind }) {
473
473
  const metaPath = path.join(bucket, metaFile);
474
474
  const meta = await readJson(metaPath);
475
475
  const stale =
476
- !meta ||
477
- !Array.isArray(meta.inputs) ||
478
- (await hashInputs(meta.inputs)) !== meta.inputsHash;
476
+ !meta || !Array.isArray(meta.inputs) || (await hashInputs(meta.inputs)) !== meta.inputsHash;
479
477
 
480
478
  if (!stale) {
481
479
  kept += 1;
@@ -1,18 +1,27 @@
1
1
  import { createRequire } from 'node:module';
2
2
  import { NODE_BUILTINS, SERVER_ONLY_PACKAGES } from '../constants.js';
3
- function serverExternalsPlugin() {
3
+
4
+ function packageNameForImport(specifier) {
5
+ const parts = specifier.split('/');
6
+ return specifier.startsWith('@') && parts.length >= 2 ? `${parts[0]}/${parts[1]}` : parts[0];
7
+ }
8
+
9
+ function isBarePackageImport(specifier) {
10
+ if (/^[A-Za-z]:/.test(specifier)) return false;
11
+ if (specifier.startsWith('node:')) return false;
12
+ return /^[^.\/\#]/.test(specifier);
13
+ }
14
+
15
+ function packageExternalsPlugin({ name, shouldBundlePackage }) {
4
16
  const resolvedCache = new Map();
5
17
  return {
6
- name: 'arcway-server-externals',
18
+ name,
7
19
  setup(build) {
8
20
  build.onResolve({ filter: /^[^.\/\#]/ }, (args) => {
9
- if (/^[A-Za-z]:/.test(args.path)) return void 0;
10
- if (args.path.startsWith('node:')) return void 0;
11
- const parts = args.path.split('/');
12
- const pkgName =
13
- args.path.startsWith('@') && parts.length >= 2 ? `${parts[0]}/${parts[1]}` : parts[0];
21
+ if (!isBarePackageImport(args.path)) return void 0;
22
+ const pkgName = packageNameForImport(args.path);
14
23
  if (!resolvedCache.has(pkgName)) {
15
- resolvedCache.set(pkgName, needsBundling(pkgName, args.resolveDir));
24
+ resolvedCache.set(pkgName, shouldBundlePackage(pkgName, args.resolveDir));
16
25
  }
17
26
  if (resolvedCache.get(pkgName)) return void 0;
18
27
  return { path: args.path, external: true };
@@ -20,6 +29,21 @@ function serverExternalsPlugin() {
20
29
  },
21
30
  };
22
31
  }
32
+
33
+ function serverExternalsPlugin() {
34
+ return packageExternalsPlugin({
35
+ name: 'arcway-server-externals',
36
+ shouldBundlePackage: needsBundling,
37
+ });
38
+ }
39
+
40
+ function pluginPackageExternalsPlugin() {
41
+ return packageExternalsPlugin({
42
+ name: 'arcway-plugin-package-externals',
43
+ shouldBundlePackage: () => false,
44
+ });
45
+ }
46
+
23
47
  function needsBundling(pkgName, resolveDir) {
24
48
  try {
25
49
  const require2 = createRequire(resolveDir + '/');
@@ -44,9 +68,7 @@ function clientIsolationPlugin() {
44
68
  return void 0;
45
69
  });
46
70
  build.onResolve({ filter: /.*/ }, (args) => {
47
- const parts = args.path.split('/');
48
- const pkgName =
49
- args.path.startsWith('@') && parts.length >= 2 ? `${parts[0]}/${parts[1]}` : parts[0];
71
+ const pkgName = packageNameForImport(args.path);
50
72
  if (SERVER_ONLY_PACKAGES.has(pkgName)) {
51
73
  return { path: args.path, namespace: STUB_NAMESPACE };
52
74
  }
@@ -73,4 +95,9 @@ function clientIsolationPlugin() {
73
95
  },
74
96
  };
75
97
  }
76
- export { clientIsolationPlugin, serverExternalsPlugin };
98
+ export {
99
+ clientIsolationPlugin,
100
+ packageNameForImport,
101
+ pluginPackageExternalsPlugin,
102
+ serverExternalsPlugin,
103
+ };
@@ -391,7 +391,7 @@ async function runPageMiddleware(
391
391
  }
392
392
  return null;
393
393
  }
394
- function buildClientManifestJson(manifest, { rootDir, outDir, viteDev } = {}) {
394
+ function buildClientManifestJson(manifest, { rootDir, viteDev } = {}) {
395
395
  if (viteDev) {
396
396
  return buildViteClientManifestJson(manifest, rootDir);
397
397
  }
@@ -104,12 +104,7 @@ async function createLazyPagesContext(options) {
104
104
  { srcPath: path.resolve(m.filePath), built: false, stale: false },
105
105
  ]),
106
106
  ),
107
- loadings: new Map(
108
- loadings.map((l) => [
109
- l.dirPath,
110
- { srcPath: path.resolve(l.filePath) },
111
- ]),
112
- ),
107
+ loadings: new Map(loadings.map((l) => [l.dirPath, { srcPath: path.resolve(l.filePath) }])),
113
108
  stylesPath: stylesPath ? path.resolve(stylesPath) : null,
114
109
  version: 0,
115
110
  };
@@ -312,10 +307,7 @@ async function createLazyPagesContext(options) {
312
307
  }
313
308
  const existing = inFlightPages.get(pattern);
314
309
  if (existing) return existing;
315
- const task = Promise.all([
316
- limit(() => buildPageServer(entry)),
317
- ensureChainBuilt(entry),
318
- ])
310
+ const task = Promise.all([limit(() => buildPageServer(entry)), ensureChainBuilt(entry)])
319
311
  .then(() => {
320
312
  entry.layoutServerBundles = entry.layoutDirs
321
313
  .map((d) => manifest.layouts.get(d)?.serverBundle)
@@ -452,7 +444,6 @@ async function createLazyPagesContext(options) {
452
444
 
453
445
  const task = (async () => {
454
446
  const previousMetafile = currentClientMetafile;
455
- const previousCssBundle = manifest.cssBundle ?? null;
456
447
  const timestamp = Date.now();
457
448
 
458
449
  const [clientResult, cssBundle] = await Promise.all([
@@ -535,12 +526,7 @@ async function createLazyPagesContext(options) {
535
526
  if (disposed) throw new Error('Lazy pages context is disposed');
536
527
  if (inFlightRediscover) return inFlightRediscover;
537
528
  const task = (async () => {
538
- const [
539
- nextPages,
540
- nextLayouts,
541
- nextLoadings,
542
- nextMiddlewares,
543
- ] = await Promise.all([
529
+ const [nextPages, nextLayouts, nextLoadings, nextMiddlewares] = await Promise.all([
544
530
  discoverPages(pagesDir),
545
531
  discoverLayouts(pagesDir),
546
532
  discoverLoadings(pagesDir),
@@ -4,6 +4,7 @@ import { pathToFileURL } from 'node:url';
4
4
  import { build } from 'esbuild';
5
5
  import { discoverFiles } from '../discovery.js';
6
6
  import { loadModule } from '../module-loader.js';
7
+ import { pluginPackageExternalsPlugin } from '../pages/build-plugins.js';
7
8
 
8
9
  let bundleCounter = 0;
9
10
 
@@ -101,6 +102,7 @@ async function loadPluginBundle(packageDir) {
101
102
  platform: 'node',
102
103
  target: 'node20',
103
104
  logLevel: 'silent',
105
+ plugins: [pluginPackageExternalsPlugin()],
104
106
  });
105
107
 
106
108
  const bundled = await loadModule(outFile);
@@ -1,4 +1,3 @@
1
- import path from 'node:path';
2
1
  import fs from 'node:fs';
3
2
  import { serveStaticAsset, servePublicFile } from '../pages/static.js';
4
3