@meridianjs/framework 0.1.0 → 0.1.2

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.
Files changed (2) hide show
  1. package/dist/index.js +109 -99
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -138,9 +138,9 @@ async function resolveModuleDefinition(config, rootDir) {
138
138
  }
139
139
 
140
140
  // src/plugin-loader.ts
141
- import path6 from "path";
142
- import fs4 from "fs/promises";
143
- import { pathToFileURL as pathToFileURL6 } from "url";
141
+ import path7 from "path";
142
+ import fs5 from "fs/promises";
143
+ import { pathToFileURL as pathToFileURL7 } from "url";
144
144
  import { createRequire } from "module";
145
145
 
146
146
  // src/route-loader.ts
@@ -316,13 +316,94 @@ async function loadJobs(container, jobsDir) {
316
316
  }
317
317
  }
318
318
 
319
+ // src/link-loader.ts
320
+ import fs4 from "fs/promises";
321
+ import path6 from "path";
322
+ import { pathToFileURL as pathToFileURL6 } from "url";
323
+ async function loadLinks(container, linksDir) {
324
+ const logger = container.resolve("logger");
325
+ const definitions = [];
326
+ try {
327
+ await fs4.access(linksDir);
328
+ } catch {
329
+ logger.debug(`No links directory at ${linksDir}, skipping.`);
330
+ registerEmptyServices(container);
331
+ return;
332
+ }
333
+ const files = await fs4.readdir(linksDir);
334
+ for (const file of files) {
335
+ if (!/\.(ts|mts|js|mjs|cjs)$/.test(file)) continue;
336
+ const fullPath = path6.join(linksDir, file);
337
+ let mod;
338
+ try {
339
+ mod = await import(pathToFileURL6(fullPath).href);
340
+ } catch (err) {
341
+ logger.error(`Failed to load link file ${file}: ${err.message}`);
342
+ continue;
343
+ }
344
+ const def = mod.default;
345
+ if (def?.linkTableName) {
346
+ definitions.push(def);
347
+ logger.debug(`Link loaded: ${def.linkTableName}`);
348
+ }
349
+ }
350
+ let existingDefs = [];
351
+ try {
352
+ const existingLink = container.resolve("link");
353
+ existingDefs = existingLink.getDefinitions?.() ?? [];
354
+ } catch {
355
+ }
356
+ const allDefs = [...existingDefs, ...definitions];
357
+ const linkService = new LinkService(allDefs, container, logger);
358
+ const queryService = new QueryService(allDefs, container, logger);
359
+ container.register({
360
+ link: linkService,
361
+ query: queryService
362
+ });
363
+ logger.info(`Loaded ${allDefs.length} module link(s)`);
364
+ }
365
+ function registerEmptyServices(container) {
366
+ const link = new LinkService([], container, null);
367
+ const query = new QueryService([], container, null);
368
+ container.register({ link, query });
369
+ }
370
+ var LinkService = class {
371
+ constructor(defs, container, logger) {
372
+ this.defs = defs;
373
+ this.container = container;
374
+ this.logger = logger;
375
+ this.defsByTable = new Map(defs.map((d) => [d.linkTableName, d]));
376
+ }
377
+ defsByTable;
378
+ async create(linkTableName, leftId, rightId, data) {
379
+ this.logger?.debug(`Link.create: ${linkTableName} ${leftId} \u2192 ${rightId}`);
380
+ }
381
+ async dismiss(linkTableName, leftId, rightId) {
382
+ this.logger?.debug(`Link.dismiss: ${linkTableName} ${leftId} \u2192 ${rightId}`);
383
+ }
384
+ getDefinitions() {
385
+ return this.defs;
386
+ }
387
+ };
388
+ var QueryService = class {
389
+ constructor(defs, container, logger) {
390
+ this.defs = defs;
391
+ this.container = container;
392
+ this.logger = logger;
393
+ }
394
+ async graph(options) {
395
+ this.logger?.debug(`Query.graph: ${options.entity}`, { fields: options.fields });
396
+ return { data: [] };
397
+ }
398
+ };
399
+
319
400
  // src/plugin-loader.ts
320
401
  async function loadPlugins(container, plugins, rootDir) {
321
402
  const logger = container.resolve("logger");
322
403
  for (const plugin of plugins) {
323
404
  logger.info(`Loading plugin: ${plugin.resolve}`);
324
- const isLocalPath = plugin.resolve.startsWith(".") || path6.isAbsolute(plugin.resolve);
325
- const importPath = isLocalPath ? pathToFileURL6(path6.resolve(rootDir, plugin.resolve)).href : plugin.resolve;
405
+ const isLocalPath = plugin.resolve.startsWith(".") || path7.isAbsolute(plugin.resolve);
406
+ const importPath = isLocalPath ? pathToFileURL7(path7.resolve(rootDir, plugin.resolve)).href : plugin.resolve;
326
407
  let pluginMod;
327
408
  try {
328
409
  pluginMod = await import(importPath);
@@ -334,12 +415,12 @@ async function loadPlugins(container, plugins, rootDir) {
334
415
  if (pluginMod.pluginRoot && typeof pluginMod.pluginRoot === "string") {
335
416
  scanRoot = pluginMod.pluginRoot;
336
417
  } else if (isLocalPath) {
337
- const resolvedPath = path6.resolve(rootDir, plugin.resolve);
418
+ const resolvedPath = path7.resolve(rootDir, plugin.resolve);
338
419
  try {
339
- const stat = await fs4.stat(resolvedPath);
340
- scanRoot = stat.isDirectory() ? resolvedPath : path6.dirname(resolvedPath);
420
+ const stat = await fs5.stat(resolvedPath);
421
+ scanRoot = stat.isDirectory() ? resolvedPath : path7.dirname(resolvedPath);
341
422
  } catch {
342
- scanRoot = path6.dirname(resolvedPath);
423
+ scanRoot = path7.dirname(resolvedPath);
343
424
  }
344
425
  } else {
345
426
  scanRoot = resolveNpmPackageRoot(plugin.resolve, rootDir);
@@ -370,19 +451,20 @@ async function autoScanPlugin(scanRoot, container, logger) {
370
451
  const candidates = [
371
452
  scanRoot,
372
453
  // pluginRoot already points to compiled dir
373
- path6.join(scanRoot, "dist"),
454
+ path7.join(scanRoot, "dist"),
374
455
  // package root → try dist/ first
375
- path6.join(scanRoot, "src")
456
+ path7.join(scanRoot, "src")
376
457
  // package root → try src/ (tsx dev mode)
377
458
  ];
378
459
  for (const candidate of candidates) {
379
- const apiDir = path6.join(candidate, "api");
460
+ const apiDir = path7.join(candidate, "api");
380
461
  try {
381
- await fs4.access(apiDir);
462
+ await fs5.access(apiDir);
382
463
  await Promise.all([
383
464
  loadRoutes(server, container, apiDir),
384
- loadSubscribers(container, path6.join(candidate, "subscribers")),
385
- loadJobs(container, path6.join(candidate, "jobs"))
465
+ loadSubscribers(container, path7.join(candidate, "subscribers")),
466
+ loadJobs(container, path7.join(candidate, "jobs")),
467
+ loadLinks(container, path7.join(candidate, "links"))
386
468
  ]);
387
469
  logger.debug(`Plugin auto-scanned from: ${candidate}`);
388
470
  return;
@@ -393,20 +475,20 @@ async function autoScanPlugin(scanRoot, container, logger) {
393
475
  }
394
476
  function resolveNpmPackageRoot(packageName, fromDir) {
395
477
  try {
396
- const require2 = createRequire(path6.join(fromDir, "synthetic.cjs"));
478
+ const require2 = createRequire(path7.join(fromDir, "synthetic.cjs"));
397
479
  const pkgJsonPath = require2.resolve(`${packageName}/package.json`);
398
- return path6.dirname(pkgJsonPath);
480
+ return path7.dirname(pkgJsonPath);
399
481
  } catch {
400
482
  try {
401
- const require2 = createRequire(path6.join(fromDir, "synthetic.cjs"));
483
+ const require2 = createRequire(path7.join(fromDir, "synthetic.cjs"));
402
484
  const mainPath = require2.resolve(packageName);
403
- let dir = path6.dirname(mainPath);
404
- while (dir !== path6.dirname(dir)) {
485
+ let dir = path7.dirname(mainPath);
486
+ while (dir !== path7.dirname(dir)) {
405
487
  try {
406
- require2.resolve(path6.join(dir, "package.json"));
488
+ require2.resolve(path7.join(dir, "package.json"));
407
489
  return dir;
408
490
  } catch {
409
- dir = path6.dirname(dir);
491
+ dir = path7.dirname(dir);
410
492
  }
411
493
  }
412
494
  } catch {
@@ -415,80 +497,6 @@ function resolveNpmPackageRoot(packageName, fromDir) {
415
497
  }
416
498
  }
417
499
 
418
- // src/link-loader.ts
419
- import fs5 from "fs/promises";
420
- import path7 from "path";
421
- import { pathToFileURL as pathToFileURL7 } from "url";
422
- async function loadLinks(container, linksDir) {
423
- const logger = container.resolve("logger");
424
- const definitions = [];
425
- try {
426
- await fs5.access(linksDir);
427
- } catch {
428
- logger.debug(`No links directory at ${linksDir}, skipping.`);
429
- registerEmptyServices(container);
430
- return;
431
- }
432
- const files = await fs5.readdir(linksDir);
433
- for (const file of files) {
434
- if (!/\.(ts|mts|js|mjs|cjs)$/.test(file)) continue;
435
- const fullPath = path7.join(linksDir, file);
436
- let mod;
437
- try {
438
- mod = await import(pathToFileURL7(fullPath).href);
439
- } catch (err) {
440
- logger.error(`Failed to load link file ${file}: ${err.message}`);
441
- continue;
442
- }
443
- const def = mod.default;
444
- if (def?.linkTableName) {
445
- definitions.push(def);
446
- logger.debug(`Link loaded: ${def.linkTableName}`);
447
- }
448
- }
449
- const linkService = new LinkService(definitions, container, logger);
450
- const queryService = new QueryService(definitions, container, logger);
451
- container.register({
452
- link: linkService,
453
- query: queryService
454
- });
455
- logger.info(`Loaded ${definitions.length} module link(s)`);
456
- }
457
- function registerEmptyServices(container) {
458
- const link = new LinkService([], container, null);
459
- const query = new QueryService([], container, null);
460
- container.register({ link, query });
461
- }
462
- var LinkService = class {
463
- constructor(defs, container, logger) {
464
- this.defs = defs;
465
- this.container = container;
466
- this.logger = logger;
467
- this.defsByTable = new Map(defs.map((d) => [d.linkTableName, d]));
468
- }
469
- defsByTable;
470
- async create(linkTableName, leftId, rightId, data) {
471
- this.logger?.debug(`Link.create: ${linkTableName} ${leftId} \u2192 ${rightId}`);
472
- }
473
- async dismiss(linkTableName, leftId, rightId) {
474
- this.logger?.debug(`Link.dismiss: ${linkTableName} ${leftId} \u2192 ${rightId}`);
475
- }
476
- getDefinitions() {
477
- return this.defs;
478
- }
479
- };
480
- var QueryService = class {
481
- constructor(defs, container, logger) {
482
- this.defs = defs;
483
- this.container = container;
484
- this.logger = logger;
485
- }
486
- async graph(options) {
487
- this.logger?.debug(`Query.graph: ${options.entity}`, { fields: options.fields });
488
- return { data: [] };
489
- }
490
- };
491
-
492
500
  // src/server.ts
493
501
  import express from "express";
494
502
  import cors from "cors";
@@ -636,9 +644,11 @@ async function bootstrap(opts) {
636
644
  },
637
645
  async stop() {
638
646
  logger.info("Shutting down Meridian server...");
639
- await new Promise((resolve, reject) => {
640
- httpServer.close((err) => err ? reject(err) : resolve());
641
- });
647
+ if (httpServer.listening) {
648
+ await new Promise((resolve, reject) => {
649
+ httpServer.close((err) => err ? reject(err) : resolve());
650
+ });
651
+ }
642
652
  try {
643
653
  const bus = container.resolve("eventBus");
644
654
  await bus.close?.();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meridianjs/framework",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Core Meridian framework: bootstrap, DI container, module/route/subscriber/job loaders",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",