@owlmeans/api-config-server 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) 2024 OwlMeans Common — Fullstack typescript framework
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,367 @@
1
+ # @owlmeans/api-config-server
2
+
3
+ The **@owlmeans/api-config-server** package provides server-side functionality for advertising API configuration to clients in OwlMeans Common Libraries, designed for fullstack microservices and microclients development with focus on security and proper authentication and authorization.
4
+
5
+ ## Purpose
6
+
7
+ This package serves as the server-side component of the OwlMeans configuration system that:
8
+
9
+ - **Advertises service configuration** to clients through API endpoints
10
+ - **Filters sensitive information** before sending configuration to clients
11
+ - **Supports multi-service architecture** by exposing service endpoint information
12
+ - **Integrates with server modules** for seamless API endpoint creation
13
+ - **Provides secure configuration sharing** with proper filtering of secrets and internal data
14
+
15
+ ## Core Concepts
16
+
17
+ ### Configuration Advertisement
18
+ The server advertises its configuration to clients through a REST API endpoint, allowing clients to discover available services, their endpoints, and relevant configuration data.
19
+
20
+ ### Information Filtering
21
+ The package carefully filters configuration data to ensure sensitive information (like secrets, API keys, and internal configurations) is not exposed to clients.
22
+
23
+ ### Service Discovery
24
+ Clients can discover all available services, their hosts, ports, and base paths through the configuration API, enabling dynamic service discovery.
25
+
26
+ ### Plugin and Record Sharing
27
+ The server can share frontend-compatible plugins and allowed configuration records with clients.
28
+
29
+ ## API Reference
30
+
31
+ ### Modules
32
+
33
+ #### `modules`
34
+
35
+ Exported server modules array containing the elevated API config module with server-side handler.
36
+
37
+ ```typescript
38
+ import { modules } from '@owlmeans/api-config-server'
39
+
40
+ // Register all server API config modules
41
+ context.registerModules(modules)
42
+ ```
43
+
44
+ ### Actions
45
+
46
+ #### `advertise`
47
+
48
+ The main action handler that processes API configuration requests and returns filtered configuration.
49
+
50
+ ```typescript
51
+ import { advertise } from '@owlmeans/api-config-server'
52
+
53
+ // This handler is automatically attached to the API config module
54
+ // It processes requests and returns filtered configuration
55
+ ```
56
+
57
+ **Returns:** `ApiConfig` object containing:
58
+ - `debug`: Debug configuration (filtered)
59
+ - `brand`: Branding information
60
+ - `services`: Service endpoint information (host, port, base, service name, type)
61
+ - `plugins`: Frontend-compatible plugins
62
+ - `[CONFIG_RECORD]`: Allowed configuration records
63
+ - `oidc`: OIDC configuration (filtered, no secrets)
64
+ - Additional safe configuration fields
65
+
66
+ **Filtering Behavior:**
67
+ - Removes sensitive keys defined in `notAdvertizedConfigKeys`
68
+ - Filters service configurations to include only public information
69
+ - Removes secrets from OIDC configuration
70
+ - Only includes frontend-compatible plugins
71
+ - Only includes allowed configuration record types
72
+
73
+ ## Configuration Filtering
74
+
75
+ The package implements strict filtering to protect sensitive information:
76
+
77
+ ### Service Information
78
+ From each service configuration, only these fields are shared:
79
+ - `service`: Service name
80
+ - `type`: Service type (Frontend/Backend)
81
+ - `host`: Service host
82
+ - `port`: Service port
83
+ - `base`: Base path
84
+
85
+ ### OIDC Configuration
86
+ For OIDC configuration, sensitive fields are filtered out:
87
+ - **Removed**: `secret`, `apiClientId`
88
+ - **Kept**: `clientCookie`, public provider information
89
+ - **Internal providers**: Completely filtered out (where `internal: true`)
90
+
91
+ ### Plugin Filtering
92
+ Only plugins marked as `AppType.Frontend` are included in the advertised configuration.
93
+
94
+ ### Configuration Records
95
+ Only configuration records with types listed in `allowedConfigRecords` are shared with clients.
96
+
97
+ ## Usage Examples
98
+
99
+ ### Basic Server Setup
100
+
101
+ ```typescript
102
+ import { makeServerContext, makeServerConfig } from '@owlmeans/server-context'
103
+ import { modules } from '@owlmeans/api-config-server'
104
+ import { AppType } from '@owlmeans/context'
105
+
106
+ // Create server configuration
107
+ const config = makeServerConfig(AppType.Backend, 'config-server', {
108
+ host: 'localhost',
109
+ port: 3000,
110
+ services: {
111
+ 'user-service': {
112
+ service: 'user-service',
113
+ type: AppType.Backend,
114
+ host: 'users.api.com',
115
+ port: 8080,
116
+ base: '/api/v1'
117
+ },
118
+ 'auth-service': {
119
+ service: 'auth-service',
120
+ type: AppType.Backend,
121
+ host: 'auth.api.com',
122
+ port: 8081,
123
+ secret: 'very-secret-key' // This will be filtered out
124
+ }
125
+ },
126
+ debug: { all: true }
127
+ })
128
+
129
+ // Create and configure context
130
+ const context = makeServerContext(config)
131
+
132
+ // Register API config modules
133
+ context.registerModules(modules)
134
+
135
+ // Configure and initialize
136
+ context.configure()
137
+ await context.init()
138
+
139
+ // API config endpoint is now available at the configured route
140
+ ```
141
+
142
+ ### Integration with Express
143
+
144
+ ```typescript
145
+ import express from 'express'
146
+ import { modules } from '@owlmeans/api-config-server'
147
+ import { API_CONFIG } from '@owlmeans/api-config'
148
+
149
+ const app = express()
150
+
151
+ // After context initialization
152
+ const configModule = context.module(API_CONFIG)
153
+
154
+ // The module has a handler that returns filtered configuration
155
+ app.get('/api/config', async (req, res) => {
156
+ try {
157
+ // The advertise handler is automatically attached
158
+ const request = adaptExpressRequest(req)
159
+ const response = provideResponse()
160
+
161
+ await configModule.handle(request, response)
162
+
163
+ if (response.error) {
164
+ res.status(500).json({ error: response.error.message })
165
+ } else {
166
+ res.json(response.value)
167
+ }
168
+ } catch (error) {
169
+ res.status(500).json({ error: 'Configuration unavailable' })
170
+ }
171
+ })
172
+ ```
173
+
174
+ ### Custom Configuration Filtering
175
+
176
+ ```typescript
177
+ import { makeServerConfig } from '@owlmeans/server-context'
178
+ import { modules } from '@owlmeans/api-config-server'
179
+
180
+ const config = makeServerConfig(AppType.Backend, 'api-server', {
181
+ // Public configuration (will be shared)
182
+ brand: {
183
+ name: 'My Application',
184
+ version: '1.0.0'
185
+ },
186
+
187
+ // Service configuration (filtered)
188
+ services: {
189
+ 'payment-service': {
190
+ service: 'payment-service',
191
+ type: AppType.Backend,
192
+ host: 'payments.api.com',
193
+ port: 443,
194
+ apiKey: 'secret-api-key', // Will be filtered out
195
+ publicEndpoint: '/api/v1' // Will be included as 'base'
196
+ }
197
+ },
198
+
199
+ // OIDC configuration (partially filtered)
200
+ oidc: {
201
+ clientCookie: 'session-cookie', // Will be shared
202
+ providers: [
203
+ {
204
+ name: 'google',
205
+ clientId: 'public-client-id', // Will be shared
206
+ secret: 'client-secret', // Will be filtered out
207
+ issuer: 'https://accounts.google.com'
208
+ },
209
+ {
210
+ name: 'internal-auth',
211
+ internal: true, // Entire provider will be filtered out
212
+ clientId: 'internal-client',
213
+ secret: 'internal-secret'
214
+ }
215
+ ]
216
+ },
217
+
218
+ // Plugins (only frontend plugins shared)
219
+ plugins: [
220
+ {
221
+ name: 'frontend-plugin',
222
+ type: AppType.Frontend,
223
+ config: { theme: 'dark' }
224
+ },
225
+ {
226
+ name: 'backend-plugin',
227
+ type: AppType.Backend,
228
+ config: { database: 'secret-connection' } // Will be filtered out
229
+ }
230
+ ]
231
+ })
232
+ ```
233
+
234
+ ### Multi-Service Architecture
235
+
236
+ ```typescript
237
+ const config = makeServerConfig(AppType.Backend, 'gateway-server', {
238
+ services: {
239
+ 'user-service': {
240
+ service: 'user-service',
241
+ type: AppType.Backend,
242
+ host: 'users.internal.com',
243
+ port: 8080,
244
+ base: '/users'
245
+ },
246
+ 'order-service': {
247
+ service: 'order-service',
248
+ type: AppType.Backend,
249
+ host: 'orders.internal.com',
250
+ port: 8081,
251
+ base: '/orders'
252
+ },
253
+ 'notification-service': {
254
+ service: 'notification-service',
255
+ type: AppType.Backend,
256
+ host: 'notifications.internal.com',
257
+ port: 8082,
258
+ base: '/notifications'
259
+ }
260
+ }
261
+ })
262
+
263
+ const context = makeServerContext(config)
264
+ context.registerModules(modules)
265
+ await context.configure().init()
266
+
267
+ // Clients can now discover all services through the config API
268
+ ```
269
+
270
+ ## Security Considerations
271
+
272
+ ### Information Filtering
273
+ The package implements multiple layers of security:
274
+
275
+ 1. **Automatic Secret Filtering** - Known secret fields are automatically removed
276
+ 2. **Service Information Limiting** - Only essential service discovery information is shared
277
+ 3. **OIDC Security** - Client secrets and internal configurations are filtered
278
+ 4. **Plugin Type Filtering** - Only frontend-compatible plugins are shared
279
+ 5. **Configuration Record Filtering** - Only explicitly allowed record types are shared
280
+
281
+ ### Best Practices
282
+
283
+ 1. **Minimize exposed information** - Only include necessary configuration in server config
284
+ 2. **Use environment variables** - Store secrets in environment variables, not configuration
285
+ 3. **Implement authentication** - Protect the config endpoint with appropriate authentication
286
+ 4. **Monitor access** - Log and monitor who accesses configuration endpoints
287
+ 5. **Regular security audits** - Review what information is being exposed
288
+
289
+ ### Example Security Setup
290
+
291
+ ```typescript
292
+ import { modules } from '@owlmeans/api-config-server'
293
+ import { authenticatedGuard } from '@owlmeans/server-auth'
294
+
295
+ // Protect configuration endpoint with authentication
296
+ const configModule = context.module(API_CONFIG)
297
+ configModule.guards = ['authenticated']
298
+
299
+ // Or use custom middleware for additional security
300
+ app.get('/api/config', authenticateRequest, async (req, res) => {
301
+ // Only authenticated clients can access configuration
302
+ })
303
+ ```
304
+
305
+ ## Integration Patterns
306
+
307
+ ### Microservices Gateway
308
+
309
+ ```typescript
310
+ // Gateway server that advertises all microservice endpoints
311
+ const gatewayConfig = makeServerConfig(AppType.Backend, 'api-gateway', {
312
+ services: {
313
+ ...userServiceConfig,
314
+ ...orderServiceConfig,
315
+ ...paymentServiceConfig,
316
+ ...notificationServiceConfig
317
+ }
318
+ })
319
+
320
+ // Clients connect to gateway and get all service information
321
+ ```
322
+
323
+ ### Development vs Production
324
+
325
+ ```typescript
326
+ const isDevelopment = process.env.NODE_ENV === 'development'
327
+
328
+ const config = makeServerConfig(AppType.Backend, 'api-server', {
329
+ debug: isDevelopment ? { all: true } : {},
330
+ services: {
331
+ 'user-service': {
332
+ service: 'user-service',
333
+ type: AppType.Backend,
334
+ host: isDevelopment ? 'localhost' : 'users.prod.com',
335
+ port: isDevelopment ? 3001 : 443,
336
+ base: '/api/v1'
337
+ }
338
+ }
339
+ })
340
+ ```
341
+
342
+ ## Error Handling
343
+
344
+ The package handles configuration errors gracefully:
345
+
346
+ - **Missing configuration** - Returns empty or default values
347
+ - **Invalid service configs** - Filters out malformed service entries
348
+ - **Plugin errors** - Continues processing even if plugin filtering fails
349
+ - **OIDC parsing errors** - Falls back to basic configuration
350
+
351
+ ## Related Packages
352
+
353
+ - [`@owlmeans/api-config`](../api-config) - Common API config module definitions
354
+ - [`@owlmeans/api-config-client`](../api-config-client) - Client-side configuration fetching
355
+ - [`@owlmeans/server-context`](../server-context) - Server-side context management
356
+ - [`@owlmeans/server-module`](../server-module) - Server-side module system
357
+ - [`@owlmeans/config`](../config) - Configuration management utilities
358
+
359
+ ## Dependencies
360
+
361
+ This package depends on:
362
+ - `@owlmeans/api-config` - Common API config definitions and constants
363
+ - `@owlmeans/server-module` - Server-side module elevation and handling
364
+ - `@owlmeans/server-context` - Server context types and configuration
365
+ - `@owlmeans/server-api` - Request handling utilities
366
+ - `@owlmeans/config` - Configuration management and plugin types
367
+ - `@owlmeans/context` - Core context functionality and types
package/build/.gitkeep ADDED
File without changes
@@ -0,0 +1,4 @@
1
+ import type { RefedModuleHandler } from '@owlmeans/server-module';
2
+ import type { ApiConfig } from '@owlmeans/api-config';
3
+ export declare const advertise: RefedModuleHandler<ApiConfig>;
4
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/actions/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AASrD,eAAO,MAAM,SAAS,EAAE,kBAAkB,CAAC,SAAS,CAuClD,CAAA"}
@@ -0,0 +1,34 @@
1
+ import { notAdvertizedConfigKeys, allowedConfigRecords } from '@owlmeans/api-config';
2
+ import { handleRequest } from '@owlmeans/server-api';
3
+ import { PLUGINS } from '@owlmeans/config';
4
+ import { AppType, CONFIG_RECORD } from '@owlmeans/context';
5
+ export const advertise = handleRequest(async (_, ctx) => {
6
+ const apiConfig = {
7
+ debug: ctx.cfg.debug ?? {},
8
+ brand: {},
9
+ services: Object.fromEntries(Object.entries(ctx.cfg.services ?? {}).map(([service, config]) => [
10
+ service, {
11
+ service: config.service,
12
+ type: config.type,
13
+ host: config.host,
14
+ port: config.port,
15
+ base: config.base
16
+ }
17
+ ])),
18
+ plugins: (ctx.cfg[PLUGINS] ?? [])
19
+ .filter((plugin) => plugin.type === AppType.Frontend),
20
+ [CONFIG_RECORD]: (ctx.cfg[CONFIG_RECORD] ?? []).filter((record) => record.recordType != null && allowedConfigRecords.includes(record.recordType)),
21
+ ...(Object.fromEntries(Object.entries(ctx.cfg).filter(([key]) => ![
22
+ 'debug', 'services', PLUGINS, ...notAdvertizedConfigKeys
23
+ ].includes(key)))),
24
+ ...("oidc" in ctx.cfg ? {
25
+ oidc: {
26
+ clientCookie: ctx.cfg.oidc.clientCookie,
27
+ providers: ctx.cfg.oidc.providers?.map(provider => Object.fromEntries(Object.entries(provider)
28
+ .filter(([key]) => !['secret', 'apiClientId'].includes(key)))).filter(provider => provider.internal !== true),
29
+ }
30
+ } : {})
31
+ };
32
+ return apiConfig;
33
+ });
34
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/actions/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AACpF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAG1D,MAAM,CAAC,MAAM,SAAS,GAAkC,aAAa,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE;IACrF,MAAM,SAAS,GAAc;QAC3B,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;QAC1B,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,MAAM,CAAC,WAAW,CAC1B,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAkB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;YAChF,OAAO,EAAE;gBACP,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,IAAI,EAAE,MAAM,CAAC,IAAI;aAClB;SACF,CAAC,CACH;QACD,OAAO,EAAE,CAAE,GAAG,CAAC,GAAiD,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;aAC7E,MAAM,CAAC,CAAC,MAAoB,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,QAAQ,CAAC;QACrE,CAAC,aAAa,CAAC,EAAE,CAAE,GAAG,CAAC,GAAiD,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CACnG,CAAC,MAAoB,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,IAAI,IAAI,IAAI,oBAAoB,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CACxG;QACD,GAAG,CACD,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;YACzC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,uBAAuB;SACzD,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CACjB,CACF;QACD,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YACtB,IAAI,EAAE;gBACJ,YAAY,EAAG,GAAG,CAAC,GAAG,CAAC,IAAkC,CAAC,YAAY;gBACtE,SAAS,EAAG,GAAG,CAAC,GAAG,CAAC,IAAgC,CAAC,SAAS,EAAE,GAAG,CACjE,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;qBACpD,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAChE,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,KAAK,IAAI,CAAC;aACjD;SACF,CAAC,CAAC,CAAC,EAAE,CAAC;KACR,CAAA;IAED,OAAO,SAAS,CAAA;AAClB,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export * as config from './config.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/actions/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA"}
@@ -0,0 +1,2 @@
1
+ export * as config from './config.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/actions/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA"}
@@ -0,0 +1,2 @@
1
+ export * from './modules.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA"}
package/build/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from './modules.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { ServerModule } from '@owlmeans/server-module';
2
+ export declare const modules: ServerModule<unknown>[];
3
+ //# sourceMappingURL=modules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAO3D,eAAO,MAAM,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,EAE1C,CAAA"}
@@ -0,0 +1,8 @@
1
+ import { elevate } from '@owlmeans/server-module';
2
+ import { modules as list, API_CONFIG } from '@owlmeans/api-config';
3
+ import { config } from './actions/index.js';
4
+ elevate(list, API_CONFIG, config.advertise);
5
+ export const modules = [
6
+ ...list.filter((module) => module.getAlias() === API_CONFIG)
7
+ ];
8
+ //# sourceMappingURL=modules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modules.js","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAE3C,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;AAE3C,MAAM,CAAC,MAAM,OAAO,GAA4B;IAC9C,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,EAAmC,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,UAAU,CAAC;CAC9F,CAAA"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@owlmeans/api-config-server",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsc -b",
7
+ "dev": "sleep 18 && nodemon -e ts,tsx,json --watch src --exec \"tsc -p ./tsconfig.json\"",
8
+ "watch": "tsc -b -w --preserveWatchOutput --pretty"
9
+ },
10
+ "main": "build/index.js",
11
+ "module": "build/index.js",
12
+ "types": "build/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "import": "./build/index.js",
16
+ "require": "./build/index.js",
17
+ "default": "./build/index.js",
18
+ "module": "./build/index.js",
19
+ "types": "./build/index.d.ts"
20
+ }
21
+ },
22
+ "dependencies": {
23
+ "@owlmeans/api-config": "^0.1.0",
24
+ "@owlmeans/server-api": "^0.1.0",
25
+ "@owlmeans/server-context": "^0.1.0",
26
+ "@owlmeans/server-module": "^0.1.0"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^22.7.8",
30
+ "nodemon": "^3.1.7",
31
+ "typescript": "^5.6.3"
32
+ },
33
+ "private": false,
34
+ "publishConfig": {
35
+ "access": "public"
36
+ }
37
+ }
@@ -0,0 +1,50 @@
1
+ import type { RefedModuleHandler } from '@owlmeans/server-module'
2
+ import type { ApiConfig } from '@owlmeans/api-config'
3
+ import type { ServerConfig } from '@owlmeans/server-context'
4
+ import type { PluginConfig } from '@owlmeans/config'
5
+ import { notAdvertizedConfigKeys, allowedConfigRecords } from '@owlmeans/api-config'
6
+ import { handleRequest } from '@owlmeans/server-api'
7
+ import { PLUGINS } from '@owlmeans/config'
8
+ import { AppType, CONFIG_RECORD } from '@owlmeans/context'
9
+ import type { ConfigRecord } from '@owlmeans/context'
10
+
11
+ export const advertise: RefedModuleHandler<ApiConfig> = handleRequest(async (_, ctx) => {
12
+ const apiConfig: ApiConfig = {
13
+ debug: ctx.cfg.debug ?? {},
14
+ brand: {},
15
+ services: Object.fromEntries(
16
+ Object.entries(ctx.cfg.services ?? {} as ServerConfig).map(([service, config]) => [
17
+ service, {
18
+ service: config.service,
19
+ type: config.type,
20
+ host: config.host,
21
+ port: config.port,
22
+ base: config.base
23
+ }
24
+ ])
25
+ ),
26
+ plugins: ((ctx.cfg as unknown as Record<string, PluginConfig[]>)[PLUGINS] ?? [])
27
+ .filter((plugin: PluginConfig) => plugin.type === AppType.Frontend),
28
+ [CONFIG_RECORD]: ((ctx.cfg as unknown as Record<string, ConfigRecord[]>)[CONFIG_RECORD] ?? []).filter(
29
+ (record: ConfigRecord) => record.recordType != null && allowedConfigRecords.includes(record.recordType)
30
+ ),
31
+ ...(
32
+ Object.fromEntries(
33
+ Object.entries(ctx.cfg).filter(([key]) => ![
34
+ 'debug', 'services', PLUGINS, ...notAdvertizedConfigKeys
35
+ ].includes(key))
36
+ )
37
+ ),
38
+ ...("oidc" in ctx.cfg ? {
39
+ oidc: {
40
+ clientCookie: (ctx.cfg.oidc as { clientCookie: unknown }).clientCookie,
41
+ providers: (ctx.cfg.oidc as { providers: Object[] }).providers?.map(
42
+ provider => Object.fromEntries(Object.entries(provider)
43
+ .filter(([key]) => !['secret', 'apiClientId'].includes(key)))
44
+ ).filter(provider => provider.internal !== true),
45
+ }
46
+ } : {})
47
+ }
48
+
49
+ return apiConfig
50
+ })
@@ -0,0 +1,2 @@
1
+
2
+ export * as config from './config.js'
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+
2
+ export * from './modules.js'
package/src/modules.ts ADDED
@@ -0,0 +1,11 @@
1
+
2
+ import type { ServerModule } from '@owlmeans/server-module'
3
+ import { elevate } from '@owlmeans/server-module'
4
+ import { modules as list, API_CONFIG } from '@owlmeans/api-config'
5
+ import { config } from './actions/index.js'
6
+
7
+ elevate(list, API_CONFIG, config.advertise)
8
+
9
+ export const modules: ServerModule<unknown>[] = [
10
+ ...list.filter((module): module is ServerModule<unknown> => module.getAlias() === API_CONFIG)
11
+ ]
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": [
3
+ "../tsconfig.default.json",
4
+ ],
5
+ "compilerOptions": {
6
+ "rootDir": "./src/", /* Specify the root folder within your source files. */
7
+ "outDir": "./build/", /* Specify an output folder for all emitted files. */
8
+ },
9
+ "exclude": [
10
+ "./dist/**/*",
11
+ "./build/**/*",
12
+ "./*.ts"
13
+ ]
14
+ }
@@ -0,0 +1 @@
1
+ {"root":["./src/index.ts","./src/modules.ts","./src/actions/config.ts","./src/actions/index.ts"],"version":"5.6.3"}