@omen.foundation/node-microservice-runtime 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.
Files changed (145) hide show
  1. package/.env +13 -0
  2. package/dist/auth.cjs +97 -0
  3. package/dist/auth.d.ts +14 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +93 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/cli/index.d.ts +3 -0
  8. package/dist/cli/index.d.ts.map +1 -0
  9. package/dist/cli/index.js +588 -0
  10. package/dist/cli/index.js.map +1 -0
  11. package/dist/decorators.cjs +181 -0
  12. package/dist/decorators.d.ts +23 -0
  13. package/dist/decorators.d.ts.map +1 -0
  14. package/dist/decorators.js +155 -0
  15. package/dist/decorators.js.map +1 -0
  16. package/dist/dependency.cjs +165 -0
  17. package/dist/dependency.d.ts +56 -0
  18. package/dist/dependency.d.ts.map +1 -0
  19. package/dist/dependency.js +162 -0
  20. package/dist/dependency.js.map +1 -0
  21. package/dist/dev.cjs +34 -0
  22. package/dist/dev.d.ts +9 -0
  23. package/dist/dev.d.ts.map +1 -0
  24. package/dist/dev.js +32 -0
  25. package/dist/dev.js.map +1 -0
  26. package/dist/discovery.cjs +79 -0
  27. package/dist/discovery.d.ts +20 -0
  28. package/dist/discovery.d.ts.map +1 -0
  29. package/dist/discovery.js +75 -0
  30. package/dist/discovery.js.map +1 -0
  31. package/dist/docs.cjs +206 -0
  32. package/dist/docs.d.ts +30 -0
  33. package/dist/docs.d.ts.map +1 -0
  34. package/dist/docs.js +209 -0
  35. package/dist/docs.js.map +1 -0
  36. package/dist/env.cjs +106 -0
  37. package/dist/env.d.ts +4 -0
  38. package/dist/env.d.ts.map +1 -0
  39. package/dist/env.js +108 -0
  40. package/dist/env.js.map +1 -0
  41. package/dist/errors.cjs +58 -0
  42. package/dist/errors.d.ts +26 -0
  43. package/dist/errors.d.ts.map +1 -0
  44. package/dist/errors.js +48 -0
  45. package/dist/errors.js.map +1 -0
  46. package/dist/federation.cjs +356 -0
  47. package/dist/federation.d.ts +108 -0
  48. package/dist/federation.d.ts.map +1 -0
  49. package/dist/federation.js +341 -0
  50. package/dist/federation.js.map +1 -0
  51. package/dist/index.cjs +42 -0
  52. package/dist/index.d.ts +13 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +10 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/inventory.cjs +361 -0
  57. package/dist/inventory.d.ts +116 -0
  58. package/dist/inventory.d.ts.map +1 -0
  59. package/dist/inventory.js +351 -0
  60. package/dist/inventory.js.map +1 -0
  61. package/dist/logger.cjs +62 -0
  62. package/dist/logger.d.ts +9 -0
  63. package/dist/logger.d.ts.map +1 -0
  64. package/dist/logger.js +29 -0
  65. package/dist/logger.js.map +1 -0
  66. package/dist/message.cjs +19 -0
  67. package/dist/message.d.ts +5 -0
  68. package/dist/message.d.ts.map +1 -0
  69. package/dist/message.js +15 -0
  70. package/dist/message.js.map +1 -0
  71. package/dist/requester.cjs +100 -0
  72. package/dist/requester.d.ts +20 -0
  73. package/dist/requester.d.ts.map +1 -0
  74. package/dist/requester.js +99 -0
  75. package/dist/requester.js.map +1 -0
  76. package/dist/routing.cjs +39 -0
  77. package/dist/routing.d.ts +2 -0
  78. package/dist/routing.d.ts.map +1 -0
  79. package/dist/routing.js +36 -0
  80. package/dist/routing.js.map +1 -0
  81. package/dist/runtime.cjs +735 -0
  82. package/dist/runtime.d.ts +40 -0
  83. package/dist/runtime.d.ts.map +1 -0
  84. package/dist/runtime.js +825 -0
  85. package/dist/runtime.js.map +1 -0
  86. package/dist/services.cjs +346 -0
  87. package/dist/services.d.ts +46 -0
  88. package/dist/services.d.ts.map +1 -0
  89. package/dist/services.js +343 -0
  90. package/dist/services.js.map +1 -0
  91. package/dist/storage.cjs +147 -0
  92. package/dist/storage.d.ts +46 -0
  93. package/dist/storage.d.ts.map +1 -0
  94. package/dist/storage.js +144 -0
  95. package/dist/storage.js.map +1 -0
  96. package/dist/types.cjs +2 -0
  97. package/dist/types.d.ts +108 -0
  98. package/dist/types.d.ts.map +1 -0
  99. package/dist/types.js +2 -0
  100. package/dist/types.js.map +1 -0
  101. package/dist/utils/urls.cjs +55 -0
  102. package/dist/utils/urls.d.ts +5 -0
  103. package/dist/utils/urls.d.ts.map +1 -0
  104. package/dist/utils/urls.js +50 -0
  105. package/dist/utils/urls.js.map +1 -0
  106. package/dist/websocket.cjs +142 -0
  107. package/dist/websocket.d.ts +33 -0
  108. package/dist/websocket.d.ts.map +1 -0
  109. package/dist/websocket.js +139 -0
  110. package/dist/websocket.js.map +1 -0
  111. package/env.sample +13 -0
  112. package/package.json +49 -0
  113. package/scripts/generate-openapi.mjs +114 -0
  114. package/scripts/lib/cli-utils.mjs +58 -0
  115. package/scripts/prepare-cjs.mjs +44 -0
  116. package/scripts/publish-service.mjs +1126 -0
  117. package/scripts/validate-service.mjs +103 -0
  118. package/scripts/ws-test.mjs +25 -0
  119. package/src/auth.ts +117 -0
  120. package/src/cli/index.ts +699 -0
  121. package/src/decorators.ts +207 -0
  122. package/src/dependency.ts +211 -0
  123. package/src/dev.ts +17 -0
  124. package/src/discovery.ts +88 -0
  125. package/src/docs.ts +262 -0
  126. package/src/env.ts +125 -0
  127. package/src/errors.ts +55 -0
  128. package/src/federation.ts +559 -0
  129. package/src/index.ts +51 -0
  130. package/src/inventory.ts +491 -0
  131. package/src/logger.ts +38 -0
  132. package/src/message.ts +19 -0
  133. package/src/requester.ts +126 -0
  134. package/src/routing.ts +42 -0
  135. package/src/runtime.ts +967 -0
  136. package/src/services.ts +459 -0
  137. package/src/storage.ts +206 -0
  138. package/src/types/beamable-sdk-api.d.ts +5 -0
  139. package/src/types.ts +117 -0
  140. package/src/utils/urls.ts +53 -0
  141. package/src/websocket.ts +170 -0
  142. package/tsconfig.base.json +31 -0
  143. package/tsconfig.build.json +10 -0
  144. package/tsconfig.cjs.json +16 -0
  145. package/tsconfig.dev.json +14 -0
@@ -0,0 +1,343 @@
1
+ import { BeamServer, BeamEnvironment, defaultTokenStorage, AccountService, AnnouncementsService, AuthService, ContentService, LeaderboardsService, StatsService, } from 'beamable-sdk';
2
+ import { hostToHttpUrl, hostToPortalUrl, hostToStorageUrl, hostToMicroserviceRegistryUrl } from './utils/urls.js';
3
+ import { createInventoryService } from './inventory.js';
4
+ import { StorageService } from './storage.js';
5
+ import { MissingScopesError } from './errors.js';
6
+ const RUNTIME_ENVIRONMENT_NAME = 'node-runtime';
7
+ let cachedBeamApiModule = null;
8
+ async function resolveBeamApiModule() {
9
+ if (!cachedBeamApiModule) {
10
+ const imported = await import('beamable-sdk/api');
11
+ cachedBeamApiModule =
12
+ imported && typeof imported === 'object' && 'default' in imported
13
+ ? imported.default
14
+ : imported;
15
+ }
16
+ return cachedBeamApiModule;
17
+ }
18
+ async function bindBeamApi(requester) {
19
+ const module = await resolveBeamApiModule();
20
+ const bound = {};
21
+ for (const key of Object.keys(module)) {
22
+ const value = module[key];
23
+ if (typeof value === 'function') {
24
+ bound[key] = (...args) => value(requester, ...args);
25
+ }
26
+ }
27
+ return bound;
28
+ }
29
+ function createFailingApi(error) {
30
+ return new Proxy({}, {
31
+ get() {
32
+ throw error;
33
+ },
34
+ });
35
+ }
36
+ class UnavailableRequester {
37
+ error;
38
+ constructor(error) {
39
+ this.error = error;
40
+ }
41
+ async request() {
42
+ throw this.error;
43
+ }
44
+ set baseUrl(_) {
45
+ // no-op
46
+ }
47
+ set defaultHeaders(_) {
48
+ // no-op
49
+ }
50
+ }
51
+ class UnavailableBeamableServices {
52
+ error;
53
+ requesterImpl;
54
+ apiBindings;
55
+ constructor(error) {
56
+ this.error = error;
57
+ this.requesterImpl = new UnavailableRequester(this.error);
58
+ this.apiBindings = createFailingApi(this.error);
59
+ }
60
+ fail() {
61
+ throw this.error;
62
+ }
63
+ get account() {
64
+ return this.fail();
65
+ }
66
+ get announcements() {
67
+ return this.fail();
68
+ }
69
+ get auth() {
70
+ return this.fail();
71
+ }
72
+ get content() {
73
+ return this.fail();
74
+ }
75
+ get leaderboards() {
76
+ return this.fail();
77
+ }
78
+ get stats() {
79
+ return this.fail();
80
+ }
81
+ get inventory() {
82
+ return this.fail();
83
+ }
84
+ get storage() {
85
+ return this.fail();
86
+ }
87
+ get federation() {
88
+ return this.fail();
89
+ }
90
+ get api() {
91
+ return this.apiBindings;
92
+ }
93
+ get requester() {
94
+ return this.requesterImpl;
95
+ }
96
+ hasScopes(..._scopes) {
97
+ return false;
98
+ }
99
+ requireScopes(...scopes) {
100
+ throw new MissingScopesError(scopes);
101
+ }
102
+ assumeUser() {
103
+ return this;
104
+ }
105
+ }
106
+ class BeamableServicesFacade {
107
+ manager;
108
+ beamServer;
109
+ userId;
110
+ cache = {};
111
+ apiBindings;
112
+ storageService;
113
+ scopes;
114
+ logger;
115
+ serviceName;
116
+ federationRegistry;
117
+ inventoryClient;
118
+ constructor(manager, beamServer, userId, scopes, serviceName) {
119
+ this.manager = manager;
120
+ this.beamServer = beamServer;
121
+ this.userId = userId;
122
+ this.apiBindings = this.manager.getBoundApi();
123
+ this.storageService = this.manager.getStorageService();
124
+ this.scopes = scopes;
125
+ this.serviceName = serviceName;
126
+ this.federationRegistry = serviceName ? this.manager.getFederationRegistry(serviceName) : undefined;
127
+ this.logger = this.manager.getLogger().child({ component: 'BeamableServicesFacade', service: serviceName });
128
+ }
129
+ getOrCreate(key, factory) {
130
+ if (!this.cache[key]) {
131
+ this.cache[key] = factory();
132
+ }
133
+ return this.cache[key];
134
+ }
135
+ get account() {
136
+ return this.getOrCreate('account', () => this.beamServer.account(this.userId));
137
+ }
138
+ get announcements() {
139
+ return this.getOrCreate('announcements', () => this.beamServer.announcements(this.userId));
140
+ }
141
+ get auth() {
142
+ return this.getOrCreate('auth', () => this.beamServer.auth(this.userId));
143
+ }
144
+ get content() {
145
+ return this.getOrCreate('content', () => this.beamServer.content(this.userId));
146
+ }
147
+ get leaderboards() {
148
+ return this.getOrCreate('leaderboards', () => this.beamServer.leaderboards(this.userId));
149
+ }
150
+ get stats() {
151
+ return this.getOrCreate('stats', () => this.beamServer.stats(this.userId));
152
+ }
153
+ get inventory() {
154
+ if (!this.inventoryClient) {
155
+ this.inventoryClient = createInventoryService(this.apiBindings, this.logger.child({ component: 'InventoryClient' }), this.userId, (requiredScopes) => this.hasScopes(...requiredScopes));
156
+ }
157
+ return this.inventoryClient;
158
+ }
159
+ get storage() {
160
+ return this.storageService;
161
+ }
162
+ get federation() {
163
+ if (!this.federationRegistry) {
164
+ throw new Error(this.serviceName
165
+ ? `Federation registry is not configured for service "${this.serviceName}".`
166
+ : 'Federation registry is not configured.');
167
+ }
168
+ return this.federationRegistry;
169
+ }
170
+ get api() {
171
+ return this.apiBindings;
172
+ }
173
+ get requester() {
174
+ return this.manager.getRequester();
175
+ }
176
+ hasScopes(...requiredScopes) {
177
+ if (requiredScopes.length === 0) {
178
+ return true;
179
+ }
180
+ return requiredScopes.every((scope) => this.scopeSetHas(scope));
181
+ }
182
+ requireScopes(...requiredScopes) {
183
+ if (!this.hasScopes(...requiredScopes)) {
184
+ throw new MissingScopesError(requiredScopes);
185
+ }
186
+ }
187
+ assumeUser(userId) {
188
+ return this.manager.createFacade(String(userId), new Set(this.scopes), this.serviceName);
189
+ }
190
+ scopeSetHas(scope) {
191
+ const normalized = scope.trim().toLowerCase();
192
+ if (!normalized) {
193
+ return false;
194
+ }
195
+ return this.scopes.has('*') || this.scopes.has(normalized);
196
+ }
197
+ }
198
+ export class BeamableServiceManager {
199
+ logger;
200
+ tokenStorage;
201
+ env;
202
+ beamServer;
203
+ boundApi;
204
+ storageService;
205
+ initialized = false;
206
+ federationRegistries = new Map();
207
+ constructor(env, logger) {
208
+ this.env = env;
209
+ this.logger = logger.child({ component: 'BeamableServiceManager' });
210
+ this.tokenStorage = defaultTokenStorage({ pid: env.pid, tag: env.routingKey ?? RUNTIME_ENVIRONMENT_NAME });
211
+ }
212
+ async initialize() {
213
+ if (this.initialized) {
214
+ return;
215
+ }
216
+ this.registerEnvironment();
217
+ this.configureSharedEnvironment();
218
+ if (this.env.refreshToken) {
219
+ await this.tokenStorage.setTokenData({ refreshToken: this.env.refreshToken });
220
+ }
221
+ const useSignedRequest = Boolean(this.env.secret);
222
+ if (!useSignedRequest && !this.env.refreshToken) {
223
+ this.logger.warn('Beamable realm secret and refresh token are both missing; Beamable SDK requests may fail due to missing credentials.');
224
+ }
225
+ try {
226
+ this.beamServer = await BeamServer.init({
227
+ cid: this.env.cid,
228
+ pid: this.env.pid,
229
+ environment: RUNTIME_ENVIRONMENT_NAME,
230
+ useSignedRequest,
231
+ tokenStorage: this.tokenStorage,
232
+ serverEvents: { enabled: false },
233
+ });
234
+ }
235
+ catch (error) {
236
+ this.logger.error({ err: error }, 'Failed to initialize Beamable SDK. Services layer will be unavailable.');
237
+ this.beamServer = undefined;
238
+ this.initialized = false;
239
+ return;
240
+ }
241
+ this.boundApi = await bindBeamApi(this.beamServer.requester);
242
+ // Configure the requester's default headers to include the routing key in the correct format
243
+ // The routing key format is: serviceName:routingKey
244
+ // We'll set this per-request in createFacade since we need the service name
245
+ this.storageService = new StorageService({
246
+ requester: this.beamServer.requester,
247
+ api: this.boundApi,
248
+ env: this.env,
249
+ logger: this.logger.child({ component: 'StorageService' }),
250
+ });
251
+ this.registerDefaultServices();
252
+ this.initialized = true;
253
+ this.logger.debug('Beamable SDK services initialized.');
254
+ }
255
+ createFacade(userId, scopes, serviceName) {
256
+ if (!this.initialized || !this.beamServer || !this.boundApi || !this.storageService) {
257
+ return new UnavailableBeamableServices(new Error('Beamable services are not initialized.'));
258
+ }
259
+ // Set the routing key in the format serviceName:routingKey for the SDK
260
+ // The SDK uses BEAM_ROUTING_KEY environment variable to construct the X-BEAM-SERVICE-ROUTING-KEY header
261
+ // We need to set it to the full format: serviceName:routingKey
262
+ if (serviceName && this.beamServer.requester) {
263
+ const fullRoutingKey = `micro_${serviceName}:${this.env.routingKey}`;
264
+ BeamServer.env.BEAM_ROUTING_KEY = fullRoutingKey;
265
+ // Set default headers on the requester for all SDK requests
266
+ // These headers are required for signature validation and routing
267
+ const scopeHeader = `${this.env.cid}.${this.env.pid}`;
268
+ this.beamServer.requester.defaultHeaders = {
269
+ ...this.beamServer.requester.defaultHeaders,
270
+ 'X-BEAM-SCOPE': scopeHeader,
271
+ 'X-BEAM-SERVICE-ROUTING-KEY': fullRoutingKey,
272
+ };
273
+ }
274
+ return new BeamableServicesFacade(this, this.beamServer, String(userId), new Set(scopes), serviceName);
275
+ }
276
+ getRequester() {
277
+ if (!this.initialized || !this.beamServer) {
278
+ return new UnavailableRequester(new Error('Beamable services are not initialized.'));
279
+ }
280
+ return this.beamServer.requester;
281
+ }
282
+ getBoundApi() {
283
+ if (!this.boundApi) {
284
+ throw new Error('Beamable bound API is not available.');
285
+ }
286
+ return this.boundApi;
287
+ }
288
+ getStorageService() {
289
+ if (!this.storageService) {
290
+ throw new Error('Storage service is not initialized.');
291
+ }
292
+ return this.storageService;
293
+ }
294
+ getLogger() {
295
+ return this.logger;
296
+ }
297
+ registerFederationRegistry(serviceName, registry) {
298
+ this.federationRegistries.set(serviceName, registry);
299
+ }
300
+ getFederationRegistry(serviceName) {
301
+ return this.federationRegistries.get(serviceName);
302
+ }
303
+ registerEnvironment() {
304
+ const apiUrl = hostToHttpUrl(this.env.host);
305
+ const portalUrl = hostToPortalUrl(apiUrl);
306
+ const storageUrl = hostToStorageUrl(apiUrl);
307
+ const registryUrl = hostToMicroserviceRegistryUrl(apiUrl);
308
+ try {
309
+ BeamEnvironment.register(RUNTIME_ENVIRONMENT_NAME, {
310
+ apiUrl,
311
+ portalUrl,
312
+ beamMongoExpressUrl: storageUrl,
313
+ dockerRegistryUrl: `${registryUrl}/v2/`,
314
+ });
315
+ }
316
+ catch (error) {
317
+ this.logger.debug({ err: error }, 'Beamable environment was already registered. Reusing existing configuration.');
318
+ }
319
+ }
320
+ configureSharedEnvironment() {
321
+ if (this.env.secret) {
322
+ BeamServer.env.BEAM_REALM_SECRET = this.env.secret;
323
+ }
324
+ // BEAM_ROUTING_KEY is used by the SDK to construct the X-BEAM-SERVICE-ROUTING-KEY header
325
+ // We set it to just the routing key value here, and will set the full format in createFacade
326
+ // BEAM_ROUTING_KEY is used by the SDK to construct the X-BEAM-SERVICE-ROUTING-KEY header
327
+ // For deployed services, routingKey is undefined, so we set it to empty string
328
+ // The SDK will handle this appropriately
329
+ BeamServer.env.BEAM_ROUTING_KEY = this.env.routingKey ?? '';
330
+ }
331
+ registerDefaultServices() {
332
+ if (!this.beamServer) {
333
+ return;
334
+ }
335
+ this.beamServer.use(AccountService);
336
+ this.beamServer.use(AnnouncementsService);
337
+ this.beamServer.use(AuthService);
338
+ this.beamServer.use(ContentService);
339
+ this.beamServer.use(LeaderboardsService);
340
+ this.beamServer.use(StatsService);
341
+ }
342
+ }
343
+ //# sourceMappingURL=services.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services.js","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Logger } from 'pino';\r\nimport {\r\n BeamServer,\r\n BeamEnvironment,\r\n defaultTokenStorage,\r\n type HttpRequester,\r\n AccountService,\r\n AnnouncementsService,\r\n AuthService,\r\n ContentService,\r\n LeaderboardsService,\r\n StatsService,\r\n} from 'beamable-sdk';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport { hostToHttpUrl, hostToPortalUrl, hostToStorageUrl, hostToMicroserviceRegistryUrl } from './utils/urls.js';\r\nimport { createInventoryService, type InventoryService } from './inventory.js';\r\nimport { StorageService } from './storage.js';\r\nimport type { FederationRegistry } from './federation.js';\r\nimport { MissingScopesError } from './errors.js';\r\n\r\nconst RUNTIME_ENVIRONMENT_NAME = 'node-runtime';\r\n\r\nexport type BoundBeamApi = Record<string, (...args: unknown[]) => unknown>;\r\n\r\nlet cachedBeamApiModule: Record<string, unknown> | null = null;\r\n\r\nasync function resolveBeamApiModule(): Promise<Record<string, unknown>> {\r\n if (!cachedBeamApiModule) {\r\n const imported = await import('beamable-sdk/api');\r\n cachedBeamApiModule =\r\n imported && typeof imported === 'object' && 'default' in imported\r\n ? (imported.default as Record<string, unknown>)\r\n : (imported as Record<string, unknown>);\r\n }\r\n return cachedBeamApiModule;\r\n}\r\n\r\nasync function bindBeamApi(requester: HttpRequester): Promise<BoundBeamApi> {\r\n const module = await resolveBeamApiModule();\r\n const bound: Record<string, (...args: unknown[]) => unknown> = {};\r\n for (const key of Object.keys(module)) {\r\n const value = module[key];\r\n if (typeof value === 'function') {\r\n bound[key] = (...args: unknown[]) => (value as (r: HttpRequester, ...params: unknown[]) => unknown)(requester, ...args);\r\n }\r\n }\r\n return bound;\r\n}\r\n\r\nfunction createFailingApi(error: Error): BoundBeamApi {\r\n return new Proxy(\r\n {},\r\n {\r\n get() {\r\n throw error;\r\n },\r\n },\r\n ) as BoundBeamApi;\r\n}\r\n\r\ntype ServiceMap = {\r\n account: AccountService;\r\n announcements: AnnouncementsService;\r\n auth: AuthService;\r\n content: ContentService;\r\n leaderboards: LeaderboardsService;\r\n stats: StatsService;\r\n};\r\n\r\ntype ServiceKey = keyof ServiceMap;\r\n\r\nclass UnavailableRequester implements HttpRequester {\r\n constructor(private readonly error: Error) {}\r\n\r\n async request(): Promise<never> {\r\n throw this.error;\r\n }\r\n\r\n set baseUrl(_: string) {\r\n // no-op\r\n }\r\n\r\n set defaultHeaders(_: Record<string, string>) {\r\n // no-op\r\n }\r\n}\r\n\r\nclass UnavailableBeamableServices implements BeamableMicroserviceServices {\r\n private readonly requesterImpl: HttpRequester;\r\n private readonly apiBindings: BoundBeamApi;\r\n\r\n constructor(private readonly error: Error) {\r\n this.requesterImpl = new UnavailableRequester(this.error);\r\n this.apiBindings = createFailingApi(this.error);\r\n }\r\n\r\n private fail(): never {\r\n throw this.error;\r\n }\r\n\r\n get account(): AccountService {\r\n return this.fail();\r\n }\r\n\r\n get announcements(): AnnouncementsService {\r\n return this.fail();\r\n }\r\n\r\n get auth(): AuthService {\r\n return this.fail();\r\n }\r\n\r\n get content(): ContentService {\r\n return this.fail();\r\n }\r\n\r\n get leaderboards(): LeaderboardsService {\r\n return this.fail();\r\n }\r\n\r\n get stats(): StatsService {\r\n return this.fail();\r\n }\r\n\r\n get inventory(): InventoryService {\r\n return this.fail();\r\n }\r\n\r\n get storage(): StorageService {\r\n return this.fail();\r\n }\r\n\r\n get federation(): FederationRegistry {\r\n return this.fail();\r\n }\r\n\r\n get api(): BoundBeamApi {\r\n return this.apiBindings;\r\n }\r\n\r\n get requester(): HttpRequester {\r\n return this.requesterImpl;\r\n }\r\n\r\n hasScopes(..._scopes: string[]): boolean {\r\n return false;\r\n }\r\n\r\n requireScopes(...scopes: string[]): void {\r\n throw new MissingScopesError(scopes);\r\n }\r\n\r\n assumeUser(): BeamableMicroserviceServices {\r\n return this;\r\n }\r\n}\r\n\r\nclass BeamableServicesFacade implements BeamableMicroserviceServices {\r\n private readonly cache: Partial<Record<ServiceKey, ServiceMap[ServiceKey]>> = {};\r\n private readonly apiBindings: BoundBeamApi;\r\n private readonly storageService: StorageService;\r\n private readonly scopes: Set<string>;\r\n private readonly logger: Logger;\r\n private readonly serviceName?: string;\r\n private readonly federationRegistry?: FederationRegistry;\r\n private inventoryClient?: InventoryService;\r\n\r\n constructor(\r\n private readonly manager: BeamableServiceManager,\r\n private readonly beamServer: BeamServer,\r\n private readonly userId: string,\r\n scopes: Set<string>,\r\n serviceName?: string,\r\n ) {\r\n this.apiBindings = this.manager.getBoundApi();\r\n this.storageService = this.manager.getStorageService();\r\n this.scopes = scopes;\r\n this.serviceName = serviceName;\r\n this.federationRegistry = serviceName ? this.manager.getFederationRegistry(serviceName) : undefined;\r\n this.logger = this.manager.getLogger().child({ component: 'BeamableServicesFacade', service: serviceName });\r\n }\r\n\r\n private getOrCreate<K extends ServiceKey>(key: K, factory: () => ServiceMap[K]): ServiceMap[K] {\r\n if (!this.cache[key]) {\r\n this.cache[key] = factory();\r\n }\r\n return this.cache[key] as ServiceMap[K];\r\n }\r\n\r\n get account(): AccountService {\r\n return this.getOrCreate('account', () => this.beamServer.account(this.userId));\r\n }\r\n\r\n get announcements(): AnnouncementsService {\r\n return this.getOrCreate('announcements', () => this.beamServer.announcements(this.userId));\r\n }\r\n\r\n get auth(): AuthService {\r\n return this.getOrCreate('auth', () => this.beamServer.auth(this.userId));\r\n }\r\n\r\n get content(): ContentService {\r\n return this.getOrCreate('content', () => this.beamServer.content(this.userId));\r\n }\r\n\r\n get leaderboards(): LeaderboardsService {\r\n return this.getOrCreate('leaderboards', () => this.beamServer.leaderboards(this.userId));\r\n }\r\n\r\n get stats(): StatsService {\r\n return this.getOrCreate('stats', () => this.beamServer.stats(this.userId));\r\n }\r\n\r\n get inventory(): InventoryService {\r\n if (!this.inventoryClient) {\r\n this.inventoryClient = createInventoryService(\r\n this.apiBindings,\r\n this.logger.child({ component: 'InventoryClient' }),\r\n this.userId,\r\n (requiredScopes) => this.hasScopes(...requiredScopes),\r\n );\r\n }\r\n return this.inventoryClient;\r\n }\r\n\r\n get storage(): StorageService {\r\n return this.storageService;\r\n }\r\n\r\n get federation(): FederationRegistry {\r\n if (!this.federationRegistry) {\r\n throw new Error(\r\n this.serviceName\r\n ? `Federation registry is not configured for service \"${this.serviceName}\".`\r\n : 'Federation registry is not configured.',\r\n );\r\n }\r\n return this.federationRegistry;\r\n }\r\n\r\n get api(): BoundBeamApi {\r\n return this.apiBindings;\r\n }\r\n\r\n get requester(): HttpRequester {\r\n return this.manager.getRequester();\r\n }\r\n\r\n hasScopes(...requiredScopes: string[]): boolean {\r\n if (requiredScopes.length === 0) {\r\n return true;\r\n }\r\n return requiredScopes.every((scope) => this.scopeSetHas(scope));\r\n }\r\n\r\n requireScopes(...requiredScopes: string[]): void {\r\n if (!this.hasScopes(...requiredScopes)) {\r\n throw new MissingScopesError(requiredScopes);\r\n }\r\n }\r\n\r\n assumeUser(userId: string | number): BeamableMicroserviceServices {\r\n return this.manager.createFacade(String(userId), new Set(this.scopes), this.serviceName);\r\n }\r\n\r\n private scopeSetHas(scope: string): boolean {\r\n const normalized = scope.trim().toLowerCase();\r\n if (!normalized) {\r\n return false;\r\n }\r\n return this.scopes.has('*') || this.scopes.has(normalized);\r\n }\r\n}\r\n\r\nexport interface BeamableMicroserviceServices {\r\n readonly account: AccountService;\r\n readonly announcements: AnnouncementsService;\r\n readonly auth: AuthService;\r\n readonly content: ContentService;\r\n readonly leaderboards: LeaderboardsService;\r\n readonly stats: StatsService;\r\n readonly inventory: InventoryService;\r\n readonly storage: StorageService;\r\n readonly federation: FederationRegistry;\r\n readonly api: BoundBeamApi;\r\n readonly requester: HttpRequester;\r\n hasScopes(...scopes: string[]): boolean;\r\n requireScopes(...scopes: string[]): void;\r\n assumeUser(userId: string | number): BeamableMicroserviceServices;\r\n}\r\n\r\nexport class BeamableServiceManager {\r\n private readonly logger: Logger;\r\n private readonly tokenStorage: ReturnType<typeof defaultTokenStorage>;\r\n private readonly env: EnvironmentConfig;\r\n private beamServer?: BeamServer;\r\n private boundApi?: BoundBeamApi;\r\n private storageService?: StorageService;\r\n private initialized = false;\r\n private readonly federationRegistries = new Map<string, FederationRegistry>();\r\n\r\n constructor(env: EnvironmentConfig, logger: Logger) {\r\n this.env = env;\r\n this.logger = logger.child({ component: 'BeamableServiceManager' });\r\n this.tokenStorage = defaultTokenStorage({ pid: env.pid, tag: env.routingKey ?? RUNTIME_ENVIRONMENT_NAME });\r\n }\r\n\r\n async initialize(): Promise<void> {\r\n if (this.initialized) {\r\n return;\r\n }\r\n\r\n this.registerEnvironment();\r\n this.configureSharedEnvironment();\r\n\r\n if (this.env.refreshToken) {\r\n await this.tokenStorage.setTokenData({ refreshToken: this.env.refreshToken });\r\n }\r\n\r\n const useSignedRequest = Boolean(this.env.secret);\r\n if (!useSignedRequest && !this.env.refreshToken) {\r\n this.logger.warn(\r\n 'Beamable realm secret and refresh token are both missing; Beamable SDK requests may fail due to missing credentials.',\r\n );\r\n }\r\n\r\n try {\r\n this.beamServer = await BeamServer.init({\r\n cid: this.env.cid,\r\n pid: this.env.pid,\r\n environment: RUNTIME_ENVIRONMENT_NAME,\r\n useSignedRequest,\r\n tokenStorage: this.tokenStorage,\r\n serverEvents: { enabled: false },\r\n });\r\n } catch (error) {\r\n this.logger.error({ err: error }, 'Failed to initialize Beamable SDK. Services layer will be unavailable.');\r\n this.beamServer = undefined;\r\n this.initialized = false;\r\n return;\r\n }\r\n\r\n this.boundApi = await bindBeamApi(this.beamServer.requester);\r\n \r\n // Configure the requester's default headers to include the routing key in the correct format\r\n // The routing key format is: serviceName:routingKey\r\n // We'll set this per-request in createFacade since we need the service name\r\n this.storageService = new StorageService({\r\n requester: this.beamServer.requester,\r\n api: this.boundApi,\r\n env: this.env,\r\n logger: this.logger.child({ component: 'StorageService' }),\r\n });\r\n\r\n this.registerDefaultServices();\r\n this.initialized = true;\r\n this.logger.debug('Beamable SDK services initialized.');\r\n }\r\n\r\n createFacade(userId: string | number, scopes: Set<string>, serviceName?: string): BeamableMicroserviceServices {\r\n if (!this.initialized || !this.beamServer || !this.boundApi || !this.storageService) {\r\n return new UnavailableBeamableServices(new Error('Beamable services are not initialized.'));\r\n }\r\n \r\n // Set the routing key in the format serviceName:routingKey for the SDK\r\n // The SDK uses BEAM_ROUTING_KEY environment variable to construct the X-BEAM-SERVICE-ROUTING-KEY header\r\n // We need to set it to the full format: serviceName:routingKey\r\n if (serviceName && this.beamServer.requester) {\r\n const fullRoutingKey = `micro_${serviceName}:${this.env.routingKey}`;\r\n BeamServer.env.BEAM_ROUTING_KEY = fullRoutingKey;\r\n \r\n // Set default headers on the requester for all SDK requests\r\n // These headers are required for signature validation and routing\r\n const scopeHeader = `${this.env.cid}.${this.env.pid}`;\r\n this.beamServer.requester.defaultHeaders = {\r\n ...this.beamServer.requester.defaultHeaders,\r\n 'X-BEAM-SCOPE': scopeHeader,\r\n 'X-BEAM-SERVICE-ROUTING-KEY': fullRoutingKey,\r\n };\r\n }\r\n \r\n return new BeamableServicesFacade(this, this.beamServer, String(userId), new Set(scopes), serviceName);\r\n }\r\n\r\n getRequester(): HttpRequester {\r\n if (!this.initialized || !this.beamServer) {\r\n return new UnavailableRequester(new Error('Beamable services are not initialized.'));\r\n }\r\n return this.beamServer.requester;\r\n }\r\n\r\n getBoundApi(): BoundBeamApi {\r\n if (!this.boundApi) {\r\n throw new Error('Beamable bound API is not available.');\r\n }\r\n return this.boundApi;\r\n }\r\n\r\n getStorageService(): StorageService {\r\n if (!this.storageService) {\r\n throw new Error('Storage service is not initialized.');\r\n }\r\n return this.storageService;\r\n }\r\n\r\n getLogger(): Logger {\r\n return this.logger;\r\n }\r\n\r\n registerFederationRegistry(serviceName: string, registry: FederationRegistry): void {\r\n this.federationRegistries.set(serviceName, registry);\r\n }\r\n\r\n getFederationRegistry(serviceName: string): FederationRegistry | undefined {\r\n return this.federationRegistries.get(serviceName);\r\n }\r\n\r\n private registerEnvironment(): void {\r\n const apiUrl = hostToHttpUrl(this.env.host);\r\n const portalUrl = hostToPortalUrl(apiUrl);\r\n const storageUrl = hostToStorageUrl(apiUrl);\r\n const registryUrl = hostToMicroserviceRegistryUrl(apiUrl);\r\n\r\n try {\r\n BeamEnvironment.register(RUNTIME_ENVIRONMENT_NAME, {\r\n apiUrl,\r\n portalUrl,\r\n beamMongoExpressUrl: storageUrl,\r\n dockerRegistryUrl: `${registryUrl}/v2/`,\r\n });\r\n } catch (error) {\r\n this.logger.debug({ err: error }, 'Beamable environment was already registered. Reusing existing configuration.');\r\n }\r\n }\r\n\r\n private configureSharedEnvironment(): void {\r\n if (this.env.secret) {\r\n BeamServer.env.BEAM_REALM_SECRET = this.env.secret;\r\n }\r\n // BEAM_ROUTING_KEY is used by the SDK to construct the X-BEAM-SERVICE-ROUTING-KEY header\r\n // We set it to just the routing key value here, and will set the full format in createFacade\r\n // BEAM_ROUTING_KEY is used by the SDK to construct the X-BEAM-SERVICE-ROUTING-KEY header\r\n // For deployed services, routingKey is undefined, so we set it to empty string\r\n // The SDK will handle this appropriately\r\n BeamServer.env.BEAM_ROUTING_KEY = this.env.routingKey ?? '';\r\n }\r\n\r\n private registerDefaultServices(): void {\r\n if (!this.beamServer) {\r\n return;\r\n }\r\n this.beamServer.use(AccountService);\r\n this.beamServer.use(AnnouncementsService);\r\n this.beamServer.use(AuthService);\r\n this.beamServer.use(ContentService);\r\n this.beamServer.use(LeaderboardsService);\r\n this.beamServer.use(StatsService);\r\n }\r\n}\r\n"]}
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StorageService = void 0;
4
+ exports.StorageObject = StorageObject;
5
+ exports.getStorageMetadata = getStorageMetadata;
6
+ exports.listRegisteredStorageObjects = listRegisteredStorageObjects;
7
+ const mongodb_1 = require("mongodb");
8
+ const STORAGE_OBJECT_METADATA = new Map();
9
+ function StorageObject(storageName) {
10
+ if (!storageName || !storageName.trim()) {
11
+ throw new Error('@StorageObject requires a non-empty storage name.');
12
+ }
13
+ return (target) => {
14
+ STORAGE_OBJECT_METADATA.set(target, { storageName: storageName.trim() });
15
+ };
16
+ }
17
+ function getStorageMetadata(target) {
18
+ return STORAGE_OBJECT_METADATA.get(target);
19
+ }
20
+ function listRegisteredStorageObjects() {
21
+ return Array.from(STORAGE_OBJECT_METADATA.values());
22
+ }
23
+ const CONNECTION_STRING_ENV_PREFIX = 'STORAGE_CONNSTR_';
24
+ class StorageService {
25
+ constructor(dependencies) {
26
+ this.databaseCache = new Map();
27
+ this.clientCache = new Map();
28
+ this.requester = dependencies.requester;
29
+ this.api = dependencies.api;
30
+ this.env = dependencies.env;
31
+ this.logger = dependencies.logger.child({ component: 'StorageService' });
32
+ }
33
+ async getDatabase(storageName, options = {}) {
34
+ const normalized = this.normalizeStorageName(storageName);
35
+ if (!options.useCache) {
36
+ this.databaseCache.delete(normalized);
37
+ }
38
+ const cached = this.databaseCache.get(normalized);
39
+ if (cached) {
40
+ return cached;
41
+ }
42
+ const connectionString = await this.getConnectionString(normalized);
43
+ const client = await this.getMongoClient(connectionString);
44
+ const databaseName = this.buildDatabaseName(normalized);
45
+ const database = client.db(databaseName);
46
+ this.databaseCache.set(normalized, database);
47
+ return database;
48
+ }
49
+ async getDatabaseFor(storageCtor, options = {}) {
50
+ const metadata = getStorageMetadata(storageCtor);
51
+ if (!metadata) {
52
+ throw new Error(`Storage metadata for ${storageCtor.name} not found. Did you decorate the class with @StorageObject('Name')?`);
53
+ }
54
+ return this.getDatabase(metadata.storageName, options);
55
+ }
56
+ async getCollection(storageName, options = {}) {
57
+ var _a;
58
+ const database = await this.getDatabase(storageName, options);
59
+ const collectionName = (_a = options.collectionName) === null || _a === void 0 ? void 0 : _a.trim();
60
+ if (!collectionName) {
61
+ throw new Error('Collection name must be provided when using getCollection with raw storage name.');
62
+ }
63
+ return database.collection(collectionName);
64
+ }
65
+ async getCollectionFor(storageCtor, collectionCtor, options = {}) {
66
+ var _a, _b;
67
+ const metadata = getStorageMetadata(storageCtor);
68
+ if (!metadata) {
69
+ throw new Error(`Storage metadata for ${storageCtor.name} not found. Did you decorate the class with @StorageObject('Name')?`);
70
+ }
71
+ const collectionName = (_b = (_a = options.collectionName) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : collectionCtor.name;
72
+ const database = await this.getDatabase(metadata.storageName, options);
73
+ return database.collection(collectionName);
74
+ }
75
+ async getMongoClient(connectionString) {
76
+ if (this.clientCache.has(connectionString)) {
77
+ return this.clientCache.get(connectionString);
78
+ }
79
+ const client = new mongodb_1.MongoClient(connectionString, {
80
+ maxPoolSize: 20,
81
+ });
82
+ await client.connect();
83
+ this.clientCache.set(connectionString, client);
84
+ return client;
85
+ }
86
+ async getConnectionString(storageName) {
87
+ const variableName = `${CONNECTION_STRING_ENV_PREFIX}${storageName}`;
88
+ const envValue = process.env[variableName];
89
+ if (envValue && envValue.trim()) {
90
+ return envValue.trim();
91
+ }
92
+ if (this.cachedConnectionString) {
93
+ return this.cachedConnectionString;
94
+ }
95
+ const response = await this.fetchConnectionString();
96
+ if (!response.connectionString || !response.connectionString.trim()) {
97
+ throw new Error(`Connection string for storage "${storageName}" is empty.`);
98
+ }
99
+ this.cachedConnectionString = response.connectionString.trim();
100
+ return this.cachedConnectionString;
101
+ }
102
+ async fetchConnectionString() {
103
+ if (typeof this.api.beamoGetStorageConnectionBasic === 'function') {
104
+ const result = await this.api.beamoGetStorageConnectionBasic();
105
+ if (result && typeof result === 'object' && 'body' in result) {
106
+ return result.body;
107
+ }
108
+ return result;
109
+ }
110
+ this.logger.warn('beamable-sdk does not expose beamoGetStorageConnectionBasic; falling back to manual requester call.');
111
+ const response = await this.requester.request({
112
+ method: 'GET',
113
+ url: '/basic/beamo/storage/connection',
114
+ withAuth: true,
115
+ });
116
+ const body = response.body;
117
+ if (!body || typeof body.connectionString !== 'string') {
118
+ throw new Error('Failed to retrieve Beamable storage connection string.');
119
+ }
120
+ return body;
121
+ }
122
+ buildDatabaseName(storageName) {
123
+ const cid = this.sanitize(this.env.cid);
124
+ const pid = this.sanitize(this.env.pid);
125
+ const storage = this.sanitize(storageName);
126
+ return `${cid}${pid}_${storage}`;
127
+ }
128
+ sanitize(value) {
129
+ return value.replace(/[^A-Za-z0-9_]/g, '_');
130
+ }
131
+ normalizeStorageName(storageName) {
132
+ const normalized = storageName.trim();
133
+ if (!normalized) {
134
+ throw new Error('Storage name cannot be empty.');
135
+ }
136
+ return normalized;
137
+ }
138
+ async dispose() {
139
+ for (const client of this.clientCache.values()) {
140
+ await client.close();
141
+ }
142
+ this.clientCache.clear();
143
+ this.databaseCache.clear();
144
+ this.cachedConnectionString = undefined;
145
+ }
146
+ }
147
+ exports.StorageService = StorageService;
@@ -0,0 +1,46 @@
1
+ import type { Logger } from 'pino';
2
+ import { type Db, type Collection, type Document } from 'mongodb';
3
+ import type { BoundBeamApi } from './services.js';
4
+ import type { EnvironmentConfig } from './types.js';
5
+ import type { HttpRequester } from 'beamable-sdk';
6
+ export interface StorageConnectionOptions {
7
+ useCache?: boolean;
8
+ }
9
+ export interface StorageCollectionOptions extends StorageConnectionOptions {
10
+ collectionName?: string;
11
+ }
12
+ export interface StorageMetadata {
13
+ storageName: string;
14
+ }
15
+ export declare function StorageObject(storageName: string): ClassDecorator;
16
+ export declare function getStorageMetadata(target: Function): StorageMetadata | undefined;
17
+ export declare function listRegisteredStorageObjects(): StorageMetadata[];
18
+ interface StorageServiceDependencies {
19
+ requester: HttpRequester;
20
+ api: BoundBeamApi;
21
+ env: EnvironmentConfig;
22
+ logger: Logger;
23
+ }
24
+ export declare class StorageService {
25
+ private readonly requester;
26
+ private readonly api;
27
+ private readonly env;
28
+ private readonly logger;
29
+ private readonly databaseCache;
30
+ private readonly clientCache;
31
+ private cachedConnectionString?;
32
+ constructor(dependencies: StorageServiceDependencies);
33
+ getDatabase(storageName: string, options?: StorageConnectionOptions): Promise<Db>;
34
+ getDatabaseFor<T>(storageCtor: new () => T, options?: StorageConnectionOptions): Promise<Db>;
35
+ getCollection<TDocument extends Document>(storageName: string, options?: StorageCollectionOptions): Promise<Collection<TDocument>>;
36
+ getCollectionFor<TStorage, TDocument extends Document>(storageCtor: new () => TStorage, collectionCtor: new () => TDocument, options?: StorageCollectionOptions): Promise<Collection<TDocument>>;
37
+ private getMongoClient;
38
+ private getConnectionString;
39
+ private fetchConnectionString;
40
+ private buildDatabaseName;
41
+ private sanitize;
42
+ private normalizeStorageName;
43
+ dispose(): Promise<void>;
44
+ }
45
+ export {};
46
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAe,KAAK,EAAE,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,wBAAyB,SAAQ,wBAAwB;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;CACrB;AAID,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,CAOjE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,QAAQ,GAAG,eAAe,GAAG,SAAS,CAEhF;AAED,wBAAgB,4BAA4B,IAAI,eAAe,EAAE,CAEhE;AAED,UAAU,0BAA0B;IAClC,SAAS,EAAE,aAAa,CAAC;IACzB,GAAG,EAAE,YAAY,CAAC;IAClB,GAAG,EAAE,iBAAiB,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAQD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;IAC1C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAyB;IACvD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkC;IAC9D,OAAO,CAAC,sBAAsB,CAAC,CAAS;gBAE5B,YAAY,EAAE,0BAA0B;IAO9C,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,EAAE,CAAC;IAkBrF,cAAc,CAAC,CAAC,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,EAAE,CAAC;IAUhG,aAAa,CAAC,SAAS,SAAS,QAAQ,EAC5C,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IAS3B,gBAAgB,CAAC,QAAQ,EAAE,SAAS,SAAS,QAAQ,EACzD,WAAW,EAAE,UAAU,QAAQ,EAC/B,cAAc,EAAE,UAAU,SAAS,EACnC,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YAYnB,cAAc;YAYd,mBAAmB;YAmBnB,qBAAqB;IAwBnC,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,oBAAoB;IAQtB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ/B"}