@effected/app 0.13.2 → 0.15.0

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 (3) hide show
  1. package/AppConfig.js +20 -12
  2. package/index.d.ts +69 -13
  3. package/package.json +5 -5
package/AppConfig.js CHANGED
@@ -1,20 +1,29 @@
1
1
  import { badFilename } from "./internal/filename.js";
2
2
  import { AppDirs, XdgConfig } from "@effected/xdg";
3
3
  import { Effect, Layer } from "effect";
4
- import { ConfigFile, MergeStrategy } from "@effected/config-file";
4
+ import { ConfigFile, ConfigResolver, MergeStrategy } from "@effected/config-file";
5
5
 
6
6
  //#region src/AppConfig.ts
7
7
  const layer = (tag, options) => Layer.unwrap(Effect.gen(function* () {
8
8
  const invalid = badFilename("AppConfig.layer", options.filename);
9
9
  if (invalid !== void 0) return yield* Effect.die(invalid);
10
10
  const appDirs = yield* AppDirs;
11
+ const xdg = options.xdg !== false;
12
+ const systemEtc = options.systemEtc ?? false;
13
+ const systemEtcDir = typeof systemEtc === "object" ? systemEtc.dir : void 0;
11
14
  const resolvers = [
12
15
  ...options.resolvers ?? [],
13
- XdgConfig.resolver({ filename: options.filename }),
14
- ...options.native === false ? [] : [XdgConfig.nativeResolver({
16
+ ...xdg ? [XdgConfig.resolver({ filename: options.filename })] : [],
17
+ ...xdg && options.native !== false ? [XdgConfig.nativeResolver({
15
18
  namespace: appDirs.namespace,
16
19
  filename: options.filename
17
- })]
20
+ })] : [],
21
+ ...systemEtc === false ? [] : [ConfigResolver.systemEtc({
22
+ app: appDirs.namespace,
23
+ filename: options.filename,
24
+ ...systemEtcDir !== void 0 && { dir: systemEtcDir }
25
+ })],
26
+ ...options.resolversAfter ?? []
18
27
  ];
19
28
  return ConfigFile.layer(tag, {
20
29
  schema: options.schema,
@@ -52,14 +61,13 @@ var AppConfig = class {
52
61
  * config-file's infallible `defaultPath` slot without an `orDie` because xdg
53
62
  * resolves at layer-construction time.
54
63
  *
55
- * `options.resolvers` prepends to that chain, which covers the case this
56
- * preset otherwise could not: a CLI whose `--config` flag must outrank the
57
- * app's XDG search path. What it deliberately does not cover is a chain that
58
- * needs the XDG resolvers somewhere other than last, or no XDG resolvers at
59
- * all — an app wanting that composes `ConfigFile.layer` from
60
- * `@effected/config-file` directly and orders the whole chain itself, which
61
- * costs it only the `defaultPath` and ambient-namespace wiring this preset
62
- * does for free.
64
+ * The chain is caller-controlled at both ends: `options.resolvers` prepends,
65
+ * `options.resolversAfter` appends, `options.systemEtc` adds the `/etc`
66
+ * tier behind the XDG pair, and `options.xdg: false` removes the XDG pair
67
+ * altogether — at which point the chain is exactly the caller's own, and
68
+ * the preset is contributing the ambient namespace and `defaultPath` alone.
69
+ * Dropping to `ConfigFile.layer` directly is no longer the price of an
70
+ * unusual chain.
63
71
  *
64
72
  * **The namespace is never a parameter.** It is read from the ambient
65
73
  * `AppDirs` service at layer build time, so it is typed exactly once, in
package/index.d.ts CHANGED
@@ -25,7 +25,7 @@ interface AppCacheOptions extends CacheOptions {
25
25
  *
26
26
  * @public
27
27
  */
28
- declare class AppCache {
28
+ export declare class AppCache {
29
29
  private constructor();
30
30
  /**
31
31
  * Build the cache-directory database layer: `AppDirs.ensureCache`, then
@@ -67,7 +67,7 @@ interface AppStoreOptions extends StoreOptions {
67
67
  *
68
68
  * @public
69
69
  */
70
- declare class AppStore {
70
+ export declare class AppStore {
71
71
  private constructor();
72
72
  /**
73
73
  * Build the state-directory database layer: `AppDirs.ensureState`, then
@@ -141,7 +141,7 @@ interface AppTestOptions {
141
141
  *
142
142
  * @public
143
143
  */
144
- declare class App {
144
+ export declare class App {
145
145
  private constructor();
146
146
  /**
147
147
  * Build the application control plane: namespaced directories, the state
@@ -292,8 +292,65 @@ interface AppConfigOptions<A, I, RR = never> {
292
292
  * The native probe sits **after** the XDG resolver, so an existing
293
293
  * `~/.config/<app>` still beats the native directory; on Linux it resolves
294
294
  * to nothing and never touches the filesystem. Pass `false` to drop it.
295
+ *
296
+ * Ignored when `xdg` is `false`: the native probe is the tail of the XDG
297
+ * fallback chain, not an independent tier.
295
298
  */
296
299
  readonly native?: boolean;
300
+ /**
301
+ * Probe the app's XDG config search path. Defaults to `true`.
302
+ *
303
+ * @remarks
304
+ * Pass `false` to build the chain from `resolvers` (and `resolversAfter`,
305
+ * and `systemEtc`) alone. The case it exists for is a CLI's
306
+ * `--config <path>` branch, where a search-path fallback defeats the flag's
307
+ * purpose: without it, a `--config` naming a file that fails to resolve
308
+ * silently loads the user's XDG config instead.
309
+ *
310
+ * It drops **both** XDG resolvers — `XdgConfig.resolver` and, since it is
311
+ * documented as sitting behind it, `XdgConfig.nativeResolver`. `native` has
312
+ * no effect while `xdg` is `false`.
313
+ *
314
+ * `defaultPath` is unaffected: `save` still writes to
315
+ * `XdgConfig.savePath(filename)`. Dropping the *discovery* tier is not a
316
+ * statement about where this app saves its config.
317
+ */
318
+ readonly xdg?: boolean;
319
+ /**
320
+ * Append the system tier — `<dir>/<namespace>/<filename>`, `/etc` by
321
+ * default — after the XDG chain. Defaults to absent (no system tier).
322
+ *
323
+ * @remarks
324
+ * `true` uses `/etc`; an object overrides the system config root, which is
325
+ * chiefly how a test points the tier at a writable directory. The app name
326
+ * is the ambient `AppDirs` namespace, never a parameter — the same rule the
327
+ * XDG resolvers follow, so the two cannot drift apart.
328
+ *
329
+ * It is appended **after** the XDG pair because a machine-wide default must
330
+ * lose to a user's own config, which is the whole convention. A chain that
331
+ * wants the system tier somewhere else passes
332
+ * `ConfigResolver.systemEtc` through `resolvers` or `resolversAfter`
333
+ * instead and leaves this absent.
334
+ */
335
+ readonly systemEtc?: boolean | {
336
+ readonly dir?: string;
337
+ };
338
+ /**
339
+ * Resolvers composed **after** every built-in tier, in priority order —
340
+ * the lowest-priority end of the chain.
341
+ *
342
+ * @remarks
343
+ * The counterpart to `resolvers`, which prepends. Together the two make the
344
+ * whole chain caller-controlled without giving up what this preset does for
345
+ * free (the ambient namespace and `defaultPath`): the built-ins can be
346
+ * surrounded, and with `xdg: false` they can be removed entirely, at which
347
+ * point the chain is exactly `[...resolvers, ...resolversAfter]`.
348
+ *
349
+ * These come last, after the system tier, so a caller who needs a different
350
+ * order around `systemEtc` leaves that option absent and passes
351
+ * `ConfigResolver.systemEtc` here in the position it wants.
352
+ */
353
+ readonly resolversAfter?: ReadonlyArray<ConfigResolver<RR>>;
297
354
  }
298
355
  /**
299
356
  * The xdg-flavored `ConfigFile` preset: discovery through the app's XDG
@@ -308,7 +365,7 @@ interface AppConfigOptions<A, I, RR = never> {
308
365
  *
309
366
  * @public
310
367
  */
311
- declare class AppConfig {
368
+ export declare class AppConfig {
312
369
  private constructor();
313
370
  /**
314
371
  * Build the xdg-flavored config layer for a `ConfigFile.Service` class.
@@ -320,14 +377,13 @@ declare class AppConfig {
320
377
  * config-file's infallible `defaultPath` slot without an `orDie` because xdg
321
378
  * resolves at layer-construction time.
322
379
  *
323
- * `options.resolvers` prepends to that chain, which covers the case this
324
- * preset otherwise could not: a CLI whose `--config` flag must outrank the
325
- * app's XDG search path. What it deliberately does not cover is a chain that
326
- * needs the XDG resolvers somewhere other than last, or no XDG resolvers at
327
- * all — an app wanting that composes `ConfigFile.layer` from
328
- * `@effected/config-file` directly and orders the whole chain itself, which
329
- * costs it only the `defaultPath` and ambient-namespace wiring this preset
330
- * does for free.
380
+ * The chain is caller-controlled at both ends: `options.resolvers` prepends,
381
+ * `options.resolversAfter` appends, `options.systemEtc` adds the `/etc`
382
+ * tier behind the XDG pair, and `options.xdg: false` removes the XDG pair
383
+ * altogether — at which point the chain is exactly the caller's own, and
384
+ * the preset is contributing the ambient namespace and `defaultPath` alone.
385
+ * Dropping to `ConfigFile.layer` directly is no longer the price of an
386
+ * unusual chain.
331
387
  *
332
388
  * **The namespace is never a parameter.** It is read from the ambient
333
389
  * `AppDirs` service at layer build time, so it is typed exactly once, in
@@ -340,5 +396,5 @@ declare class AppConfig {
340
396
  static readonly layer: <Self, A, I, RR = never>(tag: Context.Key<Self, ConfigFileShape<A>>, options: AppConfigOptions<A, I, RR>) => Layer.Layer<Self, never, FileSystem.FileSystem | Path.Path | AppDirs | Xdg | RR>;
341
397
  }
342
398
  //#endregion
343
- export { App, AppCache, type AppCacheOptions, AppConfig, type AppConfigOptions, type AppError, type AppOptions, AppStore, type AppStoreOptions, type AppTestOptions };
399
+ export type { AppCacheOptions, AppConfigOptions, AppError, AppOptions, AppStoreOptions, AppTestOptions };
344
400
  //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effected/app",
3
- "version": "0.13.2",
3
+ "version": "0.15.0",
4
4
  "private": false,
5
5
  "description": "The application control plane for Effect: one layer wiring XDG-namespaced directories, a migrated SQLite store, a TTL cache and a config file to the same place.",
6
6
  "keywords": [
@@ -39,10 +39,10 @@
39
39
  "./package.json": "./package.json"
40
40
  },
41
41
  "peerDependencies": {
42
- "@effected/config-file": "^0.5.2",
43
- "@effected/store": "^0.6.0",
44
- "@effected/xdg": "^0.3.0",
45
- "effect": "4.0.0-rc.109"
42
+ "@effected/config-file": "^0.7.0",
43
+ "@effected/store": "^0.7.0",
44
+ "@effected/xdg": "^0.4.1",
45
+ "effect": "4.0.0-rc.112"
46
46
  },
47
47
  "engines": {
48
48
  "node": ">=24.11.0"