Merge pull request 'better config handling' (#768) from dev-760 into main
Some checks failed
ci/woodpecker/push/callbacks Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_aurora Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_chsettle Pipeline is pending
ci/woodpecker/push/gateway_tron Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_methods Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/payments_quotation Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/billing_documents Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Some checks failed
ci/woodpecker/push/callbacks Pipeline is pending
ci/woodpecker/push/discovery Pipeline is pending
ci/woodpecker/push/frontend Pipeline is pending
ci/woodpecker/push/fx_ingestor Pipeline is pending
ci/woodpecker/push/fx_oracle Pipeline is pending
ci/woodpecker/push/gateway_aurora Pipeline is pending
ci/woodpecker/push/gateway_chain Pipeline is pending
ci/woodpecker/push/gateway_chsettle Pipeline is pending
ci/woodpecker/push/gateway_tron Pipeline is pending
ci/woodpecker/push/ledger Pipeline is pending
ci/woodpecker/push/notification Pipeline is pending
ci/woodpecker/push/payments_methods Pipeline is pending
ci/woodpecker/push/payments_orchestrator Pipeline is pending
ci/woodpecker/push/payments_quotation Pipeline is pending
ci/woodpecker/push/billing_fees Pipeline failed
ci/woodpecker/push/billing_documents Pipeline failed
ci/woodpecker/push/bff Pipeline failed
Reviewed-on: #768
This commit was merged in pull request #768.
This commit is contained in:
@@ -23,11 +23,10 @@ AMPLI_ENVIRONMENT=production
|
||||
API_PROTOCOL=https
|
||||
SERVICE_HOST=app.sendico.io
|
||||
API_ENDPOINT=/api/v1
|
||||
CLIENT_ID=net.sendico.web-3f9a2c6e-7b4d-4e8a-9c2a-1d5f6b8e0a11
|
||||
WS_PROTOCOL=wss
|
||||
WS_ENDPOINT=/ws
|
||||
AMPLITUDE_SECRET=c3d75b3e2520d708440acbb16b923e79
|
||||
DEFAULT_LOCALE=en
|
||||
DEFAULT_CURRENCY=EUR
|
||||
|
||||
PBM_S3_ENDPOINT=https://s3.sendico.io
|
||||
PBM_S3_REGION=eu-central-1
|
||||
|
||||
@@ -27,9 +27,8 @@ services:
|
||||
API_PROTOCOL: ${API_PROTOCOL}
|
||||
SERVICE_HOST: ${SERVICE_HOST}
|
||||
API_ENDPOINT: ${API_ENDPOINT}
|
||||
AMPLITUDE_SECRET: ${AMPLITUDE_SECRET}
|
||||
DEFAULT_LOCALE: ${DEFAULT_LOCALE}
|
||||
DEFAULT_CURRENCY: ${DEFAULT_CURRENCY}
|
||||
CLIENT_ID: ${CLIENT_ID}
|
||||
CADDY_ACME_EMAIL: ${CADDY_ACME_EMAIL}
|
||||
ports:
|
||||
- "0.0.0.0:${FRONTEND_HTTP_PORT}:80"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pshared/config/reader.dart';
|
||||
|
||||
|
||||
void applyCommonConfiguration(
|
||||
Map<String, dynamic> configJson, {
|
||||
required String currentApiProto,
|
||||
@@ -10,18 +9,12 @@ void applyCommonConfiguration(
|
||||
required void Function(String) setApiHost,
|
||||
required String currentApiEndpoint,
|
||||
required void Function(String) setApiEndpoint,
|
||||
required String currentAmplitudeSecret,
|
||||
required void Function(String) setAmplitudeSecret,
|
||||
required String currentAmplitudeServerZone,
|
||||
required void Function(String) setAmplitudeServerZone,
|
||||
required String currentPosthogApiKey,
|
||||
required void Function(String) setPosthogApiKey,
|
||||
required String currentPosthogHost,
|
||||
required void Function(String) setPosthogHost,
|
||||
required Locale currentDefaultLocale,
|
||||
required void Function(Locale) setDefaultLocale,
|
||||
required String currentDefaultCurrency,
|
||||
required void Function(String) setDefaultCurrency,
|
||||
required String currentWsProto,
|
||||
required void Function(String) setWsProto,
|
||||
required String currentWsEndpoint,
|
||||
@@ -38,16 +31,6 @@ void applyCommonConfiguration(
|
||||
setApiEndpoint(
|
||||
readConfigString(configJson, 'apiEndpoint', currentApiEndpoint),
|
||||
);
|
||||
setAmplitudeSecret(
|
||||
readConfigString(configJson, 'amplitudeSecret', currentAmplitudeSecret),
|
||||
);
|
||||
setAmplitudeServerZone(
|
||||
readConfigString(
|
||||
configJson,
|
||||
'amplitudeServerZone',
|
||||
currentAmplitudeServerZone,
|
||||
),
|
||||
);
|
||||
setPosthogApiKey(
|
||||
readConfigString(configJson, 'posthogApiKey', currentPosthogApiKey),
|
||||
);
|
||||
@@ -63,9 +46,6 @@ void applyCommonConfiguration(
|
||||
),
|
||||
),
|
||||
);
|
||||
setDefaultCurrency(
|
||||
readConfigString(configJson, 'defaultCurrency', currentDefaultCurrency),
|
||||
);
|
||||
setWsProto(readConfigString(configJson, 'wsProto', currentWsProto));
|
||||
setWsEndpoint(readConfigString(configJson, 'wsEndpoint', currentWsEndpoint));
|
||||
setDefaultDimensionLength(
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/config/apply.dart';
|
||||
|
||||
|
||||
class CommonConstants {
|
||||
static String apiProto = 'https';
|
||||
static String apiHost = 'app.sendico.io';
|
||||
static String apiEndpoint = '/api/v1';
|
||||
static String amplitudeSecret = 'c3d75b3e2520d708440acbb16b923e79';
|
||||
static String amplitudeServerZone = 'EU';
|
||||
static String posthogApiKey =
|
||||
'phc_lVhbruaZpxiQxppHBJpL36ARnPlkqbCewv6cauoceTN';
|
||||
static String posthogApiKey = 'phc_lVhbruaZpxiQxppHBJpL36ARnPlkqbCewv6cauoceTN';
|
||||
static String posthogHost = 'https://eu.i.posthog.com';
|
||||
static Locale defaultLocale = const Locale('en');
|
||||
static String defaultCurrency = 'EUR';
|
||||
static int defaultDimensionLength = 500;
|
||||
static String clientId = '';
|
||||
static String wsProto = 'ws';
|
||||
@@ -38,18 +36,12 @@ class CommonConstants {
|
||||
setApiHost: (value) => apiHost = value,
|
||||
currentApiEndpoint: apiEndpoint,
|
||||
setApiEndpoint: (value) => apiEndpoint = value,
|
||||
currentAmplitudeSecret: amplitudeSecret,
|
||||
setAmplitudeSecret: (value) => amplitudeSecret = value,
|
||||
currentAmplitudeServerZone: amplitudeServerZone,
|
||||
setAmplitudeServerZone: (value) => amplitudeServerZone = value,
|
||||
currentPosthogApiKey: posthogApiKey,
|
||||
setPosthogApiKey: (value) => posthogApiKey = value,
|
||||
currentPosthogHost: posthogHost,
|
||||
setPosthogHost: (value) => posthogHost = value,
|
||||
currentDefaultLocale: defaultLocale,
|
||||
setDefaultLocale: (value) => defaultLocale = value,
|
||||
currentDefaultCurrency: defaultCurrency,
|
||||
setDefaultCurrency: (value) => defaultCurrency = value,
|
||||
currentWsProto: wsProto,
|
||||
setWsProto: (value) => wsProto = value,
|
||||
currentWsEndpoint: wsEndpoint,
|
||||
|
||||
@@ -5,13 +5,10 @@ class CommonConstants {
|
||||
static String apiProto = 'http';
|
||||
static String apiHost = 'localhost:8080';
|
||||
static String apiEndpoint = '/api/v1';
|
||||
static String amplitudeSecret = 'c3d75b3e2520d708440acbb16b923e79';
|
||||
static String amplitudeServerZone = 'EU';
|
||||
static String posthogApiKey =
|
||||
'phc_lVhbruaZpxiQxppHBJpL36ARnPlkqbCewv6cauoceTN';
|
||||
static String posthogHost = 'https://eu.i.posthog.com';
|
||||
static Locale defaultLocale = const Locale('en');
|
||||
static String defaultCurrency = 'EUR';
|
||||
static int defaultDimensionLength = 500;
|
||||
static String clientId = '';
|
||||
static String wsProto = 'ws';
|
||||
@@ -38,18 +35,12 @@ class CommonConstants {
|
||||
setApiHost: (value) => apiHost = value,
|
||||
currentApiEndpoint: apiEndpoint,
|
||||
setApiEndpoint: (value) => apiEndpoint = value,
|
||||
currentAmplitudeSecret: amplitudeSecret,
|
||||
setAmplitudeSecret: (value) => amplitudeSecret = value,
|
||||
currentAmplitudeServerZone: amplitudeServerZone,
|
||||
setAmplitudeServerZone: (value) => amplitudeServerZone = value,
|
||||
currentPosthogApiKey: posthogApiKey,
|
||||
setPosthogApiKey: (value) => posthogApiKey = value,
|
||||
currentPosthogHost: posthogHost,
|
||||
setPosthogHost: (value) => posthogHost = value,
|
||||
currentDefaultLocale: defaultLocale,
|
||||
setDefaultLocale: (value) => defaultLocale = value,
|
||||
currentDefaultCurrency: defaultCurrency,
|
||||
setDefaultCurrency: (value) => defaultCurrency = value,
|
||||
currentWsProto: wsProto,
|
||||
setWsProto: (value) => wsProto = value,
|
||||
currentWsEndpoint: wsEndpoint,
|
||||
|
||||
@@ -1,14 +1,74 @@
|
||||
import 'dart:ui';
|
||||
import 'dart:js_interop';
|
||||
|
||||
import 'dart:js_interop';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:pshared/config/common.dart';
|
||||
|
||||
|
||||
/// Bind to the global JS `appConfig` (if it exists).
|
||||
@JS()
|
||||
external AppConfig? get appConfig;
|
||||
|
||||
final _runtimeConfigLogger = Logger('config.runtime');
|
||||
|
||||
const _requiredRuntimeConfigKeys = <String>{
|
||||
'apiProto',
|
||||
'apiHost',
|
||||
'apiEndpoint',
|
||||
'clientId',
|
||||
'wsProto',
|
||||
'wsEndpoint',
|
||||
};
|
||||
|
||||
const _optionalRuntimeConfigKeys = <String>{
|
||||
'posthogApiKey',
|
||||
'posthogHost',
|
||||
'defaultLocale',
|
||||
'defaultDimensionLength',
|
||||
'themeColor',
|
||||
};
|
||||
|
||||
bool _isMissingRuntimeConfigValue(dynamic value) {
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
final text = value.toString().trim();
|
||||
return text.isEmpty || text == 'undefined' || text == 'null';
|
||||
}
|
||||
|
||||
List<String> _missingRuntimeConfigKeys(
|
||||
Iterable<String> keys,
|
||||
Map<String, dynamic> configJson,
|
||||
) {
|
||||
return keys
|
||||
.where((key) => _isMissingRuntimeConfigValue(configJson[key]))
|
||||
.toList()
|
||||
..sort();
|
||||
}
|
||||
|
||||
void _logRuntimeConfigDiagnostics(Map<String, dynamic> configJson) {
|
||||
final missingRequired = _missingRuntimeConfigKeys(
|
||||
_requiredRuntimeConfigKeys,
|
||||
configJson,
|
||||
);
|
||||
final missingOptional = _missingRuntimeConfigKeys(
|
||||
_optionalRuntimeConfigKeys,
|
||||
configJson,
|
||||
);
|
||||
|
||||
if (missingRequired.isNotEmpty) {
|
||||
_runtimeConfigLogger.severe(
|
||||
'Missing required runtime config: ${missingRequired.join(', ')}',
|
||||
);
|
||||
}
|
||||
if (missingOptional.isNotEmpty) {
|
||||
_runtimeConfigLogger.warning(
|
||||
'Missing runtime config, using built-in defaults for: '
|
||||
'${missingOptional.join(', ')}',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A staticInterop class for the JS object returned by `appConfig`.
|
||||
@JS()
|
||||
@staticInterop
|
||||
@@ -19,8 +79,6 @@ extension AppConfigExtension on AppConfig {
|
||||
external String? get apiProto;
|
||||
external String? get apiHost;
|
||||
external String? get apiEndpoint;
|
||||
external String? get amplitudeSecret;
|
||||
external String? get amplitudeServerZone;
|
||||
external String? get posthogApiKey;
|
||||
external String? get posthogHost;
|
||||
external String? get defaultLocale;
|
||||
@@ -32,19 +90,20 @@ extension AppConfigExtension on AppConfig {
|
||||
}
|
||||
|
||||
class Constants extends CommonConstants {
|
||||
static const String _clientIdWeb = 'net.sendico.web-3f9a2c6e-7b4d-4e8a-9c2a-1d5f6b8e0a11';
|
||||
|
||||
// Just re-expose these from CommonConstants:
|
||||
static Locale get defaultLocale => CommonConstants.defaultLocale;
|
||||
static String get clientId => _clientIdWeb;
|
||||
static String get accessTokenStorageKey => CommonConstants.accessTokenStorageKey;
|
||||
static String get refreshTokenStorageKey => CommonConstants.refreshTokenStorageKey;
|
||||
static String get clientId => CommonConstants.clientId;
|
||||
static String get accessTokenStorageKey =>
|
||||
CommonConstants.accessTokenStorageKey;
|
||||
static String get refreshTokenStorageKey =>
|
||||
CommonConstants.refreshTokenStorageKey;
|
||||
static String get currentOrgKey => CommonConstants.currentOrgKey;
|
||||
static String get apiUrl => CommonConstants.apiUrl;
|
||||
static String get serviceUrl => CommonConstants.serviceUrl;
|
||||
static String get posthogApiKey => CommonConstants.posthogApiKey;
|
||||
static String get posthogHost => CommonConstants.posthogHost;
|
||||
static int get defaultDimensionLength => CommonConstants.defaultDimensionLength;
|
||||
static int get defaultDimensionLength =>
|
||||
CommonConstants.defaultDimensionLength;
|
||||
static String get deviceIdStorageKey => CommonConstants.deviceIdStorageKey;
|
||||
static String get nilObjectRef => CommonConstants.nilObjectRef;
|
||||
static Color get themeColor => CommonConstants.themeColor;
|
||||
@@ -55,12 +114,11 @@ class Constants extends CommonConstants {
|
||||
|
||||
if (config != null) {
|
||||
// Build a Dart Map from the JS object’s properties:
|
||||
final configJson = <String, dynamic>{
|
||||
final runtimeConfigJson = <String, dynamic>{
|
||||
'apiProto': config.apiProto,
|
||||
'apiHost': config.apiHost,
|
||||
'apiEndpoint': config.apiEndpoint,
|
||||
'amplitudeSecret': config.amplitudeSecret,
|
||||
'amplitudeServerZone': config.amplitudeServerZone,
|
||||
'clientId': config.clientId,
|
||||
'posthogApiKey': config.posthogApiKey,
|
||||
'posthogHost': config.posthogHost,
|
||||
'defaultLocale': config.defaultLocale,
|
||||
@@ -68,14 +126,24 @@ class Constants extends CommonConstants {
|
||||
'wsEndpoint': config.wsEndpoint,
|
||||
'defaultDimensionLength': config.defaultDimensionLength,
|
||||
'themeColor': config.themeColor,
|
||||
// If the JS side didn’t supply a clientId, fall back to our Dart constant
|
||||
'clientId': config.clientId ?? _clientIdWeb,
|
||||
};
|
||||
|
||||
CommonConstants.applyConfiguration(configJson);
|
||||
_logRuntimeConfigDiagnostics(runtimeConfigJson);
|
||||
final missingRequired = _missingRuntimeConfigKeys(
|
||||
_requiredRuntimeConfigKeys,
|
||||
runtimeConfigJson,
|
||||
);
|
||||
if (missingRequired.isNotEmpty) {
|
||||
throw StateError(
|
||||
'Missing required runtime config: ${missingRequired.join(', ')}',
|
||||
);
|
||||
}
|
||||
CommonConstants.applyConfiguration(runtimeConfigJson);
|
||||
} else {
|
||||
// No appConfig on JS side → just use the default Dart client ID.
|
||||
CommonConstants.clientId = _clientIdWeb;
|
||||
_runtimeConfigLogger.severe(
|
||||
'window.appConfig is not defined; frontend runtime config is required.',
|
||||
);
|
||||
throw StateError('window.appConfig is not defined');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,8 @@ window.appConfig = {
|
||||
apiProto: "$(js_escape "${API_PROTOCOL:-https}")",
|
||||
apiHost: "$(js_escape "${SERVICE_HOST:-app.sendico.io}")",
|
||||
apiEndpoint: "$(js_escape "${API_ENDPOINT:-/api/v1}")",
|
||||
amplitudeSecret: "$(js_escape "${AMPLITUDE_SECRET:-}")",
|
||||
defaultLocale: "$(js_escape "${DEFAULT_LOCALE:-en}")",
|
||||
defaultCurrency: "$(js_escape "${DEFAULT_CURRENCY:-EUR}")",
|
||||
clientId: "$(js_escape "${CLIENT_ID:?CLIENT_ID is required}")",
|
||||
wsProto: "$(js_escape "${WS_PROTOCOL:-wss}")",
|
||||
wsEndpoint: "$(js_escape "${WS_ENDPOINT:-/ws}")"
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user