diff --git a/packages/server/src/Server.test.ts b/packages/server/src/Server.test.ts index 228d7efc..69ef1305 100644 --- a/packages/server/src/Server.test.ts +++ b/packages/server/src/Server.test.ts @@ -8,7 +8,7 @@ describe('server', () => { user: 'username', password: 'password', }; - const server = Nile(config); + const server = new Nile(config); expect(server.config.db).toEqual({ host: 'db.thenile.dev', port: 5432, @@ -24,7 +24,7 @@ describe('server', () => { user: 'username', password: 'password', }; - const nile = Nile(config); + const nile = new Nile(config); nile.tenantId = 'tenantId'; nile.userId = 'userId'; for (const api in nile.api) { @@ -39,7 +39,7 @@ describe('server', () => { user: 'username', password: 'password', }; - const nile = Nile(config); + const nile = new Nile(config); const another = nile.getInstance({ databaseId: 'somethingelse?!', @@ -68,7 +68,7 @@ describe('server', () => { user: 'username', password: 'password', }; - const nile = Nile(config); + const nile = new Nile(config); const another = nile.getInstance({ databaseId: 'somethingelse?!', diff --git a/packages/server/src/Server.ts b/packages/server/src/Server.ts index 064bf466..2ae09eee 100644 --- a/packages/server/src/Server.ts +++ b/packages/server/src/Server.ts @@ -15,17 +15,15 @@ type Api = { tenants: Tenants; }; -const init = (config: Config): [Api] => { +const init = (config: Config): Api => { const auth = new Auth(config); const users = new Users(config); const tenants = new Tenants(config); - return [ - { - auth, - users, - tenants, - }, - ]; + return { + auth, + users, + tenants, + }; }; class Server { @@ -35,10 +33,9 @@ class Server { private servers: Map; constructor(config?: ServerConfig) { - this.config = new Config(config as ServerConfig, true); + this.config = new Config(config as ServerConfig); this.servers = new Map(); - const [api] = init(this.config); - this.api = api; + this.api = init(this.config); this.manager = new DbManager(this.config); watchTenantId((tenantId) => { @@ -55,7 +52,17 @@ class Server { } setConfig(cfg: Config) { - this.config = new Config(cfg, false); + this.config = new Config(cfg); + } + + async init(cfg?: Config) { + const updatedConfig = await this.config.configure({ + ...this.config, + ...cfg, + }); + this.setConfig(updatedConfig); + this.manager = new DbManager(this.config); + this.api = init(updatedConfig); } set databaseId(val: string | void) { @@ -134,7 +141,7 @@ class Server { if (existing) { // be sure the config is up to date - const updatedConfig = new Config(_config, false); + const updatedConfig = new Config(_config); existing.setConfig(updatedConfig); // propagage special config items existing.tenantId = updatedConfig.tenantId; @@ -149,9 +156,4 @@ class Server { } } -// export default Server; -export default function Nile(config?: ServerConfig) { - const server = new Server(config); - // server.setConfig(new Config(config as ServerConfig, false)); - return server; -} +export default Server; diff --git a/packages/server/src/auth/auth.test.ts b/packages/server/src/auth/auth.test.ts index 61408e4c..7c20d7b4 100644 --- a/packages/server/src/auth/auth.test.ts +++ b/packages/server/src/auth/auth.test.ts @@ -19,6 +19,7 @@ const baseConfig = [ 'loginSSOUrl', 'signUp', 'updateProvider', + 'configure', 'user', 'password', ]; diff --git a/packages/server/src/db/DBManager.ts b/packages/server/src/db/DBManager.ts index eaccbf25..09d225b2 100644 --- a/packages/server/src/db/DBManager.ts +++ b/packages/server/src/db/DBManager.ts @@ -3,6 +3,7 @@ import { Pool } from 'pg'; import { Config } from '../utils/Config'; import { watchEvictPool } from '../utils/Event'; import Logger from '../utils/Logger'; +import { ServerConfig } from '../types'; import NileDatabase from './NileInstance'; @@ -21,7 +22,7 @@ export default class DBManager { } return 'base'; } - constructor(config: Config) { + constructor(config: ServerConfig) { const { info } = Logger(config, '[DBManager]'); this.connections = new Map(); // add the base one, so you can at least query @@ -35,7 +36,7 @@ export default class DBManager { }); } - getConnection(config: Config): Pool { + getConnection(config: ServerConfig): Pool { const { info } = Logger(config, '[DBManager]'); const id = this.makeId(config.tenantId, config.userId); const existing = this.connections.get(id); diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 7cdbe899..0665c0d9 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1,4 +1,3 @@ import { default as Server } from './Server'; -module.exports = Server; export default Server; diff --git a/packages/server/src/tenants/tenants.test.ts b/packages/server/src/tenants/tenants.test.ts index b478ede0..6040014f 100644 --- a/packages/server/src/tenants/tenants.test.ts +++ b/packages/server/src/tenants/tenants.test.ts @@ -13,6 +13,7 @@ const baseConfig = [ 'databaseId', 'databaseName', 'user', + 'configure', 'password', ]; const config = { diff --git a/packages/server/src/users/users.test.ts b/packages/server/src/users/users.test.ts index 55f318dd..0abd0a73 100644 --- a/packages/server/src/users/users.test.ts +++ b/packages/server/src/users/users.test.ts @@ -14,6 +14,7 @@ const baseConfig = [ 'me', 'databaseName', 'debug', + 'configure', 'updateUser', 'user', 'password', diff --git a/packages/server/src/utils/Config/index.ts b/packages/server/src/utils/Config/index.ts index 4dce36d8..2619a5dd 100644 --- a/packages/server/src/utils/Config/index.ts +++ b/packages/server/src/utils/Config/index.ts @@ -83,31 +83,75 @@ export class Config { this._userId = value; } - constructor(config: ServerConfig, allowPhoneHome?: boolean) { - const { info, error } = Logger(config, '[config]'); - + constructor(config: ServerConfig) { const envVarConfig: EnvConfig = { config, }; - if (allowPhoneHome) { - envVarConfig.logger = '[config]'; - } this.databaseId = getDatbaseId(envVarConfig) as string; this.user = getUsername(envVarConfig) as string; this.password = getPassword(envVarConfig) as string; this.databaseName = getDatabaseName(envVarConfig) as string; this._tenantId = getTenantId(envVarConfig); this.debug = Boolean(config?.debug); + this._userId = config?.userId; - let basePath = getBasePath(envVarConfig); + const basePath = getBasePath(envVarConfig); + const host = getDbHost(envVarConfig); + const port = getDbPort(envVarConfig); + + this.api = new ApiConfig({ + basePath, + cookieKey: config?.api?.cookieKey ?? 'token', + token: getToken({ config }), + }); + this.db = { + user: this.user, + password: this.password, + host, + port, + database: this.databaseName, + ...(typeof config?.db === 'object' ? config.db : {}), + }; + } + configure = async (config: ServerConfig): Promise => { + const { info, error } = Logger(config, '[init]'); + const envVarConfig: EnvConfig = { + config, + }; + let basePath = getBasePath(envVarConfig); let host = getDbHost(envVarConfig); const port = getDbPort(envVarConfig); - this._userId = config?.userId; - - if (allowPhoneHome && (!host || !this.databaseName || !this.databaseId)) { - const database = getInfo(config); + const databaseName = getDatabaseName({ config, logger: 'getInfo' }); + const url = new URL(`${basePath}/databases/configure`); + if (databaseName) { + url.searchParams.set('databaseName', databaseName); + } + info(url.href); + const res = syncFetch(url, { + headers: { + Authorization: `Bearer ${getInfoBearer({ config })}`, + }, + }); + let database: Database; + const possibleError = res.clone(); + try { + const json: Database = res.json(); + if (res.status === 404) { + info('is the configured databaseName correct?'); + } + if (json.status && json.status !== 'READY') { + database = { message: 'Database is not ready yet' } as Database; + } else { + database = json; + } + } catch (e) { + const message = possibleError.text(); + error(message); + database = { message } as Database; + } + if (!host || !this.databaseName || !this.databaseId) { info('[fetched database]', database); if (process.env.NODE_ENV !== 'TEST') { if ('message' in database) { @@ -132,7 +176,6 @@ export class Config { } } } - this.api = new ApiConfig({ basePath, cookieKey: config?.api?.cookieKey ?? 'token', @@ -146,39 +189,7 @@ export class Config { database: this.databaseName, ...(typeof config?.db === 'object' ? config.db : {}), }; - if (allowPhoneHome) { - info(this); - } - } -} - -function getInfo(config: ServerConfig): Database { - const basePath = getBasePath({ config }); - const databaseName = getDatabaseName({ config, logger: 'getInfo' }); - const url = new URL(`${basePath}/databases/configure`); - if (databaseName) { - url.searchParams.set('databaseName', databaseName); - } - const { info, error } = Logger(config, '[getInfo]'); - info(url.href); - const res = syncFetch(url, { - headers: { - Authorization: `Bearer ${getInfoBearer({ config })}`, - }, - }); - const possibleError = res.clone(); - try { - const json: Database = res.json(); - if (res.status === 404) { - info('is the configured databaseName correct?'); - } - if (json.status && json.status !== 'READY') { - return { message: 'Database is not ready yet' } as Database; - } - return json; - } catch (e) { - const message = possibleError.text(); - error(message); - return { message } as Database; - } + info('[config set]', this); + return this; + }; } diff --git a/packages/server/test/integration/integration.test.ts b/packages/server/test/integration/integration.test.ts index 8b654439..b455de94 100644 --- a/packages/server/test/integration/integration.test.ts +++ b/packages/server/test/integration/integration.test.ts @@ -26,7 +26,8 @@ const config: ServerConfig = { describe.skip('api integration', () => { it('does a bunch of api calls', async () => { - const nile = Server(config); + const nile = new Server(config); + await nile.init(); const loginResp = await nile.api.auth.login({ email: String(process.env.EMAIL), password: String(process.env.PASSWORD), @@ -57,7 +58,8 @@ describe.skip('api integration', () => { describe.skip('db integration', () => { it('queries', async () => { - const nile = Server(config); + const nile = new Server(config); + await nile.init(); const res = await nile.db.query('select * from tenants'); expect(res.rowCount).toBeGreaterThan(0); });