@raubjo/architect 0.5.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 (68) hide show
  1. package/README.md +860 -0
  2. package/package.json +121 -0
  3. package/src/cache/cache.ts +46 -0
  4. package/src/cache/contract.ts +9 -0
  5. package/src/cache/manager.ts +110 -0
  6. package/src/cache/provider.ts +11 -0
  7. package/src/config/contract.ts +63 -0
  8. package/src/config/discovery.ts +99 -0
  9. package/src/config/env.global.d.ts +6 -0
  10. package/src/config/env.ts +68 -0
  11. package/src/config/index.ts +5 -0
  12. package/src/config/provider.ts +17 -0
  13. package/src/config/repository.ts +164 -0
  14. package/src/container/adapters/builtin.ts +323 -0
  15. package/src/container/contract.ts +43 -0
  16. package/src/container/runtime.ts +29 -0
  17. package/src/events/bus.ts +174 -0
  18. package/src/events/concerns/dispatchable.ts +10 -0
  19. package/src/events/provider.ts +9 -0
  20. package/src/events/types.ts +9 -0
  21. package/src/foundation/application.ts +136 -0
  22. package/src/foundation/current-application.ts +20 -0
  23. package/src/index.ts +58 -0
  24. package/src/log/contract.ts +21 -0
  25. package/src/log/drivers/console.ts +54 -0
  26. package/src/log/drivers/null.ts +23 -0
  27. package/src/log/drivers/stack.ts +46 -0
  28. package/src/log/manager.ts +76 -0
  29. package/src/log/provider.ts +11 -0
  30. package/src/react.ts +2 -0
  31. package/src/renderers/adapters/react.tsx +25 -0
  32. package/src/renderers/adapters/solid.tsx +26 -0
  33. package/src/renderers/adapters/svelte.ts +73 -0
  34. package/src/renderers/adapters/vue.ts +22 -0
  35. package/src/renderers/contract.ts +12 -0
  36. package/src/runtimes/react.tsx +81 -0
  37. package/src/runtimes/solid.tsx +47 -0
  38. package/src/runtimes/svelte.ts +17 -0
  39. package/src/runtimes/vue.ts +34 -0
  40. package/src/solid.ts +2 -0
  41. package/src/store/adapters/contract.ts +11 -0
  42. package/src/store/adapters/indexed-db.ts +187 -0
  43. package/src/store/adapters/local-storage.ts +48 -0
  44. package/src/store/adapters/memory.ts +35 -0
  45. package/src/store/manager.ts +68 -0
  46. package/src/store/provider.ts +10 -0
  47. package/src/store/store.ts +1 -0
  48. package/src/support/arr.ts +372 -0
  49. package/src/support/collection.ts +889 -0
  50. package/src/support/facades/cache.ts +6 -0
  51. package/src/support/facades/config.ts +6 -0
  52. package/src/support/facades/event.ts +6 -0
  53. package/src/support/facades/facade.ts +146 -0
  54. package/src/support/facades/index.ts +5 -0
  55. package/src/support/facades/log.ts +6 -0
  56. package/src/support/facades/store.ts +6 -0
  57. package/src/support/fluent.ts +56 -0
  58. package/src/support/globals.ts +8 -0
  59. package/src/support/lazy-collection.ts +341 -0
  60. package/src/support/manager.ts +53 -0
  61. package/src/support/num.ts +50 -0
  62. package/src/support/pipeline.ts +29 -0
  63. package/src/support/service-provider.ts +19 -0
  64. package/src/support/str.ts +682 -0
  65. package/src/svelte.ts +2 -0
  66. package/src/types/peer-deps.d.ts +10 -0
  67. package/src/vue.ts +2 -0
  68. package/tsconfig.json +15 -0
package/package.json ADDED
@@ -0,0 +1,121 @@
1
+ {
2
+ "name": "@raubjo/architect",
3
+ "version": "0.5.1",
4
+ "private": false,
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "scripts": {
11
+ "test": "bun test",
12
+ "test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-dir=coverage && node scripts/lcov-to-istanbul.js",
13
+ "fallow": "npm run test:coverage && npx fallow health --coverage coverage/coverage-final.json",
14
+ "fix": "biome check --fix ./src/**/* && fallow fix",
15
+ "sandcastle": "bun .sandcastle/main.ts",
16
+ "version:major": "npm verison major",
17
+ "version:minor": "npm verison minor",
18
+ "version:patch": "npm verison patch",
19
+ "release": "npm publish",
20
+ "prepare": "bun husky"
21
+ },
22
+ "exports": {
23
+ ".": "./src/index.ts",
24
+ "./react": "./src/react.ts",
25
+ "./solid": "./src/solid.ts",
26
+ "./svelte": "./src/svelte.ts",
27
+ "./vue": "./src/vue.ts",
28
+ "./application": "./src/foundation/application.ts",
29
+ "./container/contract": "./src/container/contract.ts",
30
+ "./container/adapters/builtin": "./src/container/adapters/builtin.ts",
31
+ "./config/env": "./src/config/env.ts",
32
+ "./config/repository": "./src/config/repository.ts",
33
+ "./cache/manager": "./src/cache/manager.ts",
34
+ "./cache/cache": "./src/cache/cache.ts",
35
+ "./cache/provider": "./src/cache/provider.ts",
36
+ "./facades/cache": "./src/support/facades/cache.ts",
37
+ "./facades/event": "./src/support/facades/event.ts",
38
+ "./facades/log": "./src/support/facades/log.ts",
39
+ "./log/contract": "./src/log/contract.ts",
40
+ "./log/manager": "./src/log/manager.ts",
41
+ "./log/provider": "./src/log/provider.ts",
42
+ "./log/drivers/console": "./src/log/drivers/console.ts",
43
+ "./log/drivers/null": "./src/log/drivers/null.ts",
44
+ "./log/drivers/stack": "./src/log/drivers/stack.ts",
45
+ "./config/provider": "./src/config/provider.ts",
46
+ "./events/bus": "./src/events/bus.ts",
47
+ "./events/concerns/dispatchable": "./src/events/concerns/dispatchable.ts",
48
+ "./events/provider": "./src/events/provider.ts",
49
+ "./store/manager": "./src/store/manager.ts",
50
+ "./store/adapters/contract": "./src/store/adapters/contract.ts",
51
+ "./store/store": "./src/store/store.ts",
52
+ "./store/adapters/memory": "./src/store/adapters/memory.ts",
53
+ "./store/adapters/local-storage": "./src/store/adapters/local-storage.ts",
54
+ "./store/adapters/indexed-db": "./src/store/adapters/indexed-db.ts",
55
+ "./store/provider": "./src/store/provider.ts",
56
+ "./facades/store": "./src/support/facades/store.ts",
57
+ "./filesystem/filesystem": "./src/filesystem/filesystem.ts",
58
+ "./filesystem/local-adapter": "./src/filesystem/adapters/local.ts",
59
+ "./renderers/contract": "./src/renderers/contract.ts",
60
+ "./renderers/react": "./src/renderers/adapters/react.tsx",
61
+ "./renderers/solid": "./src/renderers/adapters/solid.tsx",
62
+ "./renderers/svelte": "./src/renderers/adapters/svelte.ts",
63
+ "./renderers/vue": "./src/renderers/adapters/vue.ts",
64
+ "./support/facades": "./src/support/facades/index.ts",
65
+ "./facades/config": "./src/support/facades/config.ts",
66
+ "./runtimes/react": "./src/runtimes/react.tsx",
67
+ "./runtimes/solid": "./src/runtimes/solid.tsx",
68
+ "./runtimes/svelte": "./src/runtimes/svelte.ts",
69
+ "./runtimes/vue": "./src/runtimes/vue.ts",
70
+ "./str": "./src/support/str.ts",
71
+ "./arr": "./src/support/arr.ts",
72
+ "./collection": "./src/support/collection.ts",
73
+ "./lazy-collection": "./src/support/lazy-collection.ts",
74
+ "./fluent": "./src/support/fluent.ts",
75
+ "./num": "./src/support/num.ts",
76
+ "./pipeline": "./src/support/pipeline.ts",
77
+ "./service-provider": "./src/support/service-provider.ts",
78
+ "./manager": "./src/support/manager.ts",
79
+ "./facade": "./src/support/facades/facade.ts"
80
+ },
81
+ "peerDependencies": {
82
+ "react": "^19.0.0",
83
+ "react-dom": "^19.0.0",
84
+ "reflect-metadata": "^0.2.2",
85
+ "solid-js": "^1.9.0",
86
+ "svelte": "",
87
+ "vue": "^3.0.0"
88
+ },
89
+ "peerDependenciesMeta": {
90
+ "react": {
91
+ "optional": true
92
+ },
93
+ "react-dom": {
94
+ "optional": true
95
+ },
96
+ "solid-js": {
97
+ "optional": true
98
+ },
99
+ "svelte": {
100
+ "optional": true
101
+ },
102
+ "vue": {
103
+ "optional": true
104
+ },
105
+ "reflect-metadata": {
106
+ "optional": false
107
+ }
108
+ },
109
+ "devDependencies": {
110
+ "@types/react": "^19.2.14",
111
+ "@types/react-dom": "^19.2.3",
112
+ "bun-types": "^1.3.13",
113
+ "fallow": "^2.67.0",
114
+ "husky": "^9.1.7",
115
+ "solid-js": "^1.9.12",
116
+ "vue": "^3.5.34"
117
+ },
118
+ "trustedDependencies": [
119
+ "@fallow-cli/fallow-cov"
120
+ ]
121
+ }
@@ -0,0 +1,46 @@
1
+ import type { Adapter } from "../store/adapters/contract"
2
+ import type { Contract } from "./contract"
3
+
4
+ type Envelope<T> = { v: T; e: number | null }
5
+
6
+ export class Cache implements Contract {
7
+ constructor(protected readonly adapter: Adapter) {}
8
+
9
+ async get(key: string): Promise<unknown>
10
+ async get<T>(key: string): Promise<T | null>
11
+ async get<T = unknown>(key: string): Promise<T | null> {
12
+ const raw = await this.adapter.get<Envelope<T>>(key)
13
+ if (raw === null) return null
14
+ if (raw.e !== null && Date.now() >= raw.e) return null
15
+ return raw.v
16
+ }
17
+
18
+ async set<T = unknown>(key: string, value: T, ttl?: number | null): Promise<void> {
19
+ const e = typeof ttl === "number" ? Date.now() + ttl * 1000 : null
20
+ return this.adapter.set<Envelope<T>>(key, { v: value, e })
21
+ }
22
+
23
+ async has(key: string): Promise<boolean> {
24
+ return (await this.get(key)) !== null
25
+ }
26
+
27
+ async delete(key: string): Promise<void> {
28
+ return this.adapter.delete(key)
29
+ }
30
+
31
+ async clear(): Promise<void> {
32
+ return this.adapter.clear()
33
+ }
34
+
35
+ async keys(): Promise<string[]> {
36
+ const allKeys = await this.adapter.keys()
37
+ const now = Date.now()
38
+ const results = await Promise.all(
39
+ allKeys.map(async (k) => {
40
+ const raw = await this.adapter.get<Envelope<unknown>>(k)
41
+ return raw !== null && (raw.e === null || now < raw.e) ? k : null
42
+ }),
43
+ )
44
+ return results.filter((k): k is string => k !== null)
45
+ }
46
+ }
@@ -0,0 +1,9 @@
1
+ export interface Contract {
2
+ get(key: string): Promise<unknown>
3
+ get<T>(key: string): Promise<T | null>
4
+ set<T = unknown>(key: string, value: T, ttl?: number | null): Promise<void>
5
+ has(key: string): Promise<boolean>
6
+ delete(key: string): Promise<void>
7
+ clear(): Promise<void>
8
+ keys(): Promise<string[]>
9
+ }
@@ -0,0 +1,110 @@
1
+ import type ConfigRepository from "../config/repository"
2
+ import type { Adapter } from "../store/adapters/contract"
3
+ import IndexedDbAdapter from "../store/adapters/indexed-db"
4
+ import LocalStorageAdapter from "../store/adapters/local-storage"
5
+ import MemoryStoreAdapter from "../store/adapters/memory"
6
+ import Manager from "../support/manager"
7
+ import { Cache } from "./cache"
8
+ import type { Contract } from "./contract"
9
+
10
+ type StoreConfig = {
11
+ driver?: string
12
+ }
13
+
14
+ function isRecord(value: unknown): value is Record<string, unknown> {
15
+ return typeof value === "object" && value !== null && !Array.isArray(value)
16
+ }
17
+
18
+ export default class CacheManager extends Manager<Contract, Adapter> implements Adapter {
19
+ protected createDriver(raw: Adapter): Contract {
20
+ return new Cache(raw)
21
+ }
22
+
23
+ protected defaultDriverName(): string {
24
+ return "memory" in this.drivers ? "memory" : super.defaultDriverName()
25
+ }
26
+
27
+ protected driverType(): string {
28
+ return "Cache store"
29
+ }
30
+
31
+ static fromConfig(config: ConfigRepository): CacheManager {
32
+ const stores = CacheManager.storesFromConfig(config)
33
+ const active = config.get<string>("cache.default", "memory")
34
+
35
+ return new CacheManager(stores, active, config)
36
+ }
37
+
38
+ protected static storesFromConfig(config: ConfigRepository): Record<string, Contract> {
39
+ const baseDrivers = CacheManager.defaultDrivers()
40
+ const configured = config.get<Record<string, unknown>>("cache.stores", {}) ?? {}
41
+ if (hasNoConfiguredStores(configured)) {
42
+ return baseDrivers
43
+ }
44
+
45
+ return Object.fromEntries(
46
+ Object.entries(configured).map(([name, storeConfig]) => {
47
+ const driver = resolveDriver(storeConfig, name)
48
+ return [name, baseDrivers[driver] ?? baseDrivers.memory]
49
+ }),
50
+ )
51
+ }
52
+
53
+ protected static defaultDrivers(): Record<string, Contract> {
54
+ const hasWindow = typeof window !== "undefined"
55
+ const hasLocal = hasWindow && typeof window.localStorage !== "undefined"
56
+ const hasIndexed = typeof globalThis.indexedDB !== "undefined"
57
+
58
+ const rawMemory = new MemoryStoreAdapter()
59
+ const memory = new Cache(rawMemory)
60
+
61
+ return {
62
+ memory,
63
+ local: new Cache(hasLocal ? new LocalStorageAdapter(window.localStorage) : rawMemory),
64
+ indexed: new Cache(hasIndexed ? new IndexedDbAdapter() : rawMemory),
65
+ }
66
+ }
67
+
68
+ store(name?: string): Contract {
69
+ return this.resolve(name ?? this.active)
70
+ }
71
+
72
+ get(key: string): Promise<unknown>
73
+ get<T>(key: string): Promise<T | null>
74
+ get<T = unknown>(key: string): Promise<T | null> {
75
+ return this.store().get<T>(key)
76
+ }
77
+
78
+ set<T = unknown>(key: string, value: T, ttl?: number | null): Promise<void> {
79
+ return this.store().set<T>(key, value, ttl)
80
+ }
81
+
82
+ has(key: string): Promise<boolean> {
83
+ return this.store().has(key)
84
+ }
85
+
86
+ delete(key: string): Promise<void> {
87
+ return this.store().delete(key)
88
+ }
89
+
90
+ clear(): Promise<void> {
91
+ return this.store().clear()
92
+ }
93
+
94
+ keys(): Promise<string[]> {
95
+ return this.store().keys()
96
+ }
97
+ }
98
+
99
+ function hasNoConfiguredStores(value: unknown): boolean {
100
+ return !isRecord(value) || Object.keys(value).length === 0
101
+ }
102
+
103
+ function resolveDriver(value: unknown, fallback: string): string {
104
+ if (!isRecord(value)) {
105
+ return fallback
106
+ }
107
+
108
+ const storeConfig = value as StoreConfig
109
+ return typeof storeConfig.driver === "string" ? storeConfig.driver : fallback
110
+ }
@@ -0,0 +1,11 @@
1
+ import type ConfigRepository from "../config/repository"
2
+ import type { ServiceProviderContext } from "../support/service-provider"
3
+ import ServiceProvider from "../support/service-provider"
4
+ import CacheManager from "./manager"
5
+
6
+ export class CacheProvider extends ServiceProvider {
7
+ register({ container }: ServiceProviderContext) {
8
+ container.singleton("cache", (c) => CacheManager.fromConfig(c.make<ConfigRepository>("config")))
9
+ container.singleton(CacheManager, (c) => c.make<CacheManager>("cache"))
10
+ }
11
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Configuration contract defining the interface for configuration management
3
+ */
4
+ export interface Contract {
5
+ /**
6
+ * Determine if a configuration key exists
7
+ */
8
+ has(key: string | string[]): boolean
9
+
10
+ /**
11
+ * Get a configuration value by key
12
+ */
13
+ get(key: string): unknown
14
+ get<T>(key: string): T | null
15
+ get<T>(key: string, defaultValue: T | (() => T)): T
16
+ get<T>(key: string, defaultValue: T | (() => T) | null): T | null
17
+
18
+ /**
19
+ * Get multiple configuration values
20
+ */
21
+ getMany(keys: string[] | Record<string, unknown>): Record<string, unknown>
22
+
23
+ /**
24
+ * Set a configuration value
25
+ */
26
+ set(key: string | Record<string, unknown>, value?: unknown): void
27
+
28
+ /**
29
+ * Prepend a value to an array configuration
30
+ */
31
+ prepend(key: string, value: unknown): void
32
+
33
+ /**
34
+ * Append a value to an array configuration
35
+ */
36
+ push(key: string, value: unknown): void
37
+
38
+ /**
39
+ * Get all configuration items
40
+ */
41
+ all(): Record<string, unknown>
42
+
43
+ /**
44
+ * Check if a configuration key exists (offset-style)
45
+ */
46
+ offsetExists(key: string): boolean
47
+
48
+ /**
49
+ * Get a configuration value by offset (offset-style)
50
+ */
51
+ offsetGet(key: string): unknown
52
+ offsetGet<T>(key: string): T | null
53
+
54
+ /**
55
+ * Set a configuration value by offset (offset-style)
56
+ */
57
+ offsetSet(key: string, value: unknown): void
58
+
59
+ /**
60
+ * Remove a configuration key (offset-style)
61
+ */
62
+ offsetUnset(key: string): void
63
+ }
@@ -0,0 +1,99 @@
1
+ import type { ConfigItems } from "./repository"
2
+ import ConfigRepository from "./repository"
3
+
4
+ type GlobLoader = (pattern: string | string[], options?: { eager?: boolean }) => Record<string, unknown>
5
+
6
+ type ConfigModule = { default?: unknown }
7
+
8
+ export interface ConfigLoader {
9
+ load(basePath: string, staticItems?: ConfigItems): ConfigItems
10
+ }
11
+
12
+ function fileNameWithoutExtension(path: string): string {
13
+ const file = path.split("/").pop() ?? path
14
+ return file.replace(/\.[^/.]+$/, "")
15
+ }
16
+
17
+ function loadConfigFromModules(modules: Record<string, unknown>): ConfigItems {
18
+ const discovered: ConfigItems = {}
19
+
20
+ for (const [path, loaded] of Object.entries(modules)) {
21
+ const key = fileNameWithoutExtension(path)
22
+ const value = readConfigModuleDefault(loaded)
23
+ if (key !== "index" && value !== undefined) {
24
+ discovered[key] = value
25
+ }
26
+ }
27
+
28
+ return discovered
29
+ }
30
+
31
+ function readConfigModuleDefault(loaded: unknown): unknown {
32
+ const module = loaded as ConfigModule
33
+ return module && "default" in module ? module.default : undefined
34
+ }
35
+
36
+ function cloneItems(items: ConfigItems): ConfigItems {
37
+ if (typeof structuredClone === "function") {
38
+ return structuredClone(items) as ConfigItems
39
+ }
40
+ return JSON.parse(JSON.stringify(items)) as ConfigItems
41
+ }
42
+
43
+ function loadEsmConfigModules(basePath: string): Record<string, unknown> {
44
+ const glob = resolveConfigGlob()
45
+ if (!glob) {
46
+ return {}
47
+ }
48
+
49
+ const modules = glob(configPatternForBasePath(basePath), { eager: true })
50
+ return modules as Record<string, unknown>
51
+ }
52
+
53
+ function resolveConfigGlob(): GlobLoader | null {
54
+ const testGlob = (
55
+ globalThis as {
56
+ __iocConfigGlobForTests?: GlobLoader
57
+ }
58
+ ).__iocConfigGlobForTests
59
+
60
+ const viteGlob = (
61
+ import.meta as ImportMeta & {
62
+ glob?: GlobLoader
63
+ }
64
+ ).glob
65
+
66
+ return typeof testGlob === "function" ? testGlob : typeof viteGlob === "function" ? viteGlob : null
67
+ }
68
+
69
+ function configPatternForBasePath(basePath: string): string {
70
+ return basePath.endsWith("/") ? `${basePath}config/**/*.ts` : `${basePath}/config/**/*.ts`
71
+ }
72
+
73
+ export class EsmConfigLoader implements ConfigLoader {
74
+ load(basePath: string, staticItems: ConfigItems = {}): ConfigItems {
75
+ const shouldLoadEsm = Object.keys(staticItems).length === 0
76
+
77
+ const esmItems = shouldLoadEsm ? loadConfigFromModules(loadEsmConfigModules(basePath)) : {}
78
+
79
+ return { ...esmItems, ...cloneItems(staticItems) }
80
+ }
81
+ }
82
+
83
+ function createConfigRepository(
84
+ basePath: string,
85
+ staticItems: ConfigItems = {},
86
+ loader?: ConfigLoader,
87
+ ): ConfigRepository {
88
+ const configLoader = loader ?? new EsmConfigLoader()
89
+ const items = configLoader.load(basePath, staticItems)
90
+ return new ConfigRepository(items)
91
+ }
92
+
93
+ export const ConfigFactory = {
94
+ create: createConfigRepository,
95
+ }
96
+
97
+ export function createConfig(basePath: string, staticItems: ConfigItems = {}): ConfigRepository {
98
+ return ConfigFactory.create(basePath, staticItems)
99
+ }
@@ -0,0 +1,6 @@
1
+ declare global {
2
+ function env(key: string): import("./env").EnvValue | undefined
3
+ function env<T>(key: string, defaultValue: T): import("./env").EnvValue | T
4
+ }
5
+
6
+ export {}
@@ -0,0 +1,68 @@
1
+ export type EnvValue = string | number | boolean | null
2
+ type EnvMap = Record<string, EnvValue | undefined>
3
+ const normalizedEnvValues: Record<string, EnvValue> = {
4
+ "(empty)": "",
5
+ "(false)": false,
6
+ "(null)": null,
7
+ "(true)": true,
8
+ empty: "",
9
+ false: false,
10
+ null: null,
11
+ true: true,
12
+ }
13
+
14
+ function normalizeEnvValue(value: EnvValue | undefined): EnvValue | undefined {
15
+ if (typeof value !== "string") {
16
+ return value
17
+ }
18
+
19
+ const normalized = value.trim().toLowerCase()
20
+ return normalized in normalizedEnvValues ? normalizedEnvValues[normalized] : value
21
+ }
22
+
23
+ function resolveProcessEnv(): EnvMap {
24
+ const processValue = (globalThis as { process?: { env?: EnvMap } }).process
25
+
26
+ if (!processValue?.env) {
27
+ return {}
28
+ }
29
+
30
+ return processValue.env
31
+ }
32
+
33
+ function resolveImportMetaEnv(): EnvMap {
34
+ const testEnv = (
35
+ globalThis as {
36
+ __iocImportMetaEnvForTests?: EnvMap
37
+ }
38
+ ).__iocImportMetaEnvForTests
39
+ if (testEnv) {
40
+ return testEnv
41
+ }
42
+
43
+ const meta = import.meta as ImportMeta & { env?: EnvMap }
44
+ return meta.env ?? {}
45
+ }
46
+
47
+ export function env(key: string): EnvValue | undefined
48
+ export function env<T>(key: string, defaultValue: T): EnvValue | T
49
+ export function env<T>(key: string, defaultValue?: T): EnvValue | T | undefined {
50
+ const importMetaEnv = resolveImportMetaEnv()
51
+ if (key in importMetaEnv) {
52
+ return normalizeEnvValue(importMetaEnv[key])
53
+ }
54
+
55
+ const processEnv = resolveProcessEnv()
56
+ if (key in processEnv) {
57
+ return normalizeEnvValue(processEnv[key])
58
+ }
59
+
60
+ return defaultValue
61
+ }
62
+
63
+ export function registerGlobalEnv(): void {
64
+ const globalScope = globalThis as { env?: typeof env }
65
+ if (typeof globalScope.env !== "function") {
66
+ globalScope.env = env
67
+ }
68
+ }
@@ -0,0 +1,5 @@
1
+ export type { Contract as ConfigContract } from "./contract"
2
+ export { createConfig } from "./discovery"
3
+ export { env, registerGlobalEnv } from "./env"
4
+ export type { ConfigItems } from "./repository"
5
+ export { ConfigRepository } from "./repository"
@@ -0,0 +1,17 @@
1
+ import type { ServiceProviderContext } from "../support/service-provider"
2
+ import ServiceProvider from "../support/service-provider"
3
+ import ConfigRepository from "./repository"
4
+
5
+ export class ConfigProvider extends ServiceProvider {
6
+ protected readonly repository: ConfigRepository
7
+
8
+ constructor(repository: ConfigRepository) {
9
+ super()
10
+ this.repository = repository
11
+ }
12
+
13
+ register({ container }: ServiceProviderContext) {
14
+ container.instance("config", this.repository)
15
+ container.instance(ConfigRepository, this.repository)
16
+ }
17
+ }