@holo-js/config 0.1.9 → 0.2.1

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 (2) hide show
  1. package/dist/index.mjs +81 -100
  2. package/package.json +2 -2
package/dist/index.mjs CHANGED
@@ -347,19 +347,44 @@ var DEFAULT_QUEUE_CONFIG = Object.freeze({
347
347
  })
348
348
  })
349
349
  });
350
- function parseInteger(value, fallback, label, options = {}) {
351
- if (typeof value === "undefined") {
352
- return fallback;
350
+ function parseIntegerCandidate(value, parser) {
351
+ if (typeof value === "number") {
352
+ return value;
353
+ }
354
+ const trimmed = value.trim();
355
+ if (!trimmed) {
356
+ return Number.NaN;
353
357
  }
354
- const normalized = typeof value === "number" ? value : Number.parseInt(value, 10);
355
- if (!Number.isInteger(normalized)) {
356
- throw new Error(`[Holo Queue] ${label} must be an integer.`);
358
+ if (parser === "parse-int") {
359
+ return Number.parseInt(value, 10);
360
+ }
361
+ if (parser === "digits") {
362
+ return /^\d+$/.test(trimmed) ? Number.parseInt(trimmed, 10) : Number.NaN;
363
+ }
364
+ return Number(trimmed);
365
+ }
366
+ function parseScopedInteger(value, fallback, namespace, label, options = {}) {
367
+ const normalized = typeof value === "undefined" ? fallback : parseIntegerCandidate(value, options.parser ?? "number");
368
+ if (!Number.isFinite(normalized) || !Number.isInteger(normalized)) {
369
+ throw new Error(`[${namespace}] ${label} must be an integer.`);
357
370
  }
358
371
  if (typeof options.minimum === "number" && normalized < options.minimum) {
359
- throw new Error(`[Holo Queue] ${label} must be greater than or equal to ${options.minimum}.`);
372
+ throw new Error(`[${namespace}] ${label} must be greater than or equal to ${options.minimum}.`);
360
373
  }
361
374
  return normalized;
362
375
  }
376
+ function parseScopedOptionalInteger(value, namespace, label, options = {}) {
377
+ if (typeof value === "undefined") {
378
+ return void 0;
379
+ }
380
+ return parseScopedInteger(value, Number.NaN, namespace, label, options);
381
+ }
382
+ function parseInteger(value, fallback, namespace, label, options = {}) {
383
+ return parseScopedInteger(value, fallback, namespace, label, {
384
+ ...options,
385
+ parser: "parse-int"
386
+ });
387
+ }
363
388
  function normalizeNonEmptyString(value, label) {
364
389
  const normalized = value?.trim();
365
390
  if (!normalized) {
@@ -367,42 +392,25 @@ function normalizeNonEmptyString(value, label) {
367
392
  }
368
393
  return normalized;
369
394
  }
370
- function normalizeConnectionName(value, label) {
395
+ function normalizeScopedName(value, namespace, label) {
371
396
  const normalized = value?.trim();
372
397
  if (!normalized) {
373
- throw new Error(`[Holo Queue] ${label} must be a non-empty string.`);
398
+ throw new Error(`[${namespace}] ${label} must be a non-empty string.`);
374
399
  }
375
400
  return normalized;
376
401
  }
402
+ function normalizeConnectionName(value, namespace, label) {
403
+ return normalizeScopedName(value, namespace, label);
404
+ }
377
405
  function normalizeCacheName(value, label) {
378
- const normalized = value?.trim();
379
- if (!normalized) {
380
- throw new Error(`[Holo Cache] ${label} must be a non-empty string.`);
381
- }
382
- return normalized;
406
+ return normalizeScopedName(value, "Holo Cache", label);
383
407
  }
384
408
  function normalizeCacheOptionalString(value) {
385
409
  const normalized = value?.trim();
386
410
  return normalized || void 0;
387
411
  }
388
412
  function parseCacheInteger(value, label, options = {}) {
389
- if (typeof value === "undefined") {
390
- return void 0;
391
- }
392
- const normalized = typeof value === "number" ? value : (() => {
393
- const trimmed = value.trim();
394
- if (!trimmed) {
395
- return Number.NaN;
396
- }
397
- return Number(trimmed);
398
- })();
399
- if (!Number.isFinite(normalized) || !Number.isInteger(normalized)) {
400
- throw new Error(`[Holo Cache] ${label} must be an integer.`);
401
- }
402
- if (typeof options.minimum === "number" && normalized < options.minimum) {
403
- throw new Error(`[Holo Cache] ${label} must be greater than or equal to ${options.minimum}.`);
404
- }
405
- return normalized;
413
+ return parseScopedOptionalInteger(value, "Holo Cache", label, options);
406
414
  }
407
415
  function resolveCachePrefix(globalPrefix, localPrefix) {
408
416
  return normalizeCacheOptionalString(localPrefix) ?? globalPrefix;
@@ -495,30 +503,13 @@ function normalizeQueueName(value) {
495
503
  return value?.trim() || DEFAULT_QUEUE_NAME;
496
504
  }
497
505
  function parseRedisInteger(value, fallback, label, options = {}) {
498
- if (typeof value === "undefined") {
499
- return fallback;
500
- }
501
- const normalized = typeof value === "number" ? value : (() => {
502
- const trimmed = value.trim();
503
- if (!trimmed || !/^\d+$/.test(trimmed)) {
504
- return Number.NaN;
505
- }
506
- return Number.parseInt(trimmed, 10);
507
- })();
508
- if (!Number.isInteger(normalized)) {
509
- throw new Error(`[Holo Redis] ${label} must be an integer.`);
510
- }
511
- if (typeof options.minimum === "number" && normalized < options.minimum) {
512
- throw new Error(`[Holo Redis] ${label} must be greater than or equal to ${options.minimum}.`);
513
- }
514
- return normalized;
506
+ return parseScopedInteger(value, fallback, "Holo Redis", label, {
507
+ ...options,
508
+ parser: "digits"
509
+ });
515
510
  }
516
511
  function normalizeRedisConnectionName(value, label) {
517
- const normalized = value?.trim();
518
- if (!normalized) {
519
- throw new Error(`[Holo Redis] ${label} must be a non-empty string.`);
520
- }
521
- return normalized;
512
+ return normalizeScopedName(value, "Holo Redis", label);
522
513
  }
523
514
  function normalizeOptionalRedisString(value, label) {
524
515
  if (typeof value === "undefined") {
@@ -659,27 +650,10 @@ function resolveNormalizedRedisConnection(redisConfig, connectionName, label) {
659
650
  return resolved;
660
651
  }
661
652
  function parseSecurityInteger(value, fallback, label, options = {}) {
662
- const normalized = typeof value === "undefined" ? fallback : typeof value === "number" ? value : (() => {
663
- const trimmed = value.trim();
664
- if (!trimmed) {
665
- return Number.NaN;
666
- }
667
- return Number(trimmed);
668
- })();
669
- if (!Number.isFinite(normalized) || !Number.isInteger(normalized)) {
670
- throw new Error(`[Holo Security] ${label} must be an integer.`);
671
- }
672
- if (typeof options.minimum === "number" && normalized < options.minimum) {
673
- throw new Error(`[Holo Security] ${label} must be greater than or equal to ${options.minimum}.`);
674
- }
675
- return normalized;
653
+ return parseScopedInteger(value, fallback, "Holo Security", label, options);
676
654
  }
677
655
  function normalizeSecurityName(value, label) {
678
- const normalized = value?.trim();
679
- if (!normalized) {
680
- throw new Error(`[Holo Security] ${label} must be a non-empty string.`);
681
- }
682
- return normalized;
656
+ return normalizeScopedName(value, "Holo Security", label);
683
657
  }
684
658
  function normalizeSecurityOptionalString(value) {
685
659
  const normalized = value?.trim();
@@ -746,10 +720,10 @@ function normalizeRedisConnection(name, config2, redisConfig) {
746
720
  driver: "redis",
747
721
  connection: resolvedRedisConnection.name,
748
722
  queue: normalizeQueueName(config2.queue),
749
- retryAfter: parseInteger(config2.retryAfter, DEFAULT_QUEUE_RETRY_AFTER, `queue connection "${name}" retryAfter`, {
723
+ retryAfter: parseInteger(config2.retryAfter, DEFAULT_QUEUE_RETRY_AFTER, "Holo Queue", `queue connection "${name}" retryAfter`, {
750
724
  minimum: 0
751
725
  }),
752
- blockFor: parseInteger(config2.blockFor, DEFAULT_QUEUE_BLOCK_FOR, `queue connection "${name}" blockFor`, {
726
+ blockFor: parseInteger(config2.blockFor, DEFAULT_QUEUE_BLOCK_FOR, "Holo Queue", `queue connection "${name}" blockFor`, {
753
727
  minimum: 0
754
728
  }),
755
729
  redis: Object.freeze({
@@ -768,10 +742,10 @@ function normalizeDatabaseConnection(name, config2) {
768
742
  name,
769
743
  driver: "database",
770
744
  queue: normalizeQueueName(config2.queue),
771
- retryAfter: parseInteger(config2.retryAfter, DEFAULT_QUEUE_RETRY_AFTER, `queue connection "${name}" retryAfter`, {
745
+ retryAfter: parseInteger(config2.retryAfter, DEFAULT_QUEUE_RETRY_AFTER, "Holo Queue", `queue connection "${name}" retryAfter`, {
772
746
  minimum: 0
773
747
  }),
774
- sleep: parseInteger(config2.sleep, DEFAULT_QUEUE_SLEEP, `queue connection "${name}" sleep`, {
748
+ sleep: parseInteger(config2.sleep, DEFAULT_QUEUE_SLEEP, "Holo Queue", `queue connection "${name}" sleep`, {
775
749
  minimum: 0
776
750
  }),
777
751
  connection: config2.connection?.trim() || DEFAULT_FAILED_JOBS_CONNECTION,
@@ -795,7 +769,7 @@ function normalizeConnections(connections, redisConfig) {
795
769
  return DEFAULT_QUEUE_CONFIG.connections;
796
770
  }
797
771
  const normalizedEntries = Object.entries(connections).map(([name, config2]) => {
798
- const normalizedName = normalizeConnectionName(name, "Queue connection name");
772
+ const normalizedName = normalizeConnectionName(name, "Holo Queue", "Queue connection name");
799
773
  return [normalizedName, normalizeConnectionConfig(normalizedName, config2, redisConfig)];
800
774
  });
801
775
  return Object.freeze(Object.fromEntries(normalizedEntries));
@@ -898,7 +872,7 @@ function normalizeSessionStoreConfig(name, config2, redisConfig) {
898
872
  }
899
873
  function normalizeSessionConfig(config2 = {}, redisConfig) {
900
874
  const stores = !config2.stores || Object.keys(config2.stores).length === 0 ? holoSessionDefaults.stores : Object.freeze(Object.fromEntries(Object.entries(config2.stores).map(([name, store]) => {
901
- const normalizedName = normalizeConnectionName(name, "Session store name");
875
+ const normalizedName = normalizeConnectionName(name, "Holo Session", "Session store name");
902
876
  return [normalizedName, normalizeSessionStoreConfig(normalizedName, store, redisConfig)];
903
877
  })));
904
878
  const configuredDriver = config2.driver?.trim();
@@ -911,12 +885,13 @@ function normalizeSessionConfig(config2 = {}, redisConfig) {
911
885
  if (sameSite !== "lax" && sameSite !== "strict" && sameSite !== "none") {
912
886
  throw new Error(`[Holo Session] cookie sameSite must be "lax", "strict", or "none".`);
913
887
  }
914
- const idleTimeout = parseInteger(config2.idleTimeout, DEFAULT_SESSION_IDLE_TIMEOUT, "session idleTimeout", {
888
+ const idleTimeout = parseInteger(config2.idleTimeout, DEFAULT_SESSION_IDLE_TIMEOUT, "Holo Session", "session idleTimeout", {
915
889
  minimum: 0
916
890
  });
917
891
  const absoluteLifetime = parseInteger(
918
892
  config2.absoluteLifetime,
919
893
  DEFAULT_SESSION_ABSOLUTE_LIFETIME,
894
+ "Holo Session",
920
895
  "session absoluteLifetime",
921
896
  {
922
897
  minimum: 0
@@ -925,6 +900,7 @@ function normalizeSessionConfig(config2 = {}, redisConfig) {
925
900
  const rememberMeLifetime = parseInteger(
926
901
  config2.rememberMeLifetime,
927
902
  DEFAULT_SESSION_REMEMBER_ME_LIFETIME,
903
+ "Holo Session",
928
904
  "session rememberMeLifetime",
929
905
  {
930
906
  minimum: 0
@@ -941,7 +917,7 @@ function normalizeSessionConfig(config2 = {}, redisConfig) {
941
917
  httpOnly: cookie.httpOnly ?? true,
942
918
  sameSite,
943
919
  partitioned: cookie.partitioned ?? false,
944
- maxAge: parseInteger(cookie.maxAge, absoluteLifetime, "session cookie maxAge", {
920
+ maxAge: parseInteger(cookie.maxAge, absoluteLifetime, "Holo Session", "session cookie maxAge", {
945
921
  minimum: 0
946
922
  })
947
923
  }),
@@ -1074,10 +1050,10 @@ function normalizePasswordBroker(name, config2, providers) {
1074
1050
  name,
1075
1051
  provider,
1076
1052
  table: config2.table?.trim() || DEFAULT_AUTH_PASSWORD_RESET_TABLE,
1077
- expire: parseInteger(config2.expire, DEFAULT_AUTH_PASSWORD_EXPIRE, `auth password broker "${name}" expire`, {
1053
+ expire: parseInteger(config2.expire, DEFAULT_AUTH_PASSWORD_EXPIRE, "Holo Auth", `auth password broker "${name}" expire`, {
1078
1054
  minimum: 0
1079
1055
  }),
1080
- throttle: parseInteger(config2.throttle, DEFAULT_AUTH_PASSWORD_THROTTLE, `auth password broker "${name}" throttle`, {
1056
+ throttle: parseInteger(config2.throttle, DEFAULT_AUTH_PASSWORD_THROTTLE, "Holo Auth", `auth password broker "${name}" throttle`, {
1081
1057
  minimum: 0
1082
1058
  }),
1083
1059
  route: config2.route?.trim() || DEFAULT_AUTH_PASSWORD_RESET_ROUTE
@@ -1169,7 +1145,7 @@ function normalizeWorkosConfig(config2, guards, providers) {
1169
1145
  return holoAuthDefaults.workos;
1170
1146
  }
1171
1147
  const normalizedEntries = providerEntries.map(([name, providerConfig]) => {
1172
- const normalizedName = normalizeConnectionName(name, "Auth WorkOS provider name");
1148
+ const normalizedName = normalizeConnectionName(name, "Holo Auth", "Auth WorkOS provider name");
1173
1149
  return [normalizedName, providerConfig];
1174
1150
  });
1175
1151
  if (provider && !normalizedEntries.some(([name]) => name === provider)) {
@@ -1267,7 +1243,7 @@ function normalizeClerkConfig(config2, guards, providers) {
1267
1243
  return holoAuthDefaults.clerk;
1268
1244
  }
1269
1245
  const normalizedEntries = providerEntries.map(([name, providerConfig]) => {
1270
- const normalizedName = normalizeConnectionName(name, "Auth Clerk provider name");
1246
+ const normalizedName = normalizeConnectionName(name, "Holo Auth", "Auth Clerk provider name");
1271
1247
  return [normalizedName, providerConfig];
1272
1248
  });
1273
1249
  if (provider && !normalizedEntries.some(([name]) => name === provider)) {
@@ -1284,7 +1260,7 @@ function normalizeClerkConfig(config2, guards, providers) {
1284
1260
  }
1285
1261
  function normalizeAuthConfig(config2 = {}, _options = {}) {
1286
1262
  const providers = !config2.providers || Object.keys(config2.providers).length === 0 ? holoAuthDefaults.providers : Object.freeze(Object.fromEntries(Object.entries(config2.providers).map(([name, provider]) => {
1287
- const normalizedName = normalizeConnectionName(name, "Auth provider name");
1263
+ const normalizedName = normalizeConnectionName(name, "Holo Auth", "Auth provider name");
1288
1264
  return [normalizedName, normalizeAuthProvider(normalizedName, provider)];
1289
1265
  })));
1290
1266
  const guards = !config2.guards || Object.keys(config2.guards).length === 0 ? Object.freeze({
@@ -1294,7 +1270,7 @@ function normalizeAuthConfig(config2 = {}, _options = {}) {
1294
1270
  providers
1295
1271
  )
1296
1272
  }) : Object.freeze(Object.fromEntries(Object.entries(config2.guards).map(([name, guard]) => {
1297
- const normalizedName = normalizeConnectionName(name, "Auth guard name");
1273
+ const normalizedName = normalizeConnectionName(name, "Holo Auth", "Auth guard name");
1298
1274
  return [normalizedName, normalizeAuthGuard(normalizedName, guard, providers)];
1299
1275
  })));
1300
1276
  const passwords = !config2.passwords || Object.keys(config2.passwords).length === 0 ? Object.freeze({
@@ -1304,7 +1280,7 @@ function normalizeAuthConfig(config2 = {}, _options = {}) {
1304
1280
  providers
1305
1281
  )
1306
1282
  }) : Object.freeze(Object.fromEntries(Object.entries(config2.passwords).map(([name, broker]) => {
1307
- const normalizedName = normalizeConnectionName(name, "Auth password broker name");
1283
+ const normalizedName = normalizeConnectionName(name, "Holo Auth", "Auth password broker name");
1308
1284
  return [normalizedName, normalizePasswordBroker(normalizedName, broker, providers)];
1309
1285
  })));
1310
1286
  const defaultGuard = config2.defaults?.guard?.trim() || DEFAULT_AUTH_GUARD;
@@ -1316,7 +1292,7 @@ function normalizeAuthConfig(config2 = {}, _options = {}) {
1316
1292
  throw new Error(`[Holo Auth] default password broker "${defaultPasswords}" is not configured.`);
1317
1293
  }
1318
1294
  const social = !config2.social || Object.keys(config2.social).length === 0 ? holoAuthDefaults.social : Object.freeze(Object.fromEntries(Object.entries(config2.social).map(([name, provider]) => {
1319
- const normalizedName = normalizeConnectionName(name, "Auth social provider name");
1295
+ const normalizedName = normalizeConnectionName(name, "Holo Auth", "Auth social provider name");
1320
1296
  return [normalizedName, normalizeSocialProvider(normalizedName, provider, guards, providers)];
1321
1297
  })));
1322
1298
  const workos = normalizeWorkosConfig(config2.workos, guards, providers);
@@ -1404,15 +1380,16 @@ function normalizeBroadcastConnectionOptions(options, fallbackHost, label) {
1404
1380
  cluster: normalizeOptionalBroadcastString(options?.cluster, `${label} cluster`) ?? void 0
1405
1381
  });
1406
1382
  }
1407
- function normalizeBroadcastWorkerConfig(worker) {
1383
+ function normalizeBroadcastWorkerConfig(worker, connectionOptions, configuredConnectionPort) {
1408
1384
  const scaling = worker?.scaling;
1409
- const publicScheme = normalizeBroadcastScheme(worker?.publicScheme, "https", "Broadcast worker public scheme");
1385
+ const publicScheme = normalizeBroadcastScheme(worker?.publicScheme, connectionOptions?.scheme ?? "https", "Broadcast worker public scheme");
1386
+ const fallbackPort = typeof configuredConnectionPort === "undefined" ? DEFAULT_BROADCAST_WORKER_PORT : normalizeBroadcastPort(configuredConnectionPort, DEFAULT_BROADCAST_WORKER_PORT, "Broadcast worker port");
1410
1387
  if (scaling && scaling.driver !== "redis") {
1411
1388
  throw new Error('[Holo Broadcast] Broadcast worker scaling driver must be "redis".');
1412
1389
  }
1413
1390
  return Object.freeze({
1414
1391
  host: normalizeOptionalBroadcastString(worker?.host, "Broadcast worker host") ?? DEFAULT_BROADCAST_WORKER_HOST,
1415
- port: normalizeBroadcastPort(worker?.port, DEFAULT_BROADCAST_WORKER_PORT, "Broadcast worker port"),
1392
+ port: normalizeBroadcastPort(worker?.port, fallbackPort, "Broadcast worker port"),
1416
1393
  path: normalizeOptionalBroadcastString(worker?.path, "Broadcast worker path") ?? DEFAULT_BROADCAST_WORKER_PATH,
1417
1394
  publicHost: normalizeOptionalBroadcastString(worker?.publicHost, "Broadcast worker public host") ?? void 0,
1418
1395
  publicPort: typeof worker?.publicPort === "undefined" ? publicScheme === "http" ? DEFAULT_BROADCAST_HTTP_PORT : void 0 : normalizeBroadcastPort(
@@ -1520,10 +1497,14 @@ function normalizeBroadcastConfig(config2 = {}) {
1520
1497
  `[Holo Broadcast] default broadcast connection "${defaultConnection}" is not configured. Available connections: ${Object.keys(normalizedConnections).join(", ")}`
1521
1498
  );
1522
1499
  }
1500
+ const defaultBroadcastConnection = normalizedConnections[defaultConnection];
1501
+ const defaultHoloConnectionOptions = defaultBroadcastConnection && defaultBroadcastConnection.driver === "holo" && "options" in defaultBroadcastConnection ? defaultBroadcastConnection.options : void 0;
1502
+ const configuredDefaultConnection = config2.connections?.[defaultConnection];
1503
+ const configuredDefaultHoloConnectionPort = configuredDefaultConnection?.driver === "holo" ? configuredDefaultConnection.options?.port : void 0;
1523
1504
  return Object.freeze({
1524
1505
  default: defaultConnection,
1525
1506
  connections: Object.freeze(normalizedConnections),
1526
- worker: normalizeBroadcastWorkerConfig(config2.worker)
1507
+ worker: normalizeBroadcastWorkerConfig(config2.worker, defaultHoloConnectionOptions, configuredDefaultHoloConnectionPort)
1527
1508
  });
1528
1509
  }
1529
1510
  function normalizeOptionalMailString(value, label) {
@@ -1730,15 +1711,12 @@ function getValueAtPath(source, path) {
1730
1711
  return current;
1731
1712
  }
1732
1713
  function createConfigAccessors(configMap) {
1733
- const useConfig2 = ((path) => {
1734
- return getValueAtPath(configMap, path);
1735
- });
1736
- const config2 = ((path) => {
1714
+ const accessor = ((path) => {
1737
1715
  return getValueAtPath(configMap, path);
1738
1716
  });
1739
1717
  return {
1740
- useConfig: useConfig2,
1741
- config: config2
1718
+ useConfig: accessor,
1719
+ config: accessor
1742
1720
  };
1743
1721
  }
1744
1722
  function getRuntimeConfigState() {
@@ -1759,11 +1737,14 @@ function requireConfigRuntime() {
1759
1737
  }
1760
1738
  return runtimeConfigMap;
1761
1739
  }
1762
- function useConfig(path) {
1740
+ function getRuntimeConfigValue(path) {
1763
1741
  return getValueAtPath(requireConfigRuntime(), path);
1764
1742
  }
1743
+ function useConfig(path) {
1744
+ return getRuntimeConfigValue(path);
1745
+ }
1765
1746
  function config(path) {
1766
- return getValueAtPath(requireConfigRuntime(), path);
1747
+ return getRuntimeConfigValue(path);
1767
1748
  }
1768
1749
 
1769
1750
  // src/env.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holo-js/config",
3
- "version": "0.1.9",
3
+ "version": "0.2.1",
4
4
  "description": "Holo-JS Framework - typed config loading, env layering, and runtime access",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -22,7 +22,7 @@
22
22
  "test": "vitest --run"
23
23
  },
24
24
  "dependencies": {
25
- "@holo-js/db": "^0.1.9"
25
+ "@holo-js/db": "^0.2.1"
26
26
  },
27
27
  "devDependencies": {
28
28
  "tsup": "^8.3.5",