@contember/engine-server 1.2.0-alpha.9 → 1.2.0-beta.2

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 (73) hide show
  1. package/dist/src/MasterContainer.d.ts +6 -6
  2. package/dist/src/MasterContainer.d.ts.map +1 -1
  3. package/dist/src/MasterContainer.js +10 -13
  4. package/dist/src/MasterContainer.js.map +1 -1
  5. package/dist/src/bootstrap/Initializer.d.ts.map +1 -1
  6. package/dist/src/bootstrap/Initializer.js +3 -15
  7. package/dist/src/bootstrap/Initializer.js.map +1 -1
  8. package/dist/src/config/configSchema.d.ts +81 -0
  9. package/dist/src/config/configSchema.d.ts.map +1 -1
  10. package/dist/src/config/configSchema.js +16 -2
  11. package/dist/src/config/configSchema.js.map +1 -1
  12. package/dist/src/config/configTemplate.d.ts.map +1 -1
  13. package/dist/src/config/configTemplate.js +29 -24
  14. package/dist/src/config/configTemplate.js.map +1 -1
  15. package/dist/src/project/ProjectContainer.d.ts +8 -2
  16. package/dist/src/project/ProjectContainer.d.ts.map +1 -1
  17. package/dist/src/project/ProjectContainer.js +20 -5
  18. package/dist/src/project/ProjectContainer.js.map +1 -1
  19. package/dist/src/project/ProjectContainerResolver.d.ts +2 -3
  20. package/dist/src/project/ProjectContainerResolver.d.ts.map +1 -1
  21. package/dist/src/project/ProjectContainerResolver.js +3 -4
  22. package/dist/src/project/ProjectContainerResolver.js.map +1 -1
  23. package/dist/src/project/ProjectInitializer.d.ts +3 -2
  24. package/dist/src/project/ProjectInitializer.d.ts.map +1 -1
  25. package/dist/src/project/ProjectInitializer.js +3 -3
  26. package/dist/src/project/ProjectInitializer.js.map +1 -1
  27. package/dist/src/project/ProjectSchemaResolver.d.ts +2 -7
  28. package/dist/src/project/ProjectSchemaResolver.d.ts.map +1 -1
  29. package/dist/src/project/ProjectSchemaResolver.js +2 -16
  30. package/dist/src/project/ProjectSchemaResolver.js.map +1 -1
  31. package/dist/src/projectGroup/ProjectGroupContainer.d.ts +3 -1
  32. package/dist/src/projectGroup/ProjectGroupContainer.d.ts.map +1 -1
  33. package/dist/src/projectGroup/ProjectGroupContainer.js +10 -8
  34. package/dist/src/projectGroup/ProjectGroupContainer.js.map +1 -1
  35. package/dist/src/start.js +16 -13
  36. package/dist/src/start.js.map +1 -1
  37. package/dist/src/tsconfig.tsbuildinfo +1 -1
  38. package/dist/src/utils/sentry.d.ts +8 -9
  39. package/dist/src/utils/sentry.d.ts.map +1 -1
  40. package/dist/src/utils/sentry.js +44 -29
  41. package/dist/src/utils/sentry.js.map +1 -1
  42. package/dist/src/utils/serverStartup.d.ts +3 -1
  43. package/dist/src/utils/serverStartup.d.ts.map +1 -1
  44. package/dist/src/utils/serverStartup.js +49 -12
  45. package/dist/src/utils/serverStartup.js.map +1 -1
  46. package/dist/src/utils/serverTermination.d.ts +2 -1
  47. package/dist/src/utils/serverTermination.d.ts.map +1 -1
  48. package/dist/src/utils/serverTermination.js +4 -6
  49. package/dist/src/utils/serverTermination.js.map +1 -1
  50. package/dist/tests/cases/configResolver.test.d.ts +2 -0
  51. package/dist/tests/cases/configResolver.test.d.ts.map +1 -0
  52. package/dist/tests/cases/configResolver.test.js +67 -0
  53. package/dist/tests/cases/configResolver.test.js.map +1 -0
  54. package/dist/tests/src/tester.js +2 -2
  55. package/dist/tests/src/tester.js.map +1 -1
  56. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  57. package/package.json +18 -21
  58. package/src/MasterContainer.ts +17 -15
  59. package/src/bootstrap/Initializer.ts +3 -16
  60. package/src/config/configSchema.ts +44 -21
  61. package/src/config/configTemplate.ts +29 -24
  62. package/src/project/ProjectContainer.ts +23 -4
  63. package/src/project/ProjectContainerResolver.ts +4 -4
  64. package/src/project/ProjectInitializer.ts +4 -3
  65. package/src/project/ProjectSchemaResolver.ts +1 -18
  66. package/src/projectGroup/ProjectGroupContainer.ts +12 -7
  67. package/src/start.ts +24 -17
  68. package/src/tsconfig.json +6 -15
  69. package/src/utils/sentry.ts +45 -35
  70. package/src/utils/serverStartup.ts +46 -10
  71. package/src/utils/serverTermination.ts +5 -6
  72. package/tests/cases/configResolver.test.ts +67 -0
  73. package/tests/src/tester.ts +1 -1
package/package.json CHANGED
@@ -1,31 +1,29 @@
1
1
  {
2
2
  "name": "@contember/engine-server",
3
- "version": "1.2.0-alpha.9",
3
+ "version": "1.2.0-beta.2",
4
4
  "license": "Apache-2.0",
5
5
  "main": "dist/src/index.js",
6
6
  "typings": "dist/src/index.d.ts",
7
7
  "scripts": {
8
+ "test": "vitest tests/cases",
8
9
  "test-e2e": "vitest --no-threads tests/e2e"
9
10
  },
10
11
  "dependencies": {
11
- "@contember/authorization": "^1.2.0-alpha.9",
12
- "@contember/config-loader": "^1.2.0-alpha.9",
13
- "@contember/database": "^1.2.0-alpha.9",
14
- "@contember/database-migrations": "^1.2.0-alpha.9",
15
- "@contember/dic": "^1.2.0-alpha.9",
16
- "@contember/typesafe": "^1.2.0-alpha.9",
17
- "@contember/engine-content-api": "^1.2.0-alpha.9",
18
- "@contember/engine-http": "^1.2.0-alpha.9",
19
- "@contember/engine-plugins": "^1.2.0-alpha.9",
20
- "@contember/engine-s3-plugin": "^1.2.0-alpha.9",
21
- "@contember/engine-system-api": "^1.2.0-alpha.9",
22
- "@contember/engine-tenant-api": "^1.2.0-alpha.9",
23
- "@contember/engine-vimeo-plugin": "^1.2.0-alpha.9",
24
- "@contember/queryable": "^1.2.0-alpha.9",
25
- "@contember/schema": "^1.2.0-alpha.9",
26
- "@contember/schema-definition": "^1.2.0-alpha.9",
27
- "@contember/schema-migrations": "^1.2.0-alpha.9",
28
- "@contember/schema-utils": "^1.2.0-alpha.9",
12
+ "@contember/config-loader": "^1.2.0-beta.2",
13
+ "@contember/database": "^1.2.0-beta.2",
14
+ "@contember/dic": "^1.2.0-beta.2",
15
+ "@contember/typesafe": "^1.2.0-beta.2",
16
+ "@contember/engine-content-api": "^1.2.0-beta.2",
17
+ "@contember/engine-common": "^1.2.0-beta.2",
18
+ "@contember/engine-http": "^1.2.0-beta.2",
19
+ "@contember/engine-plugins": "^1.2.0-beta.2",
20
+ "@contember/engine-s3-plugin": "^1.2.0-beta.2",
21
+ "@contember/engine-system-api": "^1.2.0-beta.2",
22
+ "@contember/engine-tenant-api": "^1.2.0-beta.2",
23
+ "@contember/engine-vimeo-plugin": "^1.2.0-beta.2",
24
+ "@contember/logger": "^1.2.0-beta.2",
25
+ "@contember/schema": "^1.2.0-beta.2",
26
+ "@contember/schema-migrations": "^1.2.0-beta.2",
29
27
  "@koa/cors": "^3.1.0",
30
28
  "@sentry/node": "^7.1.1",
31
29
  "graphql": "^16.5.0",
@@ -33,11 +31,10 @@
33
31
  "koa-bodyparser": "^4.3.0",
34
32
  "koa-compress": "^5.0.1",
35
33
  "pg": "^8.5.0",
36
- "prom-client": "^12",
37
34
  "uuid": "^8.3.1"
38
35
  },
39
36
  "devDependencies": {
40
- "@contember/engine-api-tester": "^1.2.0-alpha.9",
37
+ "@contember/engine-api-tester": "^1.2.0-beta.2",
41
38
  "@types/koa-compress": "^4.0.1",
42
39
  "@types/node": "^18",
43
40
  "@types/supertest": "^2.0.8",
@@ -2,7 +2,6 @@ import { SystemContainerFactory } from '@contember/engine-system-api'
2
2
  import { TenantContainerFactory } from '@contember/engine-tenant-api'
3
3
  import { Builder } from '@contember/dic'
4
4
  import { ServerConfig } from './config/config'
5
- import { logSentryError } from './utils'
6
5
  import { ModificationHandlerFactory } from '@contember/schema-migrations'
7
6
  import { Initializer } from './bootstrap'
8
7
  import { Plugin } from '@contember/engine-plugins'
@@ -13,6 +12,7 @@ import {
13
12
  ContentQueryHandlerFactory,
14
13
  ContentSchemaTransferMappingFactory,
15
14
  createHomepageMiddleware,
15
+ createLoggerMiddleware,
16
16
  createModuleInfoMiddleware,
17
17
  createPlaygroundMiddleware,
18
18
  createPoweredByHeaderMiddleware,
@@ -25,6 +25,7 @@ import {
25
25
  ImportExecutor,
26
26
  Koa,
27
27
  NotModifiedChecker,
28
+ ProjectGroupResolver as ProjectGroupResolverInterface,
28
29
  Providers,
29
30
  route,
30
31
  SystemApiMiddlewareFactory,
@@ -43,8 +44,7 @@ import { TenantConfigResolver } from './config/tenantConfigResolver'
43
44
  import { ProjectGroupContainerFactory } from './projectGroup/ProjectGroupContainer'
44
45
  import corsMiddleware from '@koa/cors'
45
46
  import { ProjectGroupResolver } from './projectGroup/ProjectGroupResolver'
46
- import { ProjectGroupResolver as ProjectGroupResolverInterface } from '@contember/engine-http'
47
- import { Logger } from '@contember/engine-common'
47
+ import { Logger } from '@contember/logger'
48
48
 
49
49
  export interface MasterContainer {
50
50
  initializer: Initializer
@@ -58,6 +58,7 @@ export interface MasterContainerArgs {
58
58
  projectConfigResolver: ProjectConfigResolver
59
59
  tenantConfigResolver: TenantConfigResolver
60
60
  plugins: Plugin[]
61
+ logger: Logger
61
62
  version?: string
62
63
  }
63
64
 
@@ -69,6 +70,7 @@ export class MasterContainerFactory {
69
70
  projectConfigResolver,
70
71
  tenantConfigResolver,
71
72
  version,
73
+ logger,
72
74
  }: MasterContainerArgs) {
73
75
  return new Builder({})
74
76
  .addService('serverConfig', () =>
@@ -94,11 +96,13 @@ export class MasterContainerFactory {
94
96
  .addService('projectContainerFactoryFactory', ({ debugMode, plugins, providers }) =>
95
97
  new ProjectContainerFactoryFactory(debugMode, plugins, providers))
96
98
  .addService('tenantGraphQLHandlerFactory', () =>
97
- new TenantGraphQLHandlerFactory(logSentryError))
99
+ new TenantGraphQLHandlerFactory())
98
100
  .addService('systemGraphQLHandlerFactory', ({ debugMode }) =>
99
- new SystemGraphQLHandlerFactory(logSentryError, debugMode))
100
- .addService('projectGroupContainerFactory', ({ debugMode, providers, systemContainerFactory, tenantContainerFactory, projectContainerFactoryFactory, projectConfigResolver, tenantGraphQLHandlerFactory, systemGraphQLHandlerFactory }) =>
101
- new ProjectGroupContainerFactory(debugMode, providers, systemContainerFactory, tenantContainerFactory, projectContainerFactoryFactory, projectConfigResolver, tenantGraphQLHandlerFactory, systemGraphQLHandlerFactory))
101
+ new SystemGraphQLHandlerFactory(debugMode))
102
+ .addService('logger', () =>
103
+ logger)
104
+ .addService('projectGroupContainerFactory', ({ debugMode, providers, systemContainerFactory, tenantContainerFactory, projectContainerFactoryFactory, projectConfigResolver, tenantGraphQLHandlerFactory, systemGraphQLHandlerFactory, logger }) =>
105
+ new ProjectGroupContainerFactory(debugMode, providers, systemContainerFactory, tenantContainerFactory, projectContainerFactoryFactory, projectConfigResolver, tenantGraphQLHandlerFactory, systemGraphQLHandlerFactory, logger))
102
106
  .addService('projectGroupContainer', ({ tenantConfigResolver, projectGroupContainerFactory }) =>
103
107
  projectGroupContainerFactory.create({ slug: undefined, config: tenantConfigResolver(undefined, {}) }))
104
108
  .addService('httpErrorMiddlewareFactory', ({ debugMode }) =>
@@ -110,7 +114,7 @@ export class MasterContainerFactory {
110
114
  .addService('contentGraphqlContextFactory', ({ providers }) =>
111
115
  new ContentGraphQLContextFactory(providers))
112
116
  .addService('contentQueryHandlerFactory', ({ debugMode }) =>
113
- new ContentQueryHandlerFactory(debugMode, logSentryError))
117
+ new ContentQueryHandlerFactory(debugMode))
114
118
  .addService('contentApiMiddlewareFactory', ({ projectGroupResolver, notModifiedChecker, contentGraphqlContextFactory, contentQueryHandlerFactory }) =>
115
119
  new ContentApiMiddlewareFactory(projectGroupResolver, notModifiedChecker, contentGraphqlContextFactory, contentQueryHandlerFactory))
116
120
  .addService('tenantGraphQLContextFactory', () =>
@@ -121,22 +125,19 @@ export class MasterContainerFactory {
121
125
  new SystemGraphQLContextFactory())
122
126
  .addService('systemApiMiddlewareFactory', ({ debugMode, projectGroupResolver, systemGraphQLContextFactory }) =>
123
127
  new SystemApiMiddlewareFactory(debugMode, projectGroupResolver, systemGraphQLContextFactory))
124
- .addService('logger', () =>
125
- // eslint-disable-next-line no-console
126
- new Logger(console.log))
127
128
  .addService('contentSchemaTransferMappingFactory', () =>
128
129
  new ContentSchemaTransferMappingFactory())
129
130
  .addService('systemSchemaTransferMappingFactory', () =>
130
131
  new SystemSchemaTransferMappingFactory())
131
- .addService('importExecutor', ({ contentSchemaTransferMappingFactory, systemSchemaTransferMappingFactory, logger }) =>
132
- new ImportExecutor(contentSchemaTransferMappingFactory, systemSchemaTransferMappingFactory, logger))
132
+ .addService('importExecutor', ({ contentSchemaTransferMappingFactory, systemSchemaTransferMappingFactory }) =>
133
+ new ImportExecutor(contentSchemaTransferMappingFactory, systemSchemaTransferMappingFactory))
133
134
  .addService('exportExecutor', ({ contentSchemaTransferMappingFactory, systemSchemaTransferMappingFactory }) =>
134
135
  new ExportExecutor(contentSchemaTransferMappingFactory, systemSchemaTransferMappingFactory))
135
136
  .addService('importApiMiddlewareFactory', ({ projectGroupResolver, importExecutor }) =>
136
137
  new ImportApiMiddlewareFactory(projectGroupResolver, importExecutor))
137
138
  .addService('exportApiMiddlewareFactory', ({ projectGroupResolver, exportExecutor }) =>
138
139
  new ExportApiMiddlewareFactory(projectGroupResolver, exportExecutor))
139
- .addService('koaMiddlewares', ({ contentApiMiddlewareFactory, tenantApiMiddlewareFactory, systemApiMiddlewareFactory, importApiMiddlewareFactory, exportApiMiddlewareFactory, httpErrorMiddlewareFactory, debugMode, version, serverConfig }) =>
140
+ .addService('koaMiddlewares', ({ contentApiMiddlewareFactory, tenantApiMiddlewareFactory, systemApiMiddlewareFactory, importApiMiddlewareFactory, exportApiMiddlewareFactory, httpErrorMiddlewareFactory, debugMode, version, serverConfig, logger }) =>
140
141
  compose([
141
142
  koaCompress({
142
143
  br: false,
@@ -145,7 +146,8 @@ export class MasterContainerFactory {
145
146
  jsonLimit: serverConfig.http.requestBodySize || '1mb',
146
147
  }),
147
148
  createPoweredByHeaderMiddleware(debugMode, version ?? 'unknown'),
148
- createTimerMiddleware(),
149
+ createLoggerMiddleware(logger),
150
+ createTimerMiddleware({ debugMode }),
149
151
  httpErrorMiddlewareFactory.create(),
150
152
  route('/playground$', createPlaygroundMiddleware()),
151
153
  createHomepageMiddleware(),
@@ -1,4 +1,3 @@
1
- import { Logger } from '@contember/engine-common'
2
1
  import { ProjectGroupContainer } from '@contember/engine-http'
3
2
 
4
3
  export class Initializer {
@@ -7,34 +6,22 @@ export class Initializer {
7
6
  ) {}
8
7
 
9
8
  public async initialize(): Promise<string[]> {
10
- // eslint-disable-next-line no-console
11
- const logger = new Logger(console.log)
12
- logger.group('\nInitializing tenant database')
13
- // todo
14
9
  const groupContainer = await this.projectGroupContainer
15
-
10
+ const tenantMigrationsLogger = groupContainer.logger.child()
16
11
  const tenantContainer = groupContainer.tenantContainer
17
- await tenantContainer.migrationsRunner.run(logger.write.bind(logger))
18
- logger.groupEnd()
12
+ await tenantContainer.migrationsRunner.run(tenantMigrationsLogger)
19
13
 
20
14
  const projects: string[] = []
21
15
 
22
16
  const tenantProjects = await tenantContainer.projectManager.getProjects(tenantContainer.databaseContext)
23
17
  for (const { slug: projectSlug } of tenantProjects) {
24
- logger.group(`\nUpdating project ${projectSlug}`)
25
- const projectContainer = await groupContainer.projectContainerResolver.getProjectContainer(projectSlug, {
26
- alias: false,
27
- logger,
28
- })
18
+ const projectContainer = await groupContainer.projectContainerResolver.getProjectContainer(projectSlug, { alias: false })
29
19
  if (!projectContainer) {
30
20
  throw new Error()
31
21
  }
32
22
  const project = projectContainer.project
33
23
  projects.push(project.slug)
34
- logger.groupEnd()
35
24
  }
36
- // eslint-disable-next-line no-console
37
- console.log('')
38
25
  return projects
39
26
  }
40
27
  }
@@ -3,29 +3,52 @@ import { MailerOptions } from '@contember/engine-tenant-api'
3
3
  import { upperCaseFirst } from '../utils'
4
4
 
5
5
 
6
- export const dbConfigSchema = Typesafe.intersection(
7
- Typesafe.object({
8
- host: Typesafe.string,
9
- port: Typesafe.number,
10
- user: Typesafe.string,
11
- password: Typesafe.string,
12
- database: Typesafe.string,
6
+ const dbConfigRequired = {
7
+ host: Typesafe.string,
8
+ port: Typesafe.number,
9
+ user: Typesafe.string,
10
+ password: Typesafe.string,
11
+ database: Typesafe.string,
12
+ }
13
+ const dbConfigOptional = {
14
+ ssl: Typesafe.boolean,
15
+ queryTimeoutMs: Typesafe.number,
16
+ statementTimeoutMs: Typesafe.number,
17
+ connectionTimeoutMs: Typesafe.number,
18
+ pool: Typesafe.partial({
19
+ maxConnections: Typesafe.number,
20
+ maxConnecting: Typesafe.number,
21
+ maxIdle: Typesafe.number,
22
+ reconnectIntervalMs: Typesafe.number,
23
+ rateLimitCount: Typesafe.number,
24
+ rateLimitPeriodMs: Typesafe.number,
25
+ idleTimeoutMs: Typesafe.number,
26
+ acquireTimeoutMs: Typesafe.number,
27
+ maxUses: Typesafe.number,
28
+ maxAgeMs: Typesafe.number,
13
29
  }),
30
+ }
31
+
32
+ const dbConfigSchemaInner = Typesafe.intersection(
33
+ Typesafe.object(dbConfigRequired),
34
+ Typesafe.partial(dbConfigOptional),
35
+ )
36
+
37
+ const readDbSchema = Typesafe.intersection(
38
+ Typesafe.partial(dbConfigRequired),
39
+ Typesafe.partial(dbConfigOptional),
40
+ )
41
+
42
+ export const dbConfigSchema = Typesafe.intersection(
43
+ dbConfigSchemaInner,
14
44
  Typesafe.partial({
15
- ssl: Typesafe.boolean,
16
- queryTimeoutMs: Typesafe.number,
17
- statementTimeoutMs: Typesafe.number,
18
- connectionTimeoutMs: Typesafe.number,
19
- pool: Typesafe.partial({
20
- maxConnections: Typesafe.number,
21
- maxConnecting: Typesafe.number,
22
- maxIdle: Typesafe.number,
23
- reconnectIntervalMs: Typesafe.number,
24
- idleTimeoutMs: Typesafe.number,
25
- acquireTimeoutMs: Typesafe.number,
26
- maxUses: Typesafe.number,
27
- maxAgeMs: Typesafe.number,
28
- }),
45
+ read: (val: unknown) => {
46
+ const readDb = readDbSchema(val)
47
+ if ('host' in readDb) {
48
+ return readDb
49
+ }
50
+ return undefined
51
+ },
29
52
  }),
30
53
  )
31
54
 
@@ -1,3 +1,23 @@
1
+ const createDbConfigTemplate = (prefix: string) => {
2
+ return {
3
+ ssl: `%?${prefix}_SSL::bool%`,
4
+ queryTimeoutMs: `%?${prefix}_QUERY_TIMEOUT_MS::number%`,
5
+ statementTimeoutMs: `%?${prefix}_STATEMENT_TIMEOUT_MS::number%`,
6
+ connectionTimeoutMs: `%?${prefix}_CONNECTION_TIMEOUT_MS::number%`,
7
+ pool: {
8
+ maxConnections: `%?${prefix}_POOL_MAX_CONNECTIONS::number%`,
9
+ maxConnecting: `%?${prefix}_POOL_MAX_CONNECTING::number%`,
10
+ maxIdle: `%?${prefix}_POOL_MAX_IDLE::number%`,
11
+ reconnectIntervalMs: `%?${prefix}_POOL_RECONNECT_INTERVAL_MS::number%`,
12
+ idleTimeoutMs: `%?${prefix}_POOL_IDLE_TIMEOUT_MS::number%`,
13
+ acquireTimeoutMs: `%?${prefix}_POOL_ACQUIRE_TIMEOUT_MS::number%`,
14
+ maxUses: `%?${prefix}_POOL_MAX_USES::number%`,
15
+ maxAgeMs: `%?${prefix}_POOL_MAX_AGE_MS::number%`,
16
+ rateLimitCount: `%?${prefix}_POOL_RATE_LIMIT_COUNT::number%`,
17
+ rateLimitPeriodMs: `%?${prefix}_POOL_RATE_LIMIT_PERIOD_MS::number%`,
18
+ },
19
+ }
20
+ }
1
21
  export const configTemplate: any = {
2
22
  tenant: {
3
23
  db: {
@@ -6,20 +26,7 @@ export const configTemplate: any = {
6
26
  user: `%tenant.env.DB_USER%`,
7
27
  password: `%tenant.env.DB_PASSWORD%`,
8
28
  database: `%tenant.env.DB_NAME%`,
9
- ssl: `%?tenant.env.DB_SSL::bool%`,
10
- queryTimeoutMs: '%?tenant.env.DB_QUERY_TIMEOUT_MS::number%',
11
- statementTimeoutMs: '%?tenant.env.DB_STATEMENT_TIMEOUT_MS::number%',
12
- connectionTimeoutMs: '%?tenant.env.DB_CONNECTION_TIMEOUT_MS::number%',
13
- pool: {
14
- maxConnections: '%?tenant.env.DB_POOL_MAX_CONNECTIONS::number%',
15
- maxConnecting: '%?tenant.env.DB_POOL_MAX_CONNECTING::number%',
16
- maxIdle: '%?tenant.env.DB_POOL_MAX_IDLE::number%',
17
- reconnectIntervalMs: '%?tenant.env.DB_POOL_RECONNECT_INTERVAL_MS::number%',
18
- idleTimeoutMs: '%?tenant.env.DB_POOL_IDLE_TIMEOUT_MS::number%',
19
- acquireTimeoutMs: '%?tenant.env.DB_POOL_ACQUIRE_TIMEOUT_MS::number%',
20
- maxUses: '%?tenant.env.DB_POOL_MAX_USES::number%',
21
- maxAgeMs: '%?tenant.env.DB_POOL_MAX_AGE_MS::number%',
22
- },
29
+ ...createDbConfigTemplate('tenant.env.DB'),
23
30
  },
24
31
  mailer: {
25
32
  from: '%?tenant.env.MAILER_FROM%',
@@ -47,16 +54,14 @@ export const configTemplate: any = {
47
54
  user: `%?project.env.DB_USER%`,
48
55
  password: `%?project.secret.db.password||project.env.DB_PASSWORD%`,
49
56
  database: `%?project.env.DB_NAME||project.slug%`,
50
- ssl: `%?project.env.DB_SSL::bool%`,
51
- pool: {
52
- maxConnections: '%?project.env.DB_POOL_MAX_CONNECTIONS%',
53
- maxConnecting: '%?project.env.DB_POOL_MAX_CONNECTING%',
54
- maxIdle: '%?project.env.DB_POOL_MAX_IDLE%',
55
- reconnectIntervalMs: '%?project.env.DB_POOL_RECONNECT_INTERVAL_MS%',
56
- idleTimeoutMs: '%?project.env.DB_POOL_IDLE_TIMEOUT_MS%',
57
- acquireTimeoutMs: '%?project.env.DB_POOL_ACQUIRE_TIMEOUT_MS%',
58
- maxUses: '%?project.env.DB_POOL_MAX_USES%',
59
- maxAgeMs: '%?project.env.DB_POOL_MAX_AGE_MS%',
57
+ ...createDbConfigTemplate('project.env.DB'),
58
+ read: {
59
+ host: `%?project.env.DB_READ_HOST%`,
60
+ port: `%?project.env.DB_READ_PORT::number%`,
61
+ user: `%?project.env.DB_READ_USER%`,
62
+ password: `%?project.secret.db.read.password||project.env.DB_READ_PASSWORD%`,
63
+ database: `%?project.env.DB_READ_NAME%`,
64
+ ...createDbConfigTemplate('project.env.DB_READ'),
60
65
  },
61
66
  },
62
67
  },
@@ -10,6 +10,7 @@ import {
10
10
  ProjectContainer,
11
11
  Providers,
12
12
  } from '@contember/engine-http'
13
+ import { Logger } from '@contember/logger'
13
14
 
14
15
  export class ProjectContainerFactoryFactory {
15
16
  constructor(
@@ -19,8 +20,8 @@ export class ProjectContainerFactoryFactory {
19
20
  ) {
20
21
  }
21
22
 
22
- create(schemaVersionBuilder: SchemaVersionBuilder): ProjectContainerFactory {
23
- return new ProjectContainerFactory(this.debug, this.plugins, schemaVersionBuilder, this.providers)
23
+ create(schemaVersionBuilder: SchemaVersionBuilder, logger: Logger): ProjectContainerFactory {
24
+ return new ProjectContainerFactory(this.debug, this.plugins, schemaVersionBuilder, this.providers, logger)
24
25
  }
25
26
  }
26
27
 
@@ -34,6 +35,7 @@ export class ProjectContainerFactory {
34
35
  private readonly plugins: Plugin[],
35
36
  private readonly schemaVersionBuilder: SchemaVersionBuilder,
36
37
  private readonly providers: Providers,
38
+ private readonly logger: Logger,
37
39
  ) {}
38
40
 
39
41
  public createContainer(args: ProjectContainerFactoryArgs): ProjectContainer {
@@ -42,9 +44,11 @@ export class ProjectContainerFactory {
42
44
  .pick(
43
45
  'project',
44
46
  'connection',
47
+ 'readConnection',
45
48
  'systemDatabaseContextFactory',
46
49
  'contentSchemaResolver',
47
50
  'graphQlSchemaFactory',
51
+ 'logger',
48
52
  )
49
53
  }
50
54
 
@@ -54,10 +58,25 @@ export class ProjectContainerFactory {
54
58
  this.providers)
55
59
  .addService('schemaVersionBuilder', () =>
56
60
  this.schemaVersionBuilder)
61
+ .addService('logger', () =>
62
+ this.logger.child({ project: project.slug }))
57
63
  .addService('project', () =>
58
64
  project)
59
- .addService('connection', ({ project }) =>
60
- Connection.create(project.db))
65
+ .addService('connection', ({ project, logger }) =>
66
+ Connection.create(project.db, err => logger.error(err)))
67
+ .addService('readConnection', ({ project, logger, connection }) => {
68
+ if (!project.db.read) {
69
+ return connection
70
+ }
71
+ return Connection.create({
72
+ ...project.db,
73
+ ...project.db.read,
74
+ pool: {
75
+ ...project.db.pool,
76
+ ...project.db.read.pool,
77
+ },
78
+ }, err => logger.error(err))
79
+ })
61
80
  .addService('graphQlSchemaBuilderFactory', () =>
62
81
  new GraphQlSchemaBuilderFactory())
63
82
  .addService('permissionsByIdentityFactory', ({}) =>
@@ -3,9 +3,9 @@ import { ProjectContainer } from '@contember/engine-http'
3
3
  import { DatabaseContext, ProjectManager, ProjectWithSecrets } from '@contember/engine-tenant-api'
4
4
  import { ProjectInitializer as SystemProjectInitializer } from '@contember/engine-system-api'
5
5
  import { ProjectContainerStore } from './ProjectContainerStore'
6
- import { Logger } from '@contember/engine-common'
7
6
  import { ProjectConfigResolver } from '../config/projectConfigResolver'
8
7
  import { TenantConfig } from '../config/config'
8
+ import { Logger } from '@contember/logger'
9
9
 
10
10
  export class ProjectContainerResolver {
11
11
  private projectContainers = new ProjectContainerStore()
@@ -22,7 +22,7 @@ export class ProjectContainerResolver {
22
22
  ) {}
23
23
 
24
24
 
25
- public async getProjectContainer(slug: string, { alias = false, logger }: {alias?: boolean; logger?: Logger} = {}): Promise<ProjectContainer | undefined> {
25
+ public async getProjectContainer(slug: string, { alias = false }: { alias?: boolean } = {}): Promise<ProjectContainer | undefined> {
26
26
  const realSlug = this.projectContainers.resolveAlias(slug)
27
27
  if (realSlug) {
28
28
  slug = realSlug
@@ -43,7 +43,7 @@ export class ProjectContainerResolver {
43
43
  if (!project) {
44
44
  return undefined
45
45
  }
46
- const container = await this.createProjectContainer(project, logger)
46
+ const container = await this.createProjectContainer(project)
47
47
  if (slug !== project.slug) {
48
48
  this.projectContainers.setAlias(project.slug, slug)
49
49
  }
@@ -59,7 +59,7 @@ export class ProjectContainerResolver {
59
59
  await this.systemProjectInitializer.initialize(
60
60
  projectContainer.systemDatabaseContextFactory,
61
61
  projectContainer.project,
62
- logger ?? new Logger(() => null),
62
+ logger ?? projectContainer.logger,
63
63
  )
64
64
  const cleanups = this.onCreate.map(it => it(projectContainer) || (() => null))
65
65
  return {
@@ -1,12 +1,13 @@
1
1
  import { ProjectInitializer as ProjectInitializerInterface, ProjectWithSecrets } from '@contember/engine-tenant-api'
2
2
  import { ProjectContainerResolver } from './ProjectContainerResolver'
3
+ import { Logger } from '@contember/logger'
3
4
 
4
5
  export class ProjectInitializer implements ProjectInitializerInterface {
5
6
  constructor(
6
7
  private readonly projectContainerResolver: ProjectContainerResolver,
7
8
  ) {}
8
9
 
9
- async initializeProject(project: ProjectWithSecrets) {
10
+ async initializeProject(project: ProjectWithSecrets, logger: Logger) {
10
11
  await this.projectContainerResolver.createProjectContainer(project)
11
12
  }
12
13
  }
@@ -18,10 +19,10 @@ export class ProjectInitializerProxy implements ProjectInitializerInterface {
18
19
  this.initializer = initializer
19
20
  }
20
21
 
21
- initializeProject(project: ProjectWithSecrets) {
22
+ initializeProject(project: ProjectWithSecrets, logger: Logger) {
22
23
  if (!this.initializer) {
23
24
  throw new Error('Initializer is not set')
24
25
  }
25
- return this.initializer.initializeProject(project)
26
+ return this.initializer.initializeProject(project, logger)
26
27
  }
27
28
  }
@@ -1,14 +1,10 @@
1
1
  import { ProjectSchemaResolver as ProjectSchemaResolverInterface } from '@contember/engine-tenant-api'
2
- import { SchemaVersionBuilder, VersionedSchema } from '@contember/engine-system-api'
3
2
  import { ProjectContainerResolver } from '@contember/engine-http'
4
3
  import { Schema } from '@contember/schema'
5
4
 
6
5
  export class ProjectSchemaResolver implements ProjectSchemaResolverInterface {
7
- private schemaCache = new Map<string, VersionedSchema>()
8
-
9
6
  constructor(
10
7
  private readonly projectContainerResolver: ProjectContainerResolver,
11
- private readonly schemaVersionBuilder: SchemaVersionBuilder,
12
8
  ) {}
13
9
 
14
10
  async getSchema(slug: string) {
@@ -17,16 +13,7 @@ export class ProjectSchemaResolver implements ProjectSchemaResolverInterface {
17
13
  return undefined
18
14
  }
19
15
  const db = container.systemDatabaseContextFactory.create()
20
- const cachedSchema = this.schemaCache.get(slug)
21
- const newSchema = await this.schemaVersionBuilder.buildSchema(db, cachedSchema)
22
- if (cachedSchema !== newSchema) {
23
- this.schemaCache.set(slug, newSchema)
24
- }
25
- return newSchema
26
- }
27
-
28
- clearCache() {
29
- this.schemaCache.clear()
16
+ return container.contentSchemaResolver.getSchema(db)
30
17
  }
31
18
  }
32
19
 
@@ -43,8 +30,4 @@ export class ProjectSchemaResolverProxy implements ProjectSchemaResolverInterfac
43
30
  }
44
31
  return this.resolver.getSchema(projectSlug)
45
32
  }
46
-
47
- clearCache() {
48
- this.resolver?.clearCache()
49
- }
50
33
  }
@@ -22,7 +22,8 @@ import {
22
22
  } from '../project'
23
23
  import { SystemContainerFactory } from '@contember/engine-system-api'
24
24
  import { ProjectConfigResolver } from '../config/projectConfigResolver'
25
- import { createSecretKey } from 'crypto'
25
+ import { createSecretKey } from 'node:crypto'
26
+ import { Logger } from '@contember/logger'
26
27
 
27
28
  interface ProjectGroupContainerFactoryArgs
28
29
  {
@@ -40,18 +41,21 @@ export class ProjectGroupContainerFactory {
40
41
  private readonly projectConfigResolver: ProjectConfigResolver,
41
42
  private readonly tenantGraphQLHandlerFactory: TenantGraphQLHandlerFactory,
42
43
  private readonly systemGraphQLHandlerFactory: SystemGraphQLHandlerFactory,
44
+ private readonly logger: Logger,
43
45
  ) {}
44
46
 
45
47
  public create({ config, slug }: ProjectGroupContainerFactoryArgs): ProjectGroupContainer {
46
48
  return new Builder({})
47
49
  .addService('slug', () =>
48
50
  slug)
51
+ .addService('logger', ({ slug }) =>
52
+ this.logger.child({ projectGroup: slug }))
49
53
  .addService('providers', () =>
50
54
  this.providers)
51
55
  .addService('tenantDbCredentials', () =>
52
56
  config.db)
53
- .addService('tenantConnection', ({ tenantDbCredentials }): Connection.ConnectionType =>
54
- Connection.create(tenantDbCredentials))
57
+ .addService('tenantConnection', ({ tenantDbCredentials, logger }): Connection.ConnectionType =>
58
+ Connection.create(tenantDbCredentials, err => logger.error(err)))
55
59
  .addService('projectSchemaResolver', () =>
56
60
  new ProjectSchemaResolverProxy())
57
61
  .addService('projectInitializer', () =>
@@ -83,8 +87,8 @@ export class ProjectGroupContainerFactory {
83
87
  this.systemContainerFactory.create({ identityFetcher }))
84
88
  .addService('schemaVersionBuilder', ({ systemContainer }) =>
85
89
  systemContainer.schemaVersionBuilder)
86
- .addService('projectContainerFactory', ({ schemaVersionBuilder }) =>
87
- this.projectContainerFactoryFactory.create(schemaVersionBuilder))
90
+ .addService('projectContainerFactory', ({ schemaVersionBuilder, logger }) =>
91
+ this.projectContainerFactoryFactory.create(schemaVersionBuilder, logger))
88
92
  .addService('tenantProjectManager', ({ tenantContainer }) =>
89
93
  tenantContainer.projectManager)
90
94
  .addService('projectContainerResolver', ({ projectContainerFactory, tenantProjectManager, systemContainer, tenantContainer }) =>
@@ -97,8 +101,8 @@ export class ProjectGroupContainerFactory {
97
101
  config,
98
102
  ))
99
103
 
100
- .setupService('projectSchemaResolver', (it, { projectContainerResolver, schemaVersionBuilder }) => {
101
- it.setResolver(new ProjectSchemaResolver(projectContainerResolver, schemaVersionBuilder))
104
+ .setupService('projectSchemaResolver', (it, { projectContainerResolver }) => {
105
+ it.setResolver(new ProjectSchemaResolver(projectContainerResolver))
102
106
  })
103
107
  .setupService('projectInitializer', (it, { projectContainerResolver }) => {
104
108
  it.setInitializer(new ProjectInitializer(projectContainerResolver))
@@ -124,6 +128,7 @@ export class ProjectGroupContainerFactory {
124
128
  'projectMembershipResolver',
125
129
  'tenantGraphQLHandler',
126
130
  'slug',
131
+ 'logger',
127
132
  )
128
133
  }
129
134
  }