@memberjunction/server-bootstrap 0.0.1 → 3.0.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/README.md +145 -28
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/package.json +27 -5
package/README.md
CHANGED
|
@@ -1,45 +1,162 @@
|
|
|
1
1
|
# @memberjunction/server-bootstrap
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
MemberJunction 3.0 Server Bootstrap - Encapsulates all server initialization logic into a single, simple function.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
In MemberJunction 3.0, server applications (MJAPI) become **minimal bootstrapping files** (~6 lines of code) that import all functionality from NPM packages. This package provides the `createMJServer()` function that handles all the complex initialization logic.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @memberjunction/server-bootstrap
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Basic Usage (Minimal MJAPI 3.0)
|
|
18
|
+
|
|
19
|
+
Create your `packages/api/src/index.ts`:
|
|
6
20
|
|
|
7
|
-
|
|
21
|
+
```typescript
|
|
22
|
+
import { createMJServer } from '@memberjunction/server-bootstrap';
|
|
8
23
|
|
|
9
|
-
|
|
24
|
+
// Import generated packages to trigger registration
|
|
25
|
+
import '@mycompany/generated-entities';
|
|
26
|
+
import '@mycompany/generated-actions';
|
|
27
|
+
import '@mycompany/generated-resolvers';
|
|
10
28
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
2. Enable secure, token-less publishing from CI/CD workflows
|
|
14
|
-
3. Establish provenance for packages published under this name
|
|
29
|
+
createMJServer().catch(console.error);
|
|
30
|
+
```
|
|
15
31
|
|
|
16
|
-
|
|
32
|
+
**That's it!** Your entire MJAPI application in 6 lines.
|
|
17
33
|
|
|
18
|
-
|
|
34
|
+
### With Custom Configuration
|
|
19
35
|
|
|
20
|
-
|
|
36
|
+
```typescript
|
|
37
|
+
import { createMJServer } from '@memberjunction/server-bootstrap';
|
|
21
38
|
|
|
22
|
-
|
|
39
|
+
createMJServer({
|
|
40
|
+
// Add custom resolver paths
|
|
41
|
+
resolverPaths: ['./custom-resolvers/**/*Resolver.{js,ts}'],
|
|
23
42
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
43
|
+
// Run custom logic before server starts
|
|
44
|
+
beforeStart: async () => {
|
|
45
|
+
console.log('Initializing custom services...');
|
|
46
|
+
// Your initialization code here
|
|
47
|
+
},
|
|
28
48
|
|
|
29
|
-
|
|
49
|
+
// Run custom logic after server starts
|
|
50
|
+
afterStart: async () => {
|
|
51
|
+
console.log('Server is ready!');
|
|
52
|
+
// Your post-startup code here
|
|
53
|
+
},
|
|
30
54
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
55
|
+
// Configure REST API
|
|
56
|
+
restApiOptions: {
|
|
57
|
+
enabled: true,
|
|
58
|
+
includeEntities: ['Users', 'Companies'],
|
|
59
|
+
excludeEntities: ['SystemSettings']
|
|
60
|
+
}
|
|
61
|
+
}).catch(console.error);
|
|
62
|
+
```
|
|
36
63
|
|
|
37
|
-
##
|
|
64
|
+
## What It Does
|
|
38
65
|
|
|
39
|
-
|
|
40
|
-
- [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
|
|
41
|
-
- [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
|
|
66
|
+
The `createMJServer()` function handles:
|
|
42
67
|
|
|
43
|
-
|
|
68
|
+
1. **Configuration Loading** - Automatically finds and loads `mj.config.cjs` or `.mjrc`
|
|
69
|
+
2. **Generated Package Discovery** - Auto-imports generated entities, actions, forms, and resolvers
|
|
70
|
+
3. **Database Connection** - Sets up connection pooling with configured credentials
|
|
71
|
+
4. **GraphQL Schema Building** - Discovers resolvers and builds the GraphQL schema
|
|
72
|
+
5. **WebSocket Setup** - Configures WebSocket support for GraphQL subscriptions
|
|
73
|
+
6. **REST API Setup** - Registers REST endpoints based on configuration
|
|
74
|
+
7. **Graceful Shutdown** - Handles SIGTERM/SIGINT signals properly
|
|
75
|
+
8. **Scheduled Jobs** - Initializes and starts scheduled job service if enabled
|
|
44
76
|
|
|
45
|
-
|
|
77
|
+
## Configuration
|
|
78
|
+
|
|
79
|
+
The function uses your `mj.config.cjs` for all database and server settings:
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
// mj.config.cjs
|
|
83
|
+
module.exports = {
|
|
84
|
+
dbHost: process.env.DB_HOST,
|
|
85
|
+
dbPort: process.env.DB_PORT || 1433,
|
|
86
|
+
dbDatabase: process.env.DB_DATABASE,
|
|
87
|
+
dbUsername: process.env.DB_USERNAME,
|
|
88
|
+
dbPassword: process.env.DB_PASSWORD,
|
|
89
|
+
|
|
90
|
+
graphqlPort: process.env.PORT || 4000,
|
|
91
|
+
|
|
92
|
+
// 3.0 Code Generation Configuration
|
|
93
|
+
codeGeneration: {
|
|
94
|
+
outputMode: 'packages',
|
|
95
|
+
packageScope: '@mycompany',
|
|
96
|
+
packages: {
|
|
97
|
+
entities: {
|
|
98
|
+
path: './packages/generated-entities',
|
|
99
|
+
name: '@mycompany/generated-entities'
|
|
100
|
+
},
|
|
101
|
+
actions: {
|
|
102
|
+
path: './packages/generated-actions',
|
|
103
|
+
name: '@mycompany/generated-actions'
|
|
104
|
+
},
|
|
105
|
+
graphqlResolvers: {
|
|
106
|
+
path: './packages/generated-resolvers',
|
|
107
|
+
name: '@mycompany/generated-resolvers'
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## API Reference
|
|
115
|
+
|
|
116
|
+
### `createMJServer(options?: MJServerConfig): Promise<void>`
|
|
117
|
+
|
|
118
|
+
Creates and starts a MemberJunction API server.
|
|
119
|
+
|
|
120
|
+
#### Parameters
|
|
121
|
+
|
|
122
|
+
- `options.configPath` - Path to config file (optional, auto-discovers if not provided)
|
|
123
|
+
- `options.resolverPaths` - Additional resolver paths beyond defaults
|
|
124
|
+
- `options.beforeStart` - Hook function to run before server starts
|
|
125
|
+
- `options.afterStart` - Hook function to run after server starts
|
|
126
|
+
- `options.restApiOptions` - REST API configuration options
|
|
127
|
+
|
|
128
|
+
#### Returns
|
|
129
|
+
|
|
130
|
+
Promise that resolves when the server is running.
|
|
131
|
+
|
|
132
|
+
## Migration from 2.x
|
|
133
|
+
|
|
134
|
+
In MemberJunction 2.x, your MJAPI/src/index.ts had ~34 lines of boilerplate code for database setup, schema building, etc.
|
|
135
|
+
|
|
136
|
+
**Before (2.x):**
|
|
137
|
+
```typescript
|
|
138
|
+
// 34 lines of configuration, pool setup, schema building, etc.
|
|
139
|
+
import { serve } from '@memberjunction/server';
|
|
140
|
+
// ... lots of setup code ...
|
|
141
|
+
await serve(resolverPaths);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**After (3.0):**
|
|
145
|
+
```typescript
|
|
146
|
+
import { createMJServer } from '@memberjunction/server-bootstrap';
|
|
147
|
+
createMJServer().catch(console.error);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
All the complexity is now encapsulated in this package and updated via NPM.
|
|
151
|
+
|
|
152
|
+
## Benefits
|
|
153
|
+
|
|
154
|
+
- **Zero-copy updates** - `npm update` brings all improvements automatically
|
|
155
|
+
- **No stale code** - Bootstrap logic stays up-to-date with MJ releases
|
|
156
|
+
- **Minimal surface area** - Fewer lines of code means fewer places for bugs
|
|
157
|
+
- **Standard patterns** - Everyone uses the same initialization flow
|
|
158
|
+
- **Extensible** - Hooks allow custom logic without modifying core
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MJServerOptions } from '@memberjunction/server';
|
|
2
|
+
export interface MJServerConfig {
|
|
3
|
+
configPath?: string;
|
|
4
|
+
resolverPaths?: string[];
|
|
5
|
+
beforeStart?: () => void | Promise<void>;
|
|
6
|
+
afterStart?: () => void | Promise<void>;
|
|
7
|
+
restApiOptions?: MJServerOptions['restApiOptions'];
|
|
8
|
+
}
|
|
9
|
+
export declare function createMJServer(options?: MJServerConfig): Promise<void>;
|
|
10
|
+
export type { MJServerOptions } from '@memberjunction/server';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,EAAS,eAAe,EAAc,MAAM,wBAAwB,CAAC;AAM5E,MAAM,WAAW,cAAc;IAI7B,UAAU,CAAC,EAAE,MAAM,CAAC;IAMpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAKzB,WAAW,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAKzC,UAAU,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAKxC,cAAc,CAAC,EAAE,eAAe,CAAC,gBAAgB,CAAC,CAAC;CACpD;AA+ED,wBAAsB,cAAc,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2DhF;AAGD,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { serve } from '@memberjunction/server';
|
|
2
|
+
import { cosmiconfigSync } from 'cosmiconfig';
|
|
3
|
+
async function discoverAndLoadGeneratedPackages(configResult) {
|
|
4
|
+
if (!configResult?.config?.codeGeneration?.packages) {
|
|
5
|
+
console.warn('No codeGeneration.packages configuration found - skipping auto-import of generated packages');
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const packages = configResult.config.codeGeneration.packages;
|
|
9
|
+
const packageTypes = ['entities', 'actions', 'angularForms', 'graphqlResolvers'];
|
|
10
|
+
for (const pkgType of packageTypes) {
|
|
11
|
+
if (packages[pkgType]?.name) {
|
|
12
|
+
const pkgName = packages[pkgType].name;
|
|
13
|
+
try {
|
|
14
|
+
await import(pkgName);
|
|
15
|
+
console.log(`✓ Loaded generated package: ${pkgName}`);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error.code === 'ERR_MODULE_NOT_FOUND') {
|
|
19
|
+
console.log(`ℹ Generated package not found (may not exist yet): ${pkgName}`);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
console.warn(`⚠ Error loading generated package ${pkgName}:`, error);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export async function createMJServer(options = {}) {
|
|
29
|
+
console.log('🚀 MemberJunction 3.0 Server Bootstrap');
|
|
30
|
+
console.log('=====================================\n');
|
|
31
|
+
console.log('');
|
|
32
|
+
const explorer = cosmiconfigSync('mj', { searchStrategy: 'global' });
|
|
33
|
+
const configSearchResult = explorer.search(options.configPath || process.cwd());
|
|
34
|
+
const configResult = {
|
|
35
|
+
config: configSearchResult?.config || {},
|
|
36
|
+
hasUserConfig: configSearchResult && !configSearchResult.isEmpty,
|
|
37
|
+
configFilePath: configSearchResult?.filepath
|
|
38
|
+
};
|
|
39
|
+
console.log('Loading generated packages...');
|
|
40
|
+
await discoverAndLoadGeneratedPackages(configResult);
|
|
41
|
+
console.log('');
|
|
42
|
+
const resolverPaths = options.resolverPaths || [
|
|
43
|
+
'./src/generated/generated.{js,ts}',
|
|
44
|
+
'./dist/generated/generated.{js,ts}',
|
|
45
|
+
'./generated/generated.{js,ts}',
|
|
46
|
+
];
|
|
47
|
+
if (options.beforeStart) {
|
|
48
|
+
console.log('Running pre-start hook...');
|
|
49
|
+
await Promise.resolve(options.beforeStart());
|
|
50
|
+
console.log('');
|
|
51
|
+
}
|
|
52
|
+
const serverOptions = {
|
|
53
|
+
onBeforeServe: options.beforeStart,
|
|
54
|
+
restApiOptions: options.restApiOptions
|
|
55
|
+
};
|
|
56
|
+
console.log('Starting MemberJunction Server...\n');
|
|
57
|
+
await serve(resolverPaths, undefined, serverOptions);
|
|
58
|
+
if (options.afterStart) {
|
|
59
|
+
await Promise.resolve(options.afterStart());
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/server-bootstrap",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "MemberJunction Server Bootstrap - Encapsulates all server initialization logic",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"watch": "tsc --watch",
|
|
11
|
+
"clean": "rm -rf dist"
|
|
12
|
+
},
|
|
5
13
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
14
|
+
"memberjunction",
|
|
15
|
+
"bootstrap",
|
|
16
|
+
"server"
|
|
17
|
+
],
|
|
18
|
+
"author": "MemberJunction",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@memberjunction/core": "3.0.0",
|
|
22
|
+
"@memberjunction/server": "3.0.0",
|
|
23
|
+
"cosmiconfig": "^9.0.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^22.10.2",
|
|
27
|
+
"typescript": "^5.4.5"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist/**/*"
|
|
9
31
|
]
|
|
10
32
|
}
|