@moshaver/cmb-starter 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mobin Karam
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # @moshaver/cmb-starter
2
+
3
+ [English](#english) | [فارسی](#فارسی)
4
+
5
+ ## English
6
+
7
+ `@moshaver/cmb-starter` creates a framework-neutral CMB runtime from one small
8
+ configuration object. It resolves module dependencies, exposes lifecycle and
9
+ readiness APIs, and leaves HTTP transport, database drivers, secrets, routes,
10
+ and product policy to the host application.
11
+
12
+ ```bash
13
+ npm install @moshaver/cmb-starter
14
+ ```
15
+
16
+ Create one `cmb.config.cjs` file:
17
+
18
+ ```js
19
+ module.exports = {
20
+ serviceName: "notes-api",
21
+ modules: ["auth", "authorization", "notifications", "realtime"],
22
+ };
23
+ ```
24
+
25
+ Load it at the application's composition root:
26
+
27
+ ```js
28
+ const config = require("./cmb.config.cjs");
29
+ const { createCmbRuntime } = require("@moshaver/cmb-starter");
30
+
31
+ const cmb = createCmbRuntime(config);
32
+ await cmb.start();
33
+ await cmb.ready();
34
+ ```
35
+
36
+ Dependencies such as `identity` and `tenancy` are resolved automatically. Add
37
+ your own product module descriptors through `registrations`; keep product
38
+ routes, roles, storage adapters, and secrets outside this package.
39
+
40
+ ## فارسی
41
+
42
+ پکیج `@moshaver/cmb-starter` با یک شیء پیکربندی کوچک، runtime مستقل از
43
+ فریم‌ورک CMB را می‌سازد. وابستگی ماژول‌ها، چرخهٔ اجرا و وضعیت آماده‌بودن را
44
+ مدیریت می‌کند؛ اما HTTP، درایور پایگاه‌داده، رازها، مسیرها و قوانین محصول
45
+ همچنان مسئولیت برنامهٔ میزبان هستند.
46
+
47
+ ```bash
48
+ npm install @moshaver/cmb-starter
49
+ ```
50
+
51
+ یک فایل `cmb.config.cjs` بسازید:
52
+
53
+ ```js
54
+ module.exports = {
55
+ serviceName: "notes-api",
56
+ modules: ["auth", "authorization", "notifications", "realtime"],
57
+ };
58
+ ```
59
+
60
+ سپس آن را در composition root برنامه بارگذاری کنید:
61
+
62
+ ```js
63
+ const config = require("./cmb.config.cjs");
64
+ const { createCmbRuntime } = require("@moshaver/cmb-starter");
65
+
66
+ const cmb = createCmbRuntime(config);
67
+ await cmb.start();
68
+ await cmb.ready();
69
+ ```
70
+
71
+ وابستگی‌هایی مانند `identity` و `tenancy` خودکار حل می‌شوند. descriptorهای
72
+ محصول خود را با `registrations` اضافه کنید و مسیرها، نقش‌ها، adapterهای ذخیره‌سازی
73
+ و رازهای محصول را بیرون از این پکیج نگه دارید.
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@moshaver/cmb-starter",
3
+ "version": "0.1.0",
4
+ "description": "Composable Modular Backend starter primitives.",
5
+ "type": "commonjs",
6
+ "main": "./src/index.js",
7
+ "types": "./src/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "require": "./src/index.js",
11
+ "types": "./src/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "src",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "keywords": [
20
+ "cmb",
21
+ "modular-backend",
22
+ "backend",
23
+ "framework-agnostic",
24
+ "starter"
25
+ ],
26
+ "engines": {
27
+ "node": ">=22.13.0 <23"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/Mobin-Karam/moshaver.git",
32
+ "directory": "packages/cmb/starter"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/Mobin-Karam/moshaver/issues"
36
+ },
37
+ "homepage": "https://github.com/Mobin-Karam/moshaver/tree/main/packages/cmb",
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "license": "MIT",
42
+ "sideEffects": false,
43
+ "dependencies": {
44
+ "@moshaver/cmb-activity": "^0.1.0",
45
+ "@moshaver/cmb-auth": "^0.1.0",
46
+ "@moshaver/cmb-authorization": "^0.1.0",
47
+ "@moshaver/cmb-data-transfer": "^0.1.0",
48
+ "@moshaver/cmb-health": "^0.1.0",
49
+ "@moshaver/cmb-identity": "^0.1.0",
50
+ "@moshaver/cmb-infrastructure": "^0.1.0",
51
+ "@moshaver/cmb-kernel": "^0.1.0",
52
+ "@moshaver/cmb-notifications": "^0.1.0",
53
+ "@moshaver/cmb-persistence": "^0.1.0",
54
+ "@moshaver/cmb-realtime": "^0.1.0",
55
+ "@moshaver/cmb-system": "^0.1.0",
56
+ "@moshaver/cmb-tenancy": "^0.1.0"
57
+ }
58
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import type { CmbModuleDescriptor, CmbModuleRegistration, CmbModuleRegistry } from "@moshaver/cmb-kernel";
2
+ import type { CmbHealthService } from "@moshaver/cmb-health";
3
+
4
+ export const STARTER_MODULE: CmbModuleDescriptor;
5
+ export const builtInModules: Readonly<Record<string, CmbModuleDescriptor>>;
6
+
7
+ export type CmbStarterConfig = Readonly<{
8
+ serviceName?: string;
9
+ modules?: readonly (keyof typeof builtInModules)[];
10
+ registrations?: readonly CmbModuleDescriptor[] | readonly CmbModuleRegistration[];
11
+ }>;
12
+
13
+ export function normalizeConfig(input?: CmbStarterConfig): Readonly<{
14
+ serviceName: string;
15
+ modules: readonly string[];
16
+ registrations: readonly (CmbModuleDescriptor | CmbModuleRegistration)[];
17
+ }>;
18
+
19
+ export function createCmbRuntime(config?: CmbStarterConfig): Readonly<{
20
+ config: ReturnType<typeof normalizeConfig>;
21
+ registry: CmbModuleRegistry;
22
+ health: CmbHealthService;
23
+ metadata(): readonly CmbModuleDescriptor[];
24
+ ready(): ReturnType<CmbHealthService["ready"]>;
25
+ start(context?: Record<string, unknown>): ReturnType<CmbModuleRegistry["start"]>;
26
+ stop(context?: Record<string, unknown>): ReturnType<CmbModuleRegistry["stop"]>;
27
+ }>;
package/src/index.js ADDED
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+
3
+ const { CmbModuleRegistry, defineModule } = require("@moshaver/cmb-kernel");
4
+ const { HEALTH_MODULE, CmbHealthService } = require("@moshaver/cmb-health");
5
+ const { PERSISTENCE_MODULE } = require("@moshaver/cmb-persistence");
6
+ const { INFRASTRUCTURE_MODULE } = require("@moshaver/cmb-infrastructure");
7
+ const { REALTIME_MODULE } = require("@moshaver/cmb-realtime");
8
+ const { IDENTITY_MODULE } = require("@moshaver/cmb-identity");
9
+ const { TENANCY_MODULE } = require("@moshaver/cmb-tenancy");
10
+ const { SYSTEM_MODULE } = require("@moshaver/cmb-system");
11
+ const { AUTH_MODULE } = require("@moshaver/cmb-auth");
12
+ const { AUTHORIZATION_MODULE } = require("@moshaver/cmb-authorization");
13
+ const { NOTIFICATIONS_MODULE } = require("@moshaver/cmb-notifications");
14
+ const { ACTIVITY_MODULE } = require("@moshaver/cmb-activity");
15
+ const { DATA_TRANSFER_MODULE } = require("@moshaver/cmb-data-transfer");
16
+
17
+ const STARTER_MODULE = defineModule({
18
+ id: "starter",
19
+ version: "0.1.0",
20
+ kind: "platform",
21
+ dependencies: [
22
+ "activity", "auth", "authorization", "data-transfer", "health", "identity",
23
+ "infrastructure", "kernel", "notifications", "persistence", "realtime", "system", "tenancy",
24
+ ],
25
+ provides: ["cmb.runtime"],
26
+ });
27
+
28
+ const builtInModules = Object.freeze({
29
+ health: HEALTH_MODULE,
30
+ persistence: PERSISTENCE_MODULE,
31
+ infrastructure: INFRASTRUCTURE_MODULE,
32
+ realtime: REALTIME_MODULE,
33
+ identity: IDENTITY_MODULE,
34
+ tenancy: TENANCY_MODULE,
35
+ system: SYSTEM_MODULE,
36
+ auth: AUTH_MODULE,
37
+ authorization: AUTHORIZATION_MODULE,
38
+ notifications: NOTIFICATIONS_MODULE,
39
+ activity: ACTIVITY_MODULE,
40
+ "data-transfer": DATA_TRANSFER_MODULE,
41
+ });
42
+
43
+ function normalizeConfig(input = {}) {
44
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
45
+ throw new TypeError("CMB configuration must be an object.");
46
+ }
47
+ const serviceName = String(input.serviceName ?? "cmb-service").trim();
48
+ if (!serviceName) throw new TypeError("config.serviceName must not be empty.");
49
+ const registrations = input.registrations ?? [];
50
+ if (!Array.isArray(registrations)) throw new TypeError("config.registrations must be an array.");
51
+ const registeredIds = new Set(registrations.map((entry) => entry?.descriptor?.id ?? entry?.id));
52
+ const modules = input.modules ?? ["health"];
53
+ if (!Array.isArray(modules) || modules.some((id) => typeof id !== "string" || (!builtInModules[id] && !registeredIds.has(id)))) {
54
+ throw new TypeError("config.modules must contain built-in or registered CMB module ids.");
55
+ }
56
+ return Object.freeze({ serviceName, modules: [...new Set(["health", ...modules])], registrations });
57
+ }
58
+
59
+ function createCmbRuntime(config) {
60
+ const normalized = normalizeConfig(config);
61
+ const registrations = [...Object.values(builtInModules), ...normalized.registrations];
62
+ const registry = new CmbModuleRegistry(registrations);
63
+ const descriptors = new Map(
64
+ registrations.map((entry) => {
65
+ const descriptor = entry?.descriptor ?? entry;
66
+ return [descriptor.id, descriptor];
67
+ }),
68
+ );
69
+ const enabled = new Set(["kernel"]);
70
+ const include = (id) => {
71
+ if (enabled.has(id)) return;
72
+ const descriptor = descriptors.get(id);
73
+ if (!descriptor) throw new Error(`CMB module ${id} is not registered.`);
74
+ enabled.add(id);
75
+ for (const dependency of descriptor.dependencies ?? []) include(dependency);
76
+ };
77
+ for (const id of normalized.modules) include(id);
78
+ const enabledModules = [...enabled];
79
+ const health = new CmbHealthService({
80
+ serviceName: normalized.serviceName,
81
+ probes: [{ name: "modules", check: () => registry.resolve(enabledModules) }],
82
+ });
83
+ return Object.freeze({
84
+ config: normalized,
85
+ registry,
86
+ health,
87
+ metadata: () => registry.metadata(enabledModules),
88
+ ready: () => health.ready(),
89
+ start: async (context = {}) => registry.start({ ...context, health }, enabledModules),
90
+ stop: async (context = {}) => registry.stop({ ...context, health }),
91
+ });
92
+ }
93
+
94
+ module.exports = { STARTER_MODULE, builtInModules, normalizeConfig, createCmbRuntime };