@omen.foundation/node-microservice-runtime 0.1.122 → 0.1.123
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/AGENTS.md +56 -0
- package/CLAUDE.md +11 -0
- package/README.md +174 -0
- package/ai/RUNTIME_FOR_AI.md +145 -0
- package/ai/beamable-node-microservice.mdc +27 -0
- package/ai/cursor-rule-snippet.md +8 -0
- package/beam.env.example +24 -0
- package/dist/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +66 -1
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/package.json +7 -2
package/AGENTS.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Agent instructions: @omen.foundation/node-microservice-runtime
|
|
2
|
+
|
|
3
|
+
Use this file when implementing or refactoring a **Beamable Node microservice** that depends on `@omen.foundation/node-microservice-runtime`. Prefer facts below over guesses; when unsure, read the installed package source under `dist/` or this repo’s `Microservice/src/`.
|
|
4
|
+
|
|
5
|
+
## Hard rules
|
|
6
|
+
|
|
7
|
+
1. **Single `@Microservice`** — Exactly one class per process with `@Microservice('Name')`. Service name must match `package.json` → `beamable.beamoId`.
|
|
8
|
+
2. **`reflect-metadata` first** — `import 'reflect-metadata'` before any file that uses decorators on classes/methods.
|
|
9
|
+
3. **Import order** — Import `@StorageObject` classes **before** services that use storage so registration runs.
|
|
10
|
+
4. **Do not block publish/validate** — When OpenAPI generation or `beamo-node` loads the app without running the network stack, `BEAMABLE_SKIP_RUNTIME=true` is set; `runMicroservice()` becomes a no-op. Do not remove this guard or start long-lived work at module top level without checking that variable.
|
|
11
|
+
5. **Required env for live runtime** — `CID`, `PID`, `HOST` are mandatory for `loadEnvironmentConfig()`. Missing values throw at startup.
|
|
12
|
+
6. **`beam.env` semantics** — Loaded from `cwd` or `/beam/service/`. Injected keys **do not override** existing `process.env` entries.
|
|
13
|
+
7. **No fake APIs** — Only use exports from the package’s public `dist/index` surface (`Microservice`, `Callable`, `ClientCallable`, `ServerCallable`, `AdminCallable`, `ConfigureServices`, `InitializeServices`, `runMicroservice`, `loadEnvironmentConfig`, `StorageObject`, federation types, DI tokens, etc.). Do not invent Beamable HTTP paths or env vars; verify in code or Beamable docs.
|
|
14
|
+
|
|
15
|
+
## Callable access model
|
|
16
|
+
|
|
17
|
+
- **`@ClientCallable`** — Authenticated player/client flows (`userId` > 0 expected).
|
|
18
|
+
- **`@ServerCallable`** — Server/trusted routes; still use scopes appropriate to your game.
|
|
19
|
+
- **`@AdminCallable`** — Admin scope defaults.
|
|
20
|
+
- **`@Callable`** — Configure `access`, `route`, `requiredScopes`, `requireAuth` explicitly when you need fine control.
|
|
21
|
+
|
|
22
|
+
Always use **`RequestContext`** as the first parameter pattern consistent with existing handlers in the project.
|
|
23
|
+
|
|
24
|
+
## Dependency injection
|
|
25
|
+
|
|
26
|
+
- Register dependencies in a **`@ConfigureServices` static** method on the microservice class: `builder.addSingletonClass`, `builder.addSingleton`, lifetimes as provided by `DependencyBuilder`.
|
|
27
|
+
- Resolve in handlers via **`ctx.provider.resolve(MyService)`** (or inject via factories registered on the builder).
|
|
28
|
+
- If `tsx` or build pipeline strips `emitDecoratorMetadata`, prefer **factory registration** that manually resolves dependencies (see Example microservice pattern).
|
|
29
|
+
|
|
30
|
+
## Storage (MongoDB)
|
|
31
|
+
|
|
32
|
+
- Decorate with **`@StorageObject('StorageName')`**.
|
|
33
|
+
- Provide **`STORAGE_CONNSTR_<StorageName>`** when you need a direct connection string (name normalization matches runtime — use the same spelling as in code).
|
|
34
|
+
- **`MONGODB_MAX_POOL_SIZE`** optional; clamped by runtime.
|
|
35
|
+
|
|
36
|
+
## Health and hosting
|
|
37
|
+
|
|
38
|
+
- Default **health HTTP port `6565`** when `HEALTH_PORT` is unset or invalid in container contexts.
|
|
39
|
+
- Production Docker should use **`WORKDIR /beam/service`** and place **`beam.env`** there (or supply equivalent env via the platform).
|
|
40
|
+
|
|
41
|
+
## Logging / collector
|
|
42
|
+
|
|
43
|
+
- Runtime starts OpenTelemetry collector setup in the background; pre-baking collector binaries in the image under **`/opt/beam/collectors/`** avoids cold-start delay. See **`ai/RUNTIME_FOR_AI.md`** for Dockerfile snippets.
|
|
44
|
+
|
|
45
|
+
## CLI
|
|
46
|
+
|
|
47
|
+
- **`beamo-node validate`** / **`beamo-node publish`** — use project `.env` or `--env-file` so `CID`/`PID`/`HOST`/tokens match the target realm.
|
|
48
|
+
- Binary name: **`beamo-node`** (`package.json` `bin`).
|
|
49
|
+
|
|
50
|
+
## TypeScript config
|
|
51
|
+
|
|
52
|
+
- Enable **`experimentalDecorators`** and **`emitDecoratorMetadata`** unless the project standardizes on explicit factory-based DI only.
|
|
53
|
+
|
|
54
|
+
## Longer reference
|
|
55
|
+
|
|
56
|
+
See **`ai/RUNTIME_FOR_AI.md`** in this package for Dockerfile examples, `beam.env` priority, Beamable Config keys, and troubleshooting.
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# AI agents (Claude, Codex, Cursor, etc.)
|
|
2
|
+
|
|
3
|
+
Authoritative usage rules for **`@omen.foundation/node-microservice-runtime`** ship in this package:
|
|
4
|
+
|
|
5
|
+
1. **`AGENTS.md`** — concise rules (env, decorators, DI, Docker, publish).
|
|
6
|
+
2. **`ai/RUNTIME_FOR_AI.md`** — full reference (startup order, env tables, Dockerfile fragment, troubleshooting).
|
|
7
|
+
3. **`ai/cursor-rule-snippet.md`** — optional text to paste into Cursor `.cursor/rules`.
|
|
8
|
+
|
|
9
|
+
Human-oriented overview: **`README.md`**.
|
|
10
|
+
|
|
11
|
+
After `npm install`, these files are under `node_modules/@omen.foundation/node-microservice-runtime/`.
|
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# @omen.foundation/node-microservice-runtime
|
|
2
|
+
|
|
3
|
+
TypeScript/Node.js runtime for **Beamable** microservices: WebSocket gateway integration, dependency injection, OpenAPI generation, MongoDB storage helpers, optional federation, logging (OpenTelemetry / collector), and a **`beamo-node`** CLI for validate/publish workflows.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- **Node.js** `>= 22.14.0` (see `engines` in `package.json`).
|
|
8
|
+
- **ESM** projects: `"type": "module"` in your service `package.json`.
|
|
9
|
+
- **`reflect-metadata`** imported once before any decorated classes load (required for decorators / DI).
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @omen.foundation/node-microservice-runtime reflect-metadata
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The package ships:
|
|
18
|
+
|
|
19
|
+
- **Library** — decorators, `runMicroservice()`, DI tokens, storage/federation helpers.
|
|
20
|
+
- **CLI** — `beamo-node` (login, scaffold, validate, publish, …).
|
|
21
|
+
|
|
22
|
+
## Minimal service shape
|
|
23
|
+
|
|
24
|
+
1. **`package.json`** — declare the Beamable service id (must match `@Microservice` name):
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"name": "my-game-service",
|
|
29
|
+
"type": "module",
|
|
30
|
+
"main": "dist/main.js",
|
|
31
|
+
"scripts": {
|
|
32
|
+
"dev": "tsx --env-file .env src/main.ts",
|
|
33
|
+
"build": "tsc -p tsconfig.json",
|
|
34
|
+
"validate": "npx beamo-node validate --env-file .env",
|
|
35
|
+
"publish": "npx beamo-node publish --env-file .env"
|
|
36
|
+
},
|
|
37
|
+
"beamable": {
|
|
38
|
+
"beamoId": "MyGameService",
|
|
39
|
+
"projectType": "service"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
2. **Entry file** — load metadata, import the class that carries `@Microservice`, then start:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import 'reflect-metadata';
|
|
48
|
+
import './MyGameService.js';
|
|
49
|
+
import { runMicroservice } from '@omen.foundation/node-microservice-runtime';
|
|
50
|
+
|
|
51
|
+
void runMicroservice();
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
3. **Service class** — exactly one class decorated with `@Microservice('Name')` (name must match `beamable.beamoId`).
|
|
55
|
+
|
|
56
|
+
## Decorators and HTTP access
|
|
57
|
+
|
|
58
|
+
| Decorator | Typical use |
|
|
59
|
+
|-----------|-------------|
|
|
60
|
+
| `@Microservice('ServiceName')` | Registers the service (required, one per process). |
|
|
61
|
+
| `@Callable` | General callable; access via `access` option or use a specialized decorator below. |
|
|
62
|
+
| `@ClientCallable` | Game/client calls; expects authenticated user. |
|
|
63
|
+
| `@ServerCallable` | Trusted server-to-server style routes. |
|
|
64
|
+
| `@AdminCallable` | Admin-scoped routes. |
|
|
65
|
+
| `@ConfigureServices` | Static method receiving `DependencyBuilder` — register singletons, factories. |
|
|
66
|
+
| `@InitializeServices` | Static method receiving scope — run after container is built. |
|
|
67
|
+
| `@SwaggerCategory` / `@SwaggerTags` | OpenAPI grouping. |
|
|
68
|
+
| `@StorageObject('StorageName')` | Registers a named Beamable storage binding (MongoDB). |
|
|
69
|
+
| `@FederatedInventory` | Optional federation hook for inventory-style flows. |
|
|
70
|
+
|
|
71
|
+
Handlers receive **`RequestContext`** (`userId`, `cid`, `pid`, logger, `provider` for DI resolution, etc.).
|
|
72
|
+
|
|
73
|
+
## Environment: Beamable vs `beam.env`
|
|
74
|
+
|
|
75
|
+
### Required for a running service
|
|
76
|
+
|
|
77
|
+
The runtime calls `loadEnvironmentConfig()`, which **requires**:
|
|
78
|
+
|
|
79
|
+
- `CID` — customer id
|
|
80
|
+
- `PID` — project / realm id
|
|
81
|
+
- `HOST` — WebSocket host (e.g. `wss://api.beamable.com/socket`)
|
|
82
|
+
- `SECRET` — signing secret (when used by your deployment; local CLI may use tokens instead)
|
|
83
|
+
|
|
84
|
+
Optional common variables include `REFRESH_TOKEN`, `NAME_PREFIX` / `ROUTING_KEY`, `LOG_LEVEL`, `HEALTH_PORT` (defaults to **6565** when not set or invalid).
|
|
85
|
+
|
|
86
|
+
### Developer file: `beam.env`
|
|
87
|
+
|
|
88
|
+
The runtime loads **`beam.env`** (or **`.beam.env`**) from, in order:
|
|
89
|
+
|
|
90
|
+
1. `process.cwd()/beam.env` or `.beam.env`
|
|
91
|
+
2. `/beam/service/beam.env` or `.beam.env` (typical container layout)
|
|
92
|
+
|
|
93
|
+
Rules:
|
|
94
|
+
|
|
95
|
+
- Format: `KEY=value`, `#` comments, optional quotes for values.
|
|
96
|
+
- **Does not override** variables already in `process.env`.
|
|
97
|
+
|
|
98
|
+
See the published **`beam.env.example`** in this package for a starting template.
|
|
99
|
+
|
|
100
|
+
### Beamable Config API
|
|
101
|
+
|
|
102
|
+
Config from the portal can be merged in asynchronously (with a short timeout). Keys are exposed as `BEAM_CONFIG_*`. Details are summarized in **`AGENTS.md`** and **`ai/RUNTIME_FOR_AI.md`**.
|
|
103
|
+
|
|
104
|
+
### OpenAPI / validate / publish without starting the server
|
|
105
|
+
|
|
106
|
+
Tools set:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
BEAMABLE_SKIP_RUNTIME=true
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
so `runMicroservice()` returns immediately while your module graph still loads for schema generation.
|
|
113
|
+
|
|
114
|
+
## Docker (production-oriented)
|
|
115
|
+
|
|
116
|
+
Recommended patterns used in production games:
|
|
117
|
+
|
|
118
|
+
1. **Working directory** — use **`/beam/service`** so the default `beam.env` search path matches the runtime.
|
|
119
|
+
2. **Copy artifacts** — `dist/`, `package.json`, lockfile, `beam_openApi.json` (if generated), and **`beam.env`** (or inject secrets via orchestrator and skip copying secrets into images where policy forbids it).
|
|
120
|
+
3. **Health checks** — expose the HTTP health port (default **6565**, overridable with `HEALTH_PORT`).
|
|
121
|
+
4. **Collector startup** — pre-installing the Beamable OpenTelemetry collector under **`/opt/beam/collectors/...`** avoids a multi-second download on cold start. See **`ai/RUNTIME_FOR_AI.md`** for an example multi-stage `Dockerfile` fragment.
|
|
122
|
+
|
|
123
|
+
Your game may use Node 20 images today; the **runtime’s declared engine is Node 22+** — align image version with `engines` before upgrading the dependency.
|
|
124
|
+
|
|
125
|
+
## CLI: `beamo-node`
|
|
126
|
+
|
|
127
|
+
Installed as a binary with the package:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npx beamo-node --help
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Typical project scripts:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npx beamo-node validate --env-file .env
|
|
137
|
+
npx beamo-node publish --env-file .env
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Login and scaffolding commands create a local profile under `~/.beamo-node/`.
|
|
141
|
+
|
|
142
|
+
**`beamo-node scaffold <name>`** creates a new project that includes **`AGENTS.md`**, **`CLAUDE.md`**, **`ai/`** (reference docs), **`.cursor/rules/beamable-node-microservice.mdc`**, and a short **`README.md`** pointing at those files.
|
|
143
|
+
|
|
144
|
+
## TypeScript
|
|
145
|
+
|
|
146
|
+
Enable decorator metadata in `tsconfig.json`:
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"compilerOptions": {
|
|
151
|
+
"experimentalDecorators": true,
|
|
152
|
+
"emitDecoratorMetadata": true,
|
|
153
|
+
"module": "NodeNext",
|
|
154
|
+
"moduleResolution": "NodeNext",
|
|
155
|
+
"target": "ES2022"
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## MongoDB / `@StorageObject`
|
|
161
|
+
|
|
162
|
+
- Decorate a class with `@StorageObject('MyStorage')`.
|
|
163
|
+
- Connection string env var: **`STORAGE_CONNSTR_<MyStorage>`** (see runtime `StorageService` — name is normalized).
|
|
164
|
+
- Optional pool sizing: **`MONGODB_MAX_POOL_SIZE`** (clamped).
|
|
165
|
+
|
|
166
|
+
Import storage classes **before** services that depend on them so decorators register.
|
|
167
|
+
|
|
168
|
+
## AI assistants / agents
|
|
169
|
+
|
|
170
|
+
This package includes **`AGENTS.md`** (short rules), **`CLAUDE.md`** (index for AI tools), and **`ai/RUNTIME_FOR_AI.md`** (deep reference: Dockerfile, env, pitfalls). Point Cursor, Claude Code, Codex, or other tools at those files when generating or refactoring Beamable Node microservices. Optional Cursor rule text lives in **`ai/cursor-rule-snippet.md`**.
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Node Microservice Runtime — reference for AI tools
|
|
2
|
+
|
|
3
|
+
Companion to **`AGENTS.md`** (rules) and **`README.md`** (human overview). This document is optimized for accuracy and searchability by coding agents.
|
|
4
|
+
|
|
5
|
+
## Package identity
|
|
6
|
+
|
|
7
|
+
- **npm**: `@omen.foundation/node-microservice-runtime`
|
|
8
|
+
- **CLI binary**: `beamo-node`
|
|
9
|
+
- **Main export**: ESM `dist/index.js`, CJS `dist/index.cjs` (dual package)
|
|
10
|
+
- **Node**: `engines.node` is `>= 22.14.0`
|
|
11
|
+
|
|
12
|
+
## Startup sequence (conceptual)
|
|
13
|
+
|
|
14
|
+
1. `loadDeveloperEnvVarsSync()` reads `beam.env` / `.beam.env` from cwd or `/beam/service/` and fills `process.env` only for keys **not** already set.
|
|
15
|
+
2. `MicroserviceRuntime` constructor validates **at least one** `@Microservice` registration.
|
|
16
|
+
3. Beamable Config fetch runs asynchronously (timeout ~2s); failures are non-fatal.
|
|
17
|
+
4. WebSocket connection to `HOST`, gateway requester, auth, DI container build, health server, route dispatch.
|
|
18
|
+
|
|
19
|
+
If **`BEAMABLE_SKIP_RUNTIME=true`**, `runMicroservice()` exits before constructing the runtime — used when generating OpenAPI or running validate-only flows.
|
|
20
|
+
|
|
21
|
+
## Environment variables
|
|
22
|
+
|
|
23
|
+
### Required for `loadEnvironmentConfig()`
|
|
24
|
+
|
|
25
|
+
| Variable | Role |
|
|
26
|
+
|----------|------|
|
|
27
|
+
| `CID` | Customer ID |
|
|
28
|
+
| `PID` | Realm / project ID |
|
|
29
|
+
| `HOST` | WebSocket URL (e.g. `wss://api.beamable.com/socket`) |
|
|
30
|
+
|
|
31
|
+
### Common optional
|
|
32
|
+
|
|
33
|
+
| Variable | Role |
|
|
34
|
+
|----------|------|
|
|
35
|
+
| `SECRET` | Request signing |
|
|
36
|
+
| `REFRESH_TOKEN` | Token refresh path |
|
|
37
|
+
| `NAME_PREFIX` / `ROUTING_KEY` | Local dev routing; cleared in container when appropriate |
|
|
38
|
+
| `LOG_LEVEL` | Pino level |
|
|
39
|
+
| `HEALTH_PORT` | HTTP health server (default **6565** when unset or ≤0 in practice for deployed images) |
|
|
40
|
+
| `USER_ACCOUNT_ID`, `USER_EMAIL` | Dev / tooling context |
|
|
41
|
+
| `BEAM_INSTANCE_COUNT` | Instance hint |
|
|
42
|
+
| `BEAM_CONFIG_API_PATH` | Override Beamable Config endpoint |
|
|
43
|
+
|
|
44
|
+
### Beamable Config → env
|
|
45
|
+
|
|
46
|
+
API values are merged into `process.env` with prefix **`BEAM_CONFIG_`** (details in runtime `env-loader.ts`).
|
|
47
|
+
|
|
48
|
+
### MongoDB storage
|
|
49
|
+
|
|
50
|
+
- **`STORAGE_CONNSTR_<StorageName>`** — direct connection string for that `@StorageObject` name.
|
|
51
|
+
- **`MONGODB_MAX_POOL_SIZE`** — pool size clamped between 1 and 100.
|
|
52
|
+
|
|
53
|
+
## `beam.env` file
|
|
54
|
+
|
|
55
|
+
- Lines: `KEY=value`, `#` comments.
|
|
56
|
+
- Search paths (first match wins): explicit path (API), `./beam.env`, `./.beam.env`, `/beam/service/beam.env`, `/beam/service/.beam.env`.
|
|
57
|
+
- **Never overwrites** existing `process.env`.
|
|
58
|
+
|
|
59
|
+
**Production pattern (Omen Wars backend)**:
|
|
60
|
+
|
|
61
|
+
- Dockerfile **`WORKDIR /beam/service`**
|
|
62
|
+
- **`COPY ... beam.env ./beam.env`**
|
|
63
|
+
- Optionally also load `.env` in dev only via `dotenv` in entry file — keep secrets out of git; use `env.sample` for documentation.
|
|
64
|
+
|
|
65
|
+
## Entrypoint patterns
|
|
66
|
+
|
|
67
|
+
### Minimal (example / small services)
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import 'reflect-metadata';
|
|
71
|
+
import 'dotenv/config';
|
|
72
|
+
import './MyService.js';
|
|
73
|
+
import { runMicroservice } from '@omen.foundation/node-microservice-runtime';
|
|
74
|
+
|
|
75
|
+
void runMicroservice();
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Larger services (Omen Wars style)
|
|
79
|
+
|
|
80
|
+
- Guard heavy startup with `BEAMABLE_SKIP_RUNTIME === 'true'`.
|
|
81
|
+
- Explicitly `dotenv.config` for `beam.env` path relative to `dist/` if you need variables **before** custom loggers run (runtime still loads `beam.env` itself for its own logger path).
|
|
82
|
+
- Import **`@StorageObject`** module before the main `@Microservice` module.
|
|
83
|
+
- Call **`void runMicroservice()`** last.
|
|
84
|
+
|
|
85
|
+
## Docker — recommended production fragment
|
|
86
|
+
|
|
87
|
+
Multi-stage build: install all deps → `npm run build` → slim runtime image with production `npm install` only.
|
|
88
|
+
|
|
89
|
+
```dockerfile
|
|
90
|
+
FROM node:22-alpine AS builder
|
|
91
|
+
WORKDIR /build
|
|
92
|
+
COPY package*.json ./
|
|
93
|
+
RUN npm install
|
|
94
|
+
COPY . .
|
|
95
|
+
RUN npm run build
|
|
96
|
+
|
|
97
|
+
FROM node:22-alpine
|
|
98
|
+
WORKDIR /beam/service
|
|
99
|
+
COPY package*.json ./
|
|
100
|
+
RUN npm install --omit=dev && npm cache clean --force
|
|
101
|
+
|
|
102
|
+
# Optional but recommended: pre-cache OTel collector to avoid runtime download delay
|
|
103
|
+
RUN mkdir -p /opt/beam/collectors/1.0.1 && \
|
|
104
|
+
apk add --no-cache wget gzip && \
|
|
105
|
+
wget https://collectors.beamable.com/version/1.0.1/collector-linux-amd64.gz -O /tmp/collector.gz && \
|
|
106
|
+
gunzip /tmp/collector.gz && \
|
|
107
|
+
mv /tmp/collector /opt/beam/collectors/1.0.1/collector-linux-amd64 && \
|
|
108
|
+
chmod +x /opt/beam/collectors/1.0.1/collector-linux-amd64 && \
|
|
109
|
+
wget https://collectors.beamable.com/version/1.0.1/clickhouse-config.yaml.gz -O /tmp/config.gz && \
|
|
110
|
+
gunzip /tmp/config.gz && \
|
|
111
|
+
mv /tmp/config /opt/beam/collectors/1.0.1/clickhouse-config.yaml && \
|
|
112
|
+
rm -f /tmp/collector.gz /tmp/config.gz && \
|
|
113
|
+
apk del wget gzip
|
|
114
|
+
|
|
115
|
+
COPY --from=builder /build/dist ./dist
|
|
116
|
+
COPY --from=builder /build/beam_openApi.json ./beam_openApi.json
|
|
117
|
+
COPY --from=builder /build/beam.env ./beam.env
|
|
118
|
+
|
|
119
|
+
EXPOSE 6565
|
|
120
|
+
ENV NODE_ENV=production
|
|
121
|
+
CMD ["node", "dist/main.js"]
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Adjust Node major version to match your pinned runtime and `engines`. Older games may still be on Node 20 images — upgrading requires testing.
|
|
125
|
+
|
|
126
|
+
## OpenAPI and publish
|
|
127
|
+
|
|
128
|
+
- `beamo-node validate` / `publish` invoke your build and OpenAPI pipeline; they rely on **`BEAMABLE_SKIP_RUNTIME`** so the process does not bind sockets or connect to Beamable as a full runtime.
|
|
129
|
+
- Ensure **`beam_openApi.json`** output path matches `publish-service.mjs` / CLI expectations for your repo (commonly project root).
|
|
130
|
+
|
|
131
|
+
## Public exports (non-exhaustive)
|
|
132
|
+
|
|
133
|
+
From `src/index.ts`: decorators (`Microservice`, `Callable`, `ClientCallable`, `ServerCallable`, `AdminCallable`, `SwaggerCategory`, `SwaggerTags`, `ConfigureServices`, `InitializeServices`), types (`EnvironmentConfig`, `RequestContext`, `ServiceDefinition`, …), `BeamableServiceManager`, DI tokens (`LOGGER_TOKEN`, `ENVIRONMENT_CONFIG_TOKEN`, `REQUEST_CONTEXT_TOKEN`, `BEAMABLE_SERVICES_TOKEN`), `loadEnvironmentConfig`, `MicroserviceRuntime`, `runMicroservice`, inventory helpers, `StorageService` / `StorageObject`, federation symbols, collector helpers, `VERSION`.
|
|
134
|
+
|
|
135
|
+
## Troubleshooting checklist for agents
|
|
136
|
+
|
|
137
|
+
1. **“No microservices registered”** — Missing `@Microservice` import before `runMicroservice()` or wrong import order.
|
|
138
|
+
2. **Missing CID/PID/HOST** — `.env` not passed to process; Docker missing env; wrong `WORKDIR` so `beam.env` not found **and** no env injected.
|
|
139
|
+
3. **Duplicate route** — Two `@Callable` methods with same `route` string on one service class.
|
|
140
|
+
4. **DI undefined at runtime** — Metadata not emitted; switch to factory `addSingleton` with explicit dependencies.
|
|
141
|
+
5. **Publish hangs** — Side effects at import time (network, Redis, infinite loops). Guard with `BEAMABLE_SKIP_RUNTIME` or move work into `InitializeServices` / `runtime.start` path only.
|
|
142
|
+
|
|
143
|
+
## Cursor rule file
|
|
144
|
+
|
|
145
|
+
Use **`beamable-node-microservice.mdc`** in this folder (or the copy under **`.cursor/rules/`** after **`beamo-node scaffold`**). See **`cursor-rule-snippet.md`** for notes.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Beamable Node microservices using @omen.foundation/node-microservice-runtime
|
|
3
|
+
globs: "**/*.{ts,tsx,mjs,cjs,json}"
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Beamable Node microservice (Omen Foundation runtime)
|
|
8
|
+
|
|
9
|
+
When editing this microservice’s Beamable Node code:
|
|
10
|
+
|
|
11
|
+
1. Use **`@omen.foundation/node-microservice-runtime`** public APIs only; verify exports in `node_modules/@omen.foundation/node-microservice-runtime/dist/index.d.ts` or the package **README.md** / **AGENTS.md** (root of this repo) / **`ai/RUNTIME_FOR_AI.md`**.
|
|
12
|
+
|
|
13
|
+
2. **One** class with **`@Microservice('Name')`**; name matches **`package.json` → `beamable.beamoId`**.
|
|
14
|
+
|
|
15
|
+
3. Start **`main.ts`** with **`import 'reflect-metadata'`**; import **`@StorageObject`** modules before the main service module.
|
|
16
|
+
|
|
17
|
+
4. End with **`void runMicroservice()`** from the runtime. Respect **`BEAMABLE_SKIP_RUNTIME=true`** — no long-lived work at top level.
|
|
18
|
+
|
|
19
|
+
5. **Env**: runtime requires **`CID`**, **`PID`**, **`HOST`**. **`beam.env`** in **`/beam/service/`** or cwd; does not override existing **`process.env`**.
|
|
20
|
+
|
|
21
|
+
6. **Docker**: prefer **`WORKDIR /beam/service`**, copy **`beam.env`**, expose health port (**6565** default).
|
|
22
|
+
|
|
23
|
+
7. **MongoDB**: **`STORAGE_CONNSTR_<StorageName>`** for **`@StorageObject('StorageName')`**.
|
|
24
|
+
|
|
25
|
+
8. Use **`beamo-node validate`** / **`publish`** with **`--env-file`** matching the target realm.
|
|
26
|
+
|
|
27
|
+
For full detail, read **`AGENTS.md`** and **`ai/RUNTIME_FOR_AI.md`** in this project (scaffolded from the runtime package).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Cursor rule for Beamable Node microservices
|
|
2
|
+
|
|
3
|
+
**Canonical file:** `ai/beamable-node-microservice.mdc` in this package (same content).
|
|
4
|
+
|
|
5
|
+
- **`beamo-node scaffold`** copies it to **`.cursor/rules/beamable-node-microservice.mdc`** in the new project.
|
|
6
|
+
- To add the rule manually, copy **`ai/beamable-node-microservice.mdc`** into your repo’s **`.cursor/rules/`**.
|
|
7
|
+
|
|
8
|
+
Adjust `globs` and `alwaysApply` in that file if the microservice lives inside a monorepo.
|
package/beam.env.example
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Beamable Microservice Environment Variables
|
|
2
|
+
#
|
|
3
|
+
# This file defines developer-specific environment variables that will be
|
|
4
|
+
# loaded into the container at runtime.
|
|
5
|
+
#
|
|
6
|
+
# These variables take priority over Beamable Config values but will NOT
|
|
7
|
+
# overwrite existing process.env values.
|
|
8
|
+
#
|
|
9
|
+
# Format: KEY=value (one per line)
|
|
10
|
+
# Comments start with #
|
|
11
|
+
# Empty lines are ignored
|
|
12
|
+
|
|
13
|
+
# Example: BetterStack Logging Configuration
|
|
14
|
+
BEAM_BETTERSTACK_ENABLED=true
|
|
15
|
+
BEAM_BETTERSTACK_TOKEN=your-token-here
|
|
16
|
+
|
|
17
|
+
# Example: Custom configuration
|
|
18
|
+
MY_API_KEY=your-api-key-here
|
|
19
|
+
MY_FEATURE_FLAG=true
|
|
20
|
+
|
|
21
|
+
# Example: Service-specific settings
|
|
22
|
+
LOG_LEVEL=debug
|
|
23
|
+
MAX_CONNECTIONS=100
|
|
24
|
+
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/scaffold.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/scaffold.ts"],"names":[],"mappings":"AAAA;;GAEG;AAgBH;;GAEG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmElE"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import fs from 'node:fs/promises';
|
|
5
5
|
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
6
7
|
import { toPascalCase, toKebabCase, validateServiceName } from '../utils/name-utils.js';
|
|
7
8
|
import { fetchLatestRuntimeVersion } from '../utils/version-utils.js';
|
|
8
9
|
import { promptInput } from '../utils/prompt-utils.js';
|
|
@@ -60,6 +61,7 @@ export async function handleScaffold(args) {
|
|
|
60
61
|
console.log(` 3. Copy .env.sample to .env and configure your Beamable credentials`);
|
|
61
62
|
console.log(` 4. (Optional) Copy beam.env.example to beam.env for custom environment variables`);
|
|
62
63
|
console.log(` 5. npm run dev`);
|
|
64
|
+
console.log(`\nAI assistant docs were copied: AGENTS.md, CLAUDE.md, ai/, .cursor/rules/beamable-node-microservice.mdc`);
|
|
63
65
|
}
|
|
64
66
|
/**
|
|
65
67
|
* Generates the complete project structure.
|
|
@@ -70,6 +72,8 @@ async function generateProjectStructure(targetDir, options) {
|
|
|
70
72
|
await fs.mkdir(path.join(targetDir, 'src'), { recursive: true });
|
|
71
73
|
await fs.mkdir(path.join(targetDir, 'src', 'services'), { recursive: true });
|
|
72
74
|
await fs.mkdir(path.join(targetDir, 'dist'), { recursive: true });
|
|
75
|
+
// Copy AI assistant docs and Cursor rule from the installed runtime package
|
|
76
|
+
await copyAiAssistantArtifacts(getRuntimePackageRoot(), targetDir);
|
|
73
77
|
// Generate files
|
|
74
78
|
await fs.writeFile(path.join(targetDir, 'package.json'), generatePackageJson(options));
|
|
75
79
|
await fs.writeFile(path.join(targetDir, 'tsconfig.json'), generateTsConfig());
|
|
@@ -79,6 +83,65 @@ async function generateProjectStructure(targetDir, options) {
|
|
|
79
83
|
await fs.writeFile(path.join(targetDir, 'src', 'main.ts'), generateMainTs(options));
|
|
80
84
|
await fs.writeFile(path.join(targetDir, 'src', `${toPascalCase(options.serviceName)}Service.ts`), generateServiceTs(options));
|
|
81
85
|
await fs.writeFile(path.join(targetDir, 'src', 'services', 'example-domain-service.ts'), generateDomainServiceTs());
|
|
86
|
+
await fs.writeFile(path.join(targetDir, 'README.md'), generateProjectReadme(options));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Directory containing package.json for @omen.foundation/node-microservice-runtime
|
|
90
|
+
* (dist/cli/commands/*.js → ../../../).
|
|
91
|
+
*/
|
|
92
|
+
function getRuntimePackageRoot() {
|
|
93
|
+
return path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Copies AGENTS.md, CLAUDE.md, ai/*.md, and the Cursor rule into the scaffolded project.
|
|
97
|
+
*/
|
|
98
|
+
async function copyAiAssistantArtifacts(runtimeRoot, targetDir) {
|
|
99
|
+
const copies = [
|
|
100
|
+
{ relFrom: 'AGENTS.md', relTo: 'AGENTS.md' },
|
|
101
|
+
{ relFrom: 'CLAUDE.md', relTo: 'CLAUDE.md' },
|
|
102
|
+
{ relFrom: path.join('ai', 'RUNTIME_FOR_AI.md'), relTo: path.join('ai', 'RUNTIME_FOR_AI.md') },
|
|
103
|
+
{ relFrom: path.join('ai', 'cursor-rule-snippet.md'), relTo: path.join('ai', 'cursor-rule-snippet.md') },
|
|
104
|
+
{
|
|
105
|
+
relFrom: path.join('ai', 'beamable-node-microservice.mdc'),
|
|
106
|
+
relTo: path.join('.cursor', 'rules', 'beamable-node-microservice.mdc'),
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
for (const { relFrom, relTo } of copies) {
|
|
110
|
+
const src = path.join(runtimeRoot, relFrom);
|
|
111
|
+
const dest = path.join(targetDir, relTo);
|
|
112
|
+
await fs.mkdir(path.dirname(dest), { recursive: true });
|
|
113
|
+
const content = await fs.readFile(src, 'utf-8');
|
|
114
|
+
await fs.writeFile(dest, content, 'utf-8');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Short project README; AI docs are copied alongside from the runtime package.
|
|
119
|
+
*/
|
|
120
|
+
function generateProjectReadme(options) {
|
|
121
|
+
const title = options.displayName ?? options.serviceName;
|
|
122
|
+
return `# ${title}
|
|
123
|
+
|
|
124
|
+
Beamable Node microservice scaffolded with **\`beamo-node scaffold\`**.
|
|
125
|
+
|
|
126
|
+
## Documentation in this project
|
|
127
|
+
|
|
128
|
+
| Path | Purpose |
|
|
129
|
+
|------|---------|
|
|
130
|
+
| **AGENTS.md** | Rules for AI coding agents (Cursor, Claude, Codex, …) |
|
|
131
|
+
| **CLAUDE.md** | Index pointing at the AI docs below |
|
|
132
|
+
| **ai/RUNTIME_FOR_AI.md** | Full runtime reference (env, Docker, troubleshooting) |
|
|
133
|
+
| **ai/cursor-rule-snippet.md** | Notes on the Cursor rule file |
|
|
134
|
+
| **.cursor/rules/beamable-node-microservice.mdc** | Cursor rule (tune \`globs\` if this service lives in a monorepo) |
|
|
135
|
+
|
|
136
|
+
After **\`npm install\`**, the same topics are also under **\`node_modules/@omen.foundation/node-microservice-runtime/\`**.
|
|
137
|
+
|
|
138
|
+
## Scripts
|
|
139
|
+
|
|
140
|
+
- **\`npm run dev\`** — local development
|
|
141
|
+
- **\`npm run validate\`** / **\`npm run publish\`** — Beamable CLI (\`beamo-node\`)
|
|
142
|
+
|
|
143
|
+
Configure **\`.env\`** from **\`.env.sample\`** and optionally **\`beam.env\`** from **\`beam.env.example\`**.
|
|
144
|
+
`;
|
|
82
145
|
}
|
|
83
146
|
/**
|
|
84
147
|
* Generates package.json content.
|
|
@@ -103,6 +166,7 @@ function generatePackageJson(options) {
|
|
|
103
166
|
'@omen.foundation/node-microservice-runtime': `^${options.runtimeVersion}`,
|
|
104
167
|
dotenv: '^16.4.7',
|
|
105
168
|
mongodb: '^6.10.0',
|
|
169
|
+
'reflect-metadata': '^0.2.2',
|
|
106
170
|
},
|
|
107
171
|
devDependencies: {
|
|
108
172
|
'@types/node': '^20.11.30',
|
|
@@ -215,7 +279,8 @@ beam.env
|
|
|
215
279
|
*/
|
|
216
280
|
function generateMainTs(options) {
|
|
217
281
|
const serviceNamePascal = toPascalCase(options.serviceName);
|
|
218
|
-
return `import '
|
|
282
|
+
return `import 'reflect-metadata';
|
|
283
|
+
import 'dotenv/config';
|
|
219
284
|
import './${serviceNamePascal}Service.js';
|
|
220
285
|
import { runMicroservice } from '@omen.foundation/node-microservice-runtime';
|
|
221
286
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../../src/cli/commands/scaffold.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Command handler for scaffolding new microservice projects.\r\n */\r\n\r\nimport fs from 'node:fs/promises';\r\nimport path from 'node:path';\r\nimport { toPascalCase, toKebabCase, validateServiceName } from '../utils/name-utils.js';\r\nimport { fetchLatestRuntimeVersion } from '../utils/version-utils.js';\r\nimport { promptInput } from '../utils/prompt-utils.js';\r\n\r\ninterface ScaffoldOptions {\r\n serviceName: string;\r\n displayName?: string;\r\n beamoId?: string;\r\n runtimeVersion: string;\r\n}\r\n\r\n/**\r\n * Handles the scaffold command.\r\n */\r\nexport async function handleScaffold(args: string[]): Promise<void> {\r\n let serviceName = args[0];\r\n\r\n // Interactive prompt for service name if not provided\r\n if (!serviceName) {\r\n serviceName = await promptInput('Enter microservice name (alphanumeric and underscores only)');\r\n }\r\n\r\n // Validate service name\r\n if (!serviceName || !validateServiceName(serviceName)) {\r\n throw new Error(\r\n `Invalid microservice name \"${serviceName}\". Only alphanumeric and underscore characters are allowed.`,\r\n );\r\n }\r\n\r\n // Fetch latest runtime version\r\n console.log('Fetching latest runtime version...');\r\n const runtimeVersion = await fetchLatestRuntimeVersion();\r\n console.log(`Using @omen.foundation/node-microservice-runtime version ${runtimeVersion}`);\r\n\r\n // Prompt for optional values\r\n const displayName = await promptInput('Enter display name for the service (optional)', serviceName);\r\n const beamoId = await promptInput('Enter Beamable Beamo ID (optional, defaults to service name)', serviceName);\r\n\r\n // Validate beamoId\r\n if (beamoId && !validateServiceName(beamoId)) {\r\n throw new Error(\r\n `Invalid Beamo ID \"${beamoId}\". Only alphanumeric and underscore characters are allowed.`,\r\n );\r\n }\r\n\r\n const options: ScaffoldOptions = {\r\n serviceName,\r\n displayName: displayName || serviceName,\r\n beamoId: beamoId || serviceName,\r\n runtimeVersion,\r\n };\r\n\r\n // Check if directory already exists\r\n const targetDir = path.resolve(process.cwd(), serviceName);\r\n try {\r\n await fs.access(targetDir);\r\n const overwrite = await promptInput(\r\n `Directory \"${serviceName}\" already exists. Overwrite? (y/n)`,\r\n 'n',\r\n );\r\n if (overwrite.toLowerCase() !== 'y' && overwrite.toLowerCase() !== 'yes') {\r\n console.log('Scaffold cancelled.');\r\n return;\r\n }\r\n // Remove existing directory\r\n await fs.rm(targetDir, { recursive: true, force: true });\r\n } catch {\r\n // Directory doesn't exist, that's fine\r\n }\r\n\r\n // Generate project structure\r\n await generateProjectStructure(targetDir, options);\r\n\r\n console.log(`\\n✅ Successfully scaffolded microservice \"${serviceName}\"!`);\r\n console.log(`\\nNext steps:`);\r\n console.log(` 1. cd ${serviceName}`);\r\n console.log(` 2. npm install`);\r\n console.log(` 3. Copy .env.sample to .env and configure your Beamable credentials`);\r\n console.log(` 4. (Optional) Copy beam.env.example to beam.env for custom environment variables`);\r\n console.log(` 5. npm run dev`);\r\n}\r\n\r\n/**\r\n * Generates the complete project structure.\r\n */\r\nasync function generateProjectStructure(targetDir: string, options: ScaffoldOptions): Promise<void> {\r\n // Create directories\r\n await fs.mkdir(targetDir, { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'src'), { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'src', 'services'), { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'dist'), { recursive: true });\r\n\r\n // Generate files\r\n await fs.writeFile(path.join(targetDir, 'package.json'), generatePackageJson(options));\r\n await fs.writeFile(path.join(targetDir, 'tsconfig.json'), generateTsConfig());\r\n await fs.writeFile(path.join(targetDir, '.env.sample'), generateEnvSample());\r\n await fs.writeFile(path.join(targetDir, 'beam.env.example'), generateBeamEnvExample());\r\n await fs.writeFile(path.join(targetDir, '.gitignore'), generateGitIgnore());\r\n await fs.writeFile(path.join(targetDir, 'src', 'main.ts'), generateMainTs(options));\r\n await fs.writeFile(\r\n path.join(targetDir, 'src', `${toPascalCase(options.serviceName)}Service.ts`),\r\n generateServiceTs(options),\r\n );\r\n await fs.writeFile(\r\n path.join(targetDir, 'src', 'services', 'example-domain-service.ts'),\r\n generateDomainServiceTs(),\r\n );\r\n}\r\n\r\n/**\r\n * Generates package.json content.\r\n */\r\nfunction generatePackageJson(options: ScaffoldOptions): string {\r\n const serviceNameKebab = toKebabCase(options.serviceName);\r\n const packageName = `@beamable/${serviceNameKebab}-node-microservice`;\r\n\r\n return JSON.stringify(\r\n {\r\n name: packageName,\r\n version: '0.1.0',\r\n private: true,\r\n type: 'module',\r\n main: 'dist/main.js',\r\n types: 'dist/main.d.ts',\r\n scripts: {\r\n dev: 'tsx --env-file .env src/main.ts',\r\n build: 'tsc -p tsconfig.json',\r\n validate: 'npx beamo-node validate --env-file .env',\r\n publish: 'npx beamo-node publish --env-file .env',\r\n },\r\n dependencies: {\r\n '@omen.foundation/node-microservice-runtime': `^${options.runtimeVersion}`,\r\n dotenv: '^16.4.7',\r\n mongodb: '^6.10.0',\r\n },\r\n devDependencies: {\r\n '@types/node': '^20.11.30',\r\n 'pino-pretty': '^13.0.0',\r\n tsx: '^4.19.2',\r\n typescript: '^5.4.5',\r\n },\r\n beamable: {\r\n beamoId: options.beamoId,\r\n projectType: 'service',\r\n },\r\n },\r\n null,\r\n 2,\r\n );\r\n}\r\n\r\n/**\r\n * Generates tsconfig.json content.\r\n * Includes all necessary compiler options directly to avoid dependency on base config.\r\n */\r\nfunction generateTsConfig(): string {\r\n return JSON.stringify(\r\n {\r\n compilerOptions: {\r\n target: 'ES2022',\r\n module: 'NodeNext',\r\n moduleResolution: 'NodeNext',\r\n esModuleInterop: true,\r\n forceConsistentCasingInFileNames: true,\r\n strict: true,\r\n skipLibCheck: false,\r\n noImplicitOverride: true,\r\n noUnusedLocals: true,\r\n noUnusedParameters: true,\r\n resolveJsonModule: true,\r\n sourceMap: true,\r\n inlineSources: true,\r\n experimentalDecorators: true,\r\n emitDecoratorMetadata: true,\r\n types: ['node'],\r\n outDir: 'dist',\r\n rootDir: 'src',\r\n declaration: true,\r\n declarationMap: true,\r\n },\r\n include: ['src/**/*.ts'],\r\n exclude: ['dist', 'node_modules'],\r\n },\r\n null,\r\n 2,\r\n );\r\n}\r\n\r\n/**\r\n * Generates .env.sample content.\r\n */\r\nfunction generateEnvSample(): string {\r\n return `# Beamable Authentication & Configuration\r\n# This file is for Beamable-specific credentials (CID, PID, SECRET, etc.)\r\n# For custom environment variables, use beam.env instead (see beam.env.example)\r\n\r\nCID=\r\nPID=\r\nHOST=wss://api.beamable.com/socket\r\nSECRET=\r\nNAME_PREFIX=\r\nLOG_LEVEL=info\r\nBEAMABLE_TOKEN=\r\nBEAMABLE_API_HOST=https://api.beamable.com\r\nBEAMABLE_GAME_PID=\r\n`;\r\n}\r\n\r\n/**\r\n * Generates beam.env.example content.\r\n */\r\nfunction generateBeamEnvExample(): string {\r\n return `# Beamable Microservice Environment Variables\r\n# \r\n# This file defines developer-specific environment variables that will be\r\n# loaded into the container at runtime.\r\n#\r\n# These variables take priority over Beamable Config values but will NOT\r\n# overwrite existing process.env values.\r\n#\r\n# Format: KEY=value (one per line)\r\n# Comments start with #\r\n# Empty lines are ignored\r\n\r\n# Example: BetterStack Logging Configuration\r\n# BEAM_BETTERSTACK_ENABLED=true\r\n# BEAM_BETTERSTACK_TOKEN=your-token-here\r\n\r\n# Example: Custom configuration\r\n# MY_API_KEY=your-api-key-here\r\n# MY_FEATURE_FLAG=true\r\n\r\n# Example: Service-specific settings\r\n# LOG_LEVEL=debug\r\n# MAX_CONNECTIONS=100\r\n`;\r\n}\r\n\r\n/**\r\n * Generates .gitignore content.\r\n */\r\nfunction generateGitIgnore(): string {\r\n return `node_modules/\r\ndist/\r\n.env\r\n.env.local\r\nbeam.env\r\n.beam.env\r\n*.log\r\n.DS_Store\r\n`;\r\n}\r\n\r\n/**\r\n * Generates main.ts content.\r\n */\r\nfunction generateMainTs(options: ScaffoldOptions): string {\r\n const serviceNamePascal = toPascalCase(options.serviceName);\r\n return `import 'dotenv/config';\r\nimport './${serviceNamePascal}Service.js';\r\nimport { runMicroservice } from '@omen.foundation/node-microservice-runtime';\r\n\r\nvoid runMicroservice();\r\n`;\r\n}\r\n\r\n/**\r\n * Generates the main service class file.\r\n */\r\nfunction generateServiceTs(options: ScaffoldOptions): string {\r\n const serviceNamePascal = toPascalCase(options.serviceName);\r\n return `import {\r\n Microservice,\r\n Callable,\r\n ClientCallable,\r\n ServerCallable,\r\n SwaggerCategory,\r\n ConfigureServices,\r\n type DependencyBuilder,\r\n type RequestContext,\r\n} from '@omen.foundation/node-microservice-runtime';\r\nimport { ExampleDomainService } from './services/example-domain-service.js';\r\n\r\n@Microservice('${options.serviceName}')\r\nexport class ${serviceNamePascal}Service {\r\n @ConfigureServices\r\n static register(builder: DependencyBuilder): void {\r\n builder.addSingletonClass(ExampleDomainService);\r\n }\r\n\r\n /**\r\n * Example of a public Callable endpoint.\r\n * No authentication required.\r\n */\r\n @Callable({ route: 'isTwo' })\r\n @SwaggerCategory('Examples')\r\n async isTwo(_ctx: RequestContext): Promise<boolean> {\r\n return 1 + 1 === 2;\r\n }\r\n\r\n /**\r\n * Example of a ClientCallable endpoint.\r\n * Requires user authentication (client scope).\r\n */\r\n @ClientCallable({ route: 'isThree' })\r\n @SwaggerCategory('Examples')\r\n async isThree(_ctx: RequestContext): Promise<boolean> {\r\n return 1 + 2 === 3;\r\n }\r\n\r\n /**\r\n * Example of a ServerCallable endpoint.\r\n * Requires server authentication (server scope).\r\n */\r\n @ServerCallable({ route: 'isFour' })\r\n @SwaggerCategory('Examples')\r\n async isFour(_ctx: RequestContext): Promise<boolean> {\r\n return 2 + 2 === 4;\r\n }\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * Generates example domain service content.\r\n */\r\nfunction generateDomainServiceTs(): string {\r\n return `import type { RequestContext } from '@omen.foundation/node-microservice-runtime';\r\n\r\nexport class ExampleDomainService {\r\n greet(userId: number): string {\r\n return \\`Hello from Node microservices, user \\${userId}!\\`;\r\n }\r\n\r\n async getServiceInfo(_ctx: RequestContext): Promise<{ service: string; version: string }> {\r\n return {\r\n service: 'ExampleDomainService',\r\n version: '1.0.0',\r\n };\r\n }\r\n}\r\n`;\r\n}\r\n\r\n"]}
|
|
1
|
+
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../../src/cli/commands/scaffold.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Command handler for scaffolding new microservice projects.\r\n */\r\n\r\nimport fs from 'node:fs/promises';\r\nimport path from 'node:path';\r\nimport { fileURLToPath } from 'node:url';\r\nimport { toPascalCase, toKebabCase, validateServiceName } from '../utils/name-utils.js';\r\nimport { fetchLatestRuntimeVersion } from '../utils/version-utils.js';\r\nimport { promptInput } from '../utils/prompt-utils.js';\r\n\r\ninterface ScaffoldOptions {\r\n serviceName: string;\r\n displayName?: string;\r\n beamoId?: string;\r\n runtimeVersion: string;\r\n}\r\n\r\n/**\r\n * Handles the scaffold command.\r\n */\r\nexport async function handleScaffold(args: string[]): Promise<void> {\r\n let serviceName = args[0];\r\n\r\n // Interactive prompt for service name if not provided\r\n if (!serviceName) {\r\n serviceName = await promptInput('Enter microservice name (alphanumeric and underscores only)');\r\n }\r\n\r\n // Validate service name\r\n if (!serviceName || !validateServiceName(serviceName)) {\r\n throw new Error(\r\n `Invalid microservice name \"${serviceName}\". Only alphanumeric and underscore characters are allowed.`,\r\n );\r\n }\r\n\r\n // Fetch latest runtime version\r\n console.log('Fetching latest runtime version...');\r\n const runtimeVersion = await fetchLatestRuntimeVersion();\r\n console.log(`Using @omen.foundation/node-microservice-runtime version ${runtimeVersion}`);\r\n\r\n // Prompt for optional values\r\n const displayName = await promptInput('Enter display name for the service (optional)', serviceName);\r\n const beamoId = await promptInput('Enter Beamable Beamo ID (optional, defaults to service name)', serviceName);\r\n\r\n // Validate beamoId\r\n if (beamoId && !validateServiceName(beamoId)) {\r\n throw new Error(\r\n `Invalid Beamo ID \"${beamoId}\". Only alphanumeric and underscore characters are allowed.`,\r\n );\r\n }\r\n\r\n const options: ScaffoldOptions = {\r\n serviceName,\r\n displayName: displayName || serviceName,\r\n beamoId: beamoId || serviceName,\r\n runtimeVersion,\r\n };\r\n\r\n // Check if directory already exists\r\n const targetDir = path.resolve(process.cwd(), serviceName);\r\n try {\r\n await fs.access(targetDir);\r\n const overwrite = await promptInput(\r\n `Directory \"${serviceName}\" already exists. Overwrite? (y/n)`,\r\n 'n',\r\n );\r\n if (overwrite.toLowerCase() !== 'y' && overwrite.toLowerCase() !== 'yes') {\r\n console.log('Scaffold cancelled.');\r\n return;\r\n }\r\n // Remove existing directory\r\n await fs.rm(targetDir, { recursive: true, force: true });\r\n } catch {\r\n // Directory doesn't exist, that's fine\r\n }\r\n\r\n // Generate project structure\r\n await generateProjectStructure(targetDir, options);\r\n\r\n console.log(`\\n✅ Successfully scaffolded microservice \"${serviceName}\"!`);\r\n console.log(`\\nNext steps:`);\r\n console.log(` 1. cd ${serviceName}`);\r\n console.log(` 2. npm install`);\r\n console.log(` 3. Copy .env.sample to .env and configure your Beamable credentials`);\r\n console.log(` 4. (Optional) Copy beam.env.example to beam.env for custom environment variables`);\r\n console.log(` 5. npm run dev`);\r\n console.log(`\\nAI assistant docs were copied: AGENTS.md, CLAUDE.md, ai/, .cursor/rules/beamable-node-microservice.mdc`);\r\n}\r\n\r\n/**\r\n * Generates the complete project structure.\r\n */\r\nasync function generateProjectStructure(targetDir: string, options: ScaffoldOptions): Promise<void> {\r\n // Create directories\r\n await fs.mkdir(targetDir, { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'src'), { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'src', 'services'), { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'dist'), { recursive: true });\r\n\r\n // Copy AI assistant docs and Cursor rule from the installed runtime package\r\n await copyAiAssistantArtifacts(getRuntimePackageRoot(), targetDir);\r\n\r\n // Generate files\r\n await fs.writeFile(path.join(targetDir, 'package.json'), generatePackageJson(options));\r\n await fs.writeFile(path.join(targetDir, 'tsconfig.json'), generateTsConfig());\r\n await fs.writeFile(path.join(targetDir, '.env.sample'), generateEnvSample());\r\n await fs.writeFile(path.join(targetDir, 'beam.env.example'), generateBeamEnvExample());\r\n await fs.writeFile(path.join(targetDir, '.gitignore'), generateGitIgnore());\r\n await fs.writeFile(path.join(targetDir, 'src', 'main.ts'), generateMainTs(options));\r\n await fs.writeFile(\r\n path.join(targetDir, 'src', `${toPascalCase(options.serviceName)}Service.ts`),\r\n generateServiceTs(options),\r\n );\r\n await fs.writeFile(\r\n path.join(targetDir, 'src', 'services', 'example-domain-service.ts'),\r\n generateDomainServiceTs(),\r\n );\r\n await fs.writeFile(path.join(targetDir, 'README.md'), generateProjectReadme(options));\r\n}\r\n\r\n/**\r\n * Directory containing package.json for @omen.foundation/node-microservice-runtime\r\n * (dist/cli/commands/*.js → ../../../).\r\n */\r\nfunction getRuntimePackageRoot(): string {\r\n return path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');\r\n}\r\n\r\n/**\r\n * Copies AGENTS.md, CLAUDE.md, ai/*.md, and the Cursor rule into the scaffolded project.\r\n */\r\nasync function copyAiAssistantArtifacts(runtimeRoot: string, targetDir: string): Promise<void> {\r\n const copies: Array<{ relFrom: string; relTo: string }> = [\r\n { relFrom: 'AGENTS.md', relTo: 'AGENTS.md' },\r\n { relFrom: 'CLAUDE.md', relTo: 'CLAUDE.md' },\r\n { relFrom: path.join('ai', 'RUNTIME_FOR_AI.md'), relTo: path.join('ai', 'RUNTIME_FOR_AI.md') },\r\n { relFrom: path.join('ai', 'cursor-rule-snippet.md'), relTo: path.join('ai', 'cursor-rule-snippet.md') },\r\n {\r\n relFrom: path.join('ai', 'beamable-node-microservice.mdc'),\r\n relTo: path.join('.cursor', 'rules', 'beamable-node-microservice.mdc'),\r\n },\r\n ];\r\n\r\n for (const { relFrom, relTo } of copies) {\r\n const src = path.join(runtimeRoot, relFrom);\r\n const dest = path.join(targetDir, relTo);\r\n await fs.mkdir(path.dirname(dest), { recursive: true });\r\n const content = await fs.readFile(src, 'utf-8');\r\n await fs.writeFile(dest, content, 'utf-8');\r\n }\r\n}\r\n\r\n/**\r\n * Short project README; AI docs are copied alongside from the runtime package.\r\n */\r\nfunction generateProjectReadme(options: ScaffoldOptions): string {\r\n const title = options.displayName ?? options.serviceName;\r\n return `# ${title}\r\n\r\nBeamable Node microservice scaffolded with **\\`beamo-node scaffold\\`**.\r\n\r\n## Documentation in this project\r\n\r\n| Path | Purpose |\r\n|------|---------|\r\n| **AGENTS.md** | Rules for AI coding agents (Cursor, Claude, Codex, …) |\r\n| **CLAUDE.md** | Index pointing at the AI docs below |\r\n| **ai/RUNTIME_FOR_AI.md** | Full runtime reference (env, Docker, troubleshooting) |\r\n| **ai/cursor-rule-snippet.md** | Notes on the Cursor rule file |\r\n| **.cursor/rules/beamable-node-microservice.mdc** | Cursor rule (tune \\`globs\\` if this service lives in a monorepo) |\r\n\r\nAfter **\\`npm install\\`**, the same topics are also under **\\`node_modules/@omen.foundation/node-microservice-runtime/\\`**.\r\n\r\n## Scripts\r\n\r\n- **\\`npm run dev\\`** — local development\r\n- **\\`npm run validate\\`** / **\\`npm run publish\\`** — Beamable CLI (\\`beamo-node\\`)\r\n\r\nConfigure **\\`.env\\`** from **\\`.env.sample\\`** and optionally **\\`beam.env\\`** from **\\`beam.env.example\\`**.\r\n`;\r\n}\r\n\r\n/**\r\n * Generates package.json content.\r\n */\r\nfunction generatePackageJson(options: ScaffoldOptions): string {\r\n const serviceNameKebab = toKebabCase(options.serviceName);\r\n const packageName = `@beamable/${serviceNameKebab}-node-microservice`;\r\n\r\n return JSON.stringify(\r\n {\r\n name: packageName,\r\n version: '0.1.0',\r\n private: true,\r\n type: 'module',\r\n main: 'dist/main.js',\r\n types: 'dist/main.d.ts',\r\n scripts: {\r\n dev: 'tsx --env-file .env src/main.ts',\r\n build: 'tsc -p tsconfig.json',\r\n validate: 'npx beamo-node validate --env-file .env',\r\n publish: 'npx beamo-node publish --env-file .env',\r\n },\r\n dependencies: {\r\n '@omen.foundation/node-microservice-runtime': `^${options.runtimeVersion}`,\r\n dotenv: '^16.4.7',\r\n mongodb: '^6.10.0',\r\n 'reflect-metadata': '^0.2.2',\r\n },\r\n devDependencies: {\r\n '@types/node': '^20.11.30',\r\n 'pino-pretty': '^13.0.0',\r\n tsx: '^4.19.2',\r\n typescript: '^5.4.5',\r\n },\r\n beamable: {\r\n beamoId: options.beamoId,\r\n projectType: 'service',\r\n },\r\n },\r\n null,\r\n 2,\r\n );\r\n}\r\n\r\n/**\r\n * Generates tsconfig.json content.\r\n * Includes all necessary compiler options directly to avoid dependency on base config.\r\n */\r\nfunction generateTsConfig(): string {\r\n return JSON.stringify(\r\n {\r\n compilerOptions: {\r\n target: 'ES2022',\r\n module: 'NodeNext',\r\n moduleResolution: 'NodeNext',\r\n esModuleInterop: true,\r\n forceConsistentCasingInFileNames: true,\r\n strict: true,\r\n skipLibCheck: false,\r\n noImplicitOverride: true,\r\n noUnusedLocals: true,\r\n noUnusedParameters: true,\r\n resolveJsonModule: true,\r\n sourceMap: true,\r\n inlineSources: true,\r\n experimentalDecorators: true,\r\n emitDecoratorMetadata: true,\r\n types: ['node'],\r\n outDir: 'dist',\r\n rootDir: 'src',\r\n declaration: true,\r\n declarationMap: true,\r\n },\r\n include: ['src/**/*.ts'],\r\n exclude: ['dist', 'node_modules'],\r\n },\r\n null,\r\n 2,\r\n );\r\n}\r\n\r\n/**\r\n * Generates .env.sample content.\r\n */\r\nfunction generateEnvSample(): string {\r\n return `# Beamable Authentication & Configuration\r\n# This file is for Beamable-specific credentials (CID, PID, SECRET, etc.)\r\n# For custom environment variables, use beam.env instead (see beam.env.example)\r\n\r\nCID=\r\nPID=\r\nHOST=wss://api.beamable.com/socket\r\nSECRET=\r\nNAME_PREFIX=\r\nLOG_LEVEL=info\r\nBEAMABLE_TOKEN=\r\nBEAMABLE_API_HOST=https://api.beamable.com\r\nBEAMABLE_GAME_PID=\r\n`;\r\n}\r\n\r\n/**\r\n * Generates beam.env.example content.\r\n */\r\nfunction generateBeamEnvExample(): string {\r\n return `# Beamable Microservice Environment Variables\r\n# \r\n# This file defines developer-specific environment variables that will be\r\n# loaded into the container at runtime.\r\n#\r\n# These variables take priority over Beamable Config values but will NOT\r\n# overwrite existing process.env values.\r\n#\r\n# Format: KEY=value (one per line)\r\n# Comments start with #\r\n# Empty lines are ignored\r\n\r\n# Example: BetterStack Logging Configuration\r\n# BEAM_BETTERSTACK_ENABLED=true\r\n# BEAM_BETTERSTACK_TOKEN=your-token-here\r\n\r\n# Example: Custom configuration\r\n# MY_API_KEY=your-api-key-here\r\n# MY_FEATURE_FLAG=true\r\n\r\n# Example: Service-specific settings\r\n# LOG_LEVEL=debug\r\n# MAX_CONNECTIONS=100\r\n`;\r\n}\r\n\r\n/**\r\n * Generates .gitignore content.\r\n */\r\nfunction generateGitIgnore(): string {\r\n return `node_modules/\r\ndist/\r\n.env\r\n.env.local\r\nbeam.env\r\n.beam.env\r\n*.log\r\n.DS_Store\r\n`;\r\n}\r\n\r\n/**\r\n * Generates main.ts content.\r\n */\r\nfunction generateMainTs(options: ScaffoldOptions): string {\r\n const serviceNamePascal = toPascalCase(options.serviceName);\r\n return `import 'reflect-metadata';\r\nimport 'dotenv/config';\r\nimport './${serviceNamePascal}Service.js';\r\nimport { runMicroservice } from '@omen.foundation/node-microservice-runtime';\r\n\r\nvoid runMicroservice();\r\n`;\r\n}\r\n\r\n/**\r\n * Generates the main service class file.\r\n */\r\nfunction generateServiceTs(options: ScaffoldOptions): string {\r\n const serviceNamePascal = toPascalCase(options.serviceName);\r\n return `import {\r\n Microservice,\r\n Callable,\r\n ClientCallable,\r\n ServerCallable,\r\n SwaggerCategory,\r\n ConfigureServices,\r\n type DependencyBuilder,\r\n type RequestContext,\r\n} from '@omen.foundation/node-microservice-runtime';\r\nimport { ExampleDomainService } from './services/example-domain-service.js';\r\n\r\n@Microservice('${options.serviceName}')\r\nexport class ${serviceNamePascal}Service {\r\n @ConfigureServices\r\n static register(builder: DependencyBuilder): void {\r\n builder.addSingletonClass(ExampleDomainService);\r\n }\r\n\r\n /**\r\n * Example of a public Callable endpoint.\r\n * No authentication required.\r\n */\r\n @Callable({ route: 'isTwo' })\r\n @SwaggerCategory('Examples')\r\n async isTwo(_ctx: RequestContext): Promise<boolean> {\r\n return 1 + 1 === 2;\r\n }\r\n\r\n /**\r\n * Example of a ClientCallable endpoint.\r\n * Requires user authentication (client scope).\r\n */\r\n @ClientCallable({ route: 'isThree' })\r\n @SwaggerCategory('Examples')\r\n async isThree(_ctx: RequestContext): Promise<boolean> {\r\n return 1 + 2 === 3;\r\n }\r\n\r\n /**\r\n * Example of a ServerCallable endpoint.\r\n * Requires server authentication (server scope).\r\n */\r\n @ServerCallable({ route: 'isFour' })\r\n @SwaggerCategory('Examples')\r\n async isFour(_ctx: RequestContext): Promise<boolean> {\r\n return 2 + 2 === 4;\r\n }\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * Generates example domain service content.\r\n */\r\nfunction generateDomainServiceTs(): string {\r\n return `import type { RequestContext } from '@omen.foundation/node-microservice-runtime';\r\n\r\nexport class ExampleDomainService {\r\n greet(userId: number): string {\r\n return \\`Hello from Node microservices, user \\${userId}!\\`;\r\n }\r\n\r\n async getServiceInfo(_ctx: RequestContext): Promise<{ service: string; version: string }> {\r\n return {\r\n service: 'ExampleDomainService',\r\n version: '1.0.0',\r\n };\r\n }\r\n}\r\n`;\r\n}\r\n\r\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omen.foundation/node-microservice-runtime",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.123",
|
|
4
4
|
"description": "Beamable microservice runtime for Node.js/TypeScript services.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,7 +16,12 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
|
-
"scripts"
|
|
19
|
+
"scripts",
|
|
20
|
+
"README.md",
|
|
21
|
+
"CLAUDE.md",
|
|
22
|
+
"AGENTS.md",
|
|
23
|
+
"beam.env.example",
|
|
24
|
+
"ai"
|
|
20
25
|
],
|
|
21
26
|
"scripts": {
|
|
22
27
|
"clean": "rimraf dist dist-cjs",
|