Hyperlinkv0.9.0-beta.0

DynamicConfig

DynamicConfig.layerconstsrc/DynamicConfig.ts:646
(
  config?: FieldRecord | ConfigField<unknown>
): Layer.Layer<DynamicConfigStore>

Provide the override store and a ConfigProvider (reads swaps first, then the real environment). The setByKey allowlist is the process-wide SwappableRegistry (every globalSwappable) plus — when you pass config (a bag from make / extend, or a lone swappable field) — that config's own swappable keys, scoped to this provision. Provide once, at or above any scope that reads or swaps; scoping (Effect.scoped) and forked fibers inherit it. Separate runtimes get their own store.

export const layer = (
  config?: FieldRecord | ConfigField<unknown>,
): Layer.Layer<DynamicConfigStore> =>
  Layer.unwrap(
    Effect.gen(function* () {
      const overrides = yield* SubscriptionRef.make(new Map<string, string>());

      const provider = ConfigProvider.make((path) =>
        Effect.map(SubscriptionRef.get(overrides), (map) => {
          const value = map.get(path.join("_"));
          return value === undefined
            ? undefined
            : ConfigProvider.makeValue(value);
        }),
      );

      // allowlist = the process-wide registry, plus this config's own swappable keys.
      const allowed = new Map<string, Config.Config<unknown>>(
        yield* SwappableRegistry,
      );
      if (config !== undefined) {
        for (const field of fieldsOf(config)) {
          if (isSwappableField(field)) {
            for (const key of metaOf(field).envKeys) {
              allowed.set(key, field.config);
            }
          }
        }
      }

      const store = DynamicConfigStore.of({
        setRaw: (entries) =>
          SubscriptionRef.update(overrides, (map) => {
            const next = new Map(map);
            for (const [key, value] of entries) {
              next.set(key, value);
            }
            return next;
          }),
        unsetRaw: (keys) =>
          SubscriptionRef.update(overrides, (map) => {
            const next = new Map(map);
            for (const key of keys) {
              next.delete(key);
            }
            return next;
          }),
        changedKeys: Stream.map(SubscriptionRef.changes(overrides), (map) =>
          Array.from(map.keys()),
        ),
        allowed,
      });

      return Layer.merge(
        ConfigProvider.layer(
          ConfigProvider.orElse(provider, ConfigProvider.fromEnv()),
        ),
        Layer.succeed(DynamicConfigStore, store),
      );
    }),
  );