@fougere/defaults 0.6.0-alpha.0 → 0.7.0-alpha.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.
package/dist/index.d.ts CHANGED
@@ -1,13 +1,4 @@
1
- /**
2
- * @fougere/defaults — the conventional boot, declared once.
3
- *
4
- * Booting an app from `fougere.config.ts` means the same three opinionated
5
- * bindings every time: the container is `container`, `db: sqlite`
6
- * realizes through `schema-sql`, and `remotes:` are reached over
7
- * `transport-http`. core stays pure (it knows none of these); this layer-2
8
- * package supplies them on top of `core.boot()`. Nuxt's fallback, the CLI's
9
- * `serve`/`call`, and a standalone frond host are all projections of it.
10
- */
1
+ /** @fougere/defaults — the conventional boot, declared once. */
11
2
  import { type App, type CreateAppOptions } from '@fougere/core';
12
3
  export { resolveStorage, declaresStorage, storageFrom } from './storage.js';
13
4
  export type { DbConfig, SourcesConfig, DeclaredStorage, Placement, ResolvedStorage } from './storage.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAMhE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5E,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEzG,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,GAAG,CAAC,CAe7F"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAMhE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5E,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEzG,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,GAAG,CAAC,CAe7F"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAiB,MAAM,cAAc,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAkB5E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAY,EAAE,IAAI,GAAmB,EAAE;IAC7E,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;IACrC,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAE9E,OAAO,IAAI,CAAC;QACV,IAAI;QACJ,eAAe;QACf,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;QACzC,eAAe,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;QAC3E,wDAAwD;QACxD,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,EAAc,EAAG,GAA6B,CAAC,OAAgB,CAAC;QAChG,UAAU,EAAE,IAAI,CAAC,UAAU;KAC5B,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAiB,MAAM,cAAc,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAkB5E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAY,EAAE,IAAI,GAAmB,EAAE;IAC7E,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;IACrC,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAE9E,OAAO,IAAI,CAAC;QACV,IAAI;QACJ,eAAe;QACf,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;QACzC,eAAe,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;QAC3E,wDAAwD;QACxD,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,EAAc,EAAG,GAA6B,CAAC,OAAgB,CAAC;QAChG,UAAU,EAAE,IAAI,CAAC,UAAU;KAC5B,CAAC,CAAC;AACL,CAAC"}
package/dist/storage.d.ts CHANGED
@@ -1,13 +1,4 @@
1
- /**
2
- * Storage resolution — `config.db` → a working data layer.
3
- *
4
- * THE single place that names a storage package. Every host (the conventional
5
- * boot, the Nuxt fallback, the CLI's frond host) calls this instead of wiring an
6
- * engine itself; swapping the implementation is a change here and nowhere else.
7
- *
8
- * Before this existed, each host re-resolved `db: 'sqlite'` inline — which is
9
- * why an engine change looked like it touched seven files.
10
- */
1
+ /** Storage resolution — `config.db` → a working data layer. */
11
2
  import type { App } from '@fougere/core';
12
3
  import { type Source } from '@fougere/core';
13
4
  import '@fougere/adapter-sql/sqlite';
@@ -29,13 +20,8 @@ export interface ResolvedStorage {
29
20
  db?: unknown;
30
21
  storageFactory: ((entity: any, name: string) => any) | undefined;
31
22
  /**
32
- * The source an entity's rows live in — what decides whether a frame gets a real
33
- * transaction or an unwind it replays itself.
34
- *
35
- * Absent when the caller built a `ResolvedStorage` by hand: there is then one factory
36
- * and no routing, so every entity IS on one engine — but nothing here can reach into it
37
- * for a transaction, and a frame falls back to compensating. Not knowing and promising
38
- * atomicity are two different things.
23
+ * The source an entity's rows live in — what decides whether a frame gets a real transaction or
24
+ * an unwind it replays itself.
39
25
  */
40
26
  sourceOf?: (entityName: string) => string;
41
27
  /**
@@ -45,34 +31,21 @@ export interface ResolvedStorage {
45
31
  dbOf?: (source: string) => unknown;
46
32
  /** Every source that has an engine, the default one first. */
47
33
  sources?: () => string[];
34
+ /** Whether that source hands out a transaction — the dual of running one in it. */
35
+ transacts?: (source: string) => boolean;
48
36
  /** Run `fn` inside one transaction of that source, with a storage factory bound to it. */
49
37
  transacted?: <R>(source: string, fn: (storageFactory: (entity: any, name: string) => any) => Promise<R>) => Promise<R>;
50
38
  /**
51
39
  * Brings the schema up to date once the app is scanned — the storage's `up`, handed to
52
- * `migrating()`. It was called `afterBoot`, a word that also meant the host's own
53
- * post-boot and was read in four places under the two senses.
40
+ * `migrating()`.
54
41
  */
55
42
  migrate?: (app: App) => Promise<void> | void;
56
- /**
57
- * Close every engine this opened — the dual of opening them, declared by whoever did.
58
- *
59
- * `boot()` calls the factory that lands here, so `boot()` is what owns closing it: a
60
- * container disposes what IT built, and this connection was handed in. Without this
61
- * the pool of a discarded app stayed open, which is what turning the ring makes
62
- * ordinary rather than rare.
63
- */
43
+ /** Close every engine this opened — the dual of opening them, declared by whoever did. */
64
44
  close?: () => Promise<void>;
65
45
  }
66
46
  /** Does this config ask for persistence at all? */
67
47
  export declare function declaresStorage(dbConf: DbConfig): boolean;
68
- /**
69
- * Resolve the data layer. `db: false` (or absent) means a frond with no
70
- * persistence of its own — the caller decides what to fall back to.
71
- *
72
- * `sources` names the places that are NOT the default one. An entity it does not
73
- * name stays in `db`, so an app with one database declares nothing and behaves
74
- * exactly as before.
75
- */
48
+ /** Resolve the data layer. */
76
49
  export declare function resolveStorage(dbConf: DbConfig, sources?: SourcesConfig): ResolvedStorage;
77
50
  /** One source: what realizes it, and the entities that live there. */
78
51
  export interface Placement {
@@ -85,26 +58,6 @@ export interface DeclaredStorage {
85
58
  /** The other places. Absent means one source, the way it always was. */
86
59
  sources?: Record<string, Placement>;
87
60
  }
88
- /**
89
- * The same routing `resolveStorage` performs, over engines the CALLER built.
90
- *
91
- * `resolveStorage` reads a config file, and a config file cannot hold a live Kysely
92
- * dialect — so it can only ever resolve sqlite, the one driver this package depends
93
- * on. That was fine while `db:` was alone, because the escape hatch was to abandon
94
- * the convention entirely and hand `configureFougere` your own factory. With several
95
- * sources that stopped being an escape: a user wanting Postgres for ONE of them had
96
- * to re-implement the routing and the per-source migration to keep the other.
97
- *
98
- * So the two jobs are separated. Resolving a NAME into an engine is sqlite-only and
99
- * stays there; placing entities and migrating each source is engine-agnostic and
100
- * lives here, where any `Setup` is welcome:
101
- *
102
- * ```ts
103
- * configureFougere(storageFrom({
104
- * db: setupSqlite({ path: '.data/app.db' }),
105
- * sources: { legacy: { setup: setupKysely(pgDialect, 'postgres'), entities: ['Book'] } },
106
- * }));
107
- * ```
108
- */
61
+ /** The same routing `resolveStorage` performs, over engines the CALLER built. */
109
62
  export declare function storageFrom(declared: DeclaredStorage): ResolvedStorage;
110
63
  //# sourceMappingURL=storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAGzC,OAAO,EAAW,KAAK,MAAM,EAAmB,MAAM,eAAe,CAAC;AAEtE,OAAO,6BAA6B,CAAC;AAErC,8DAA8D;AAC9D,MAAM,MAAM,QAAQ,GAChB,KAAK,GACL,QAAQ,GACR;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD,SAAS,CAAC;AAEd,yFAAyF;AACzF,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,GAAG,SAAS,CAAC;AAEjI,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,GAAG,CAAC,GAAG,SAAS,CAAC;IACjE;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,MAAM,EAAE,CAAC;IACzB,0FAA0F;IAC1F,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACvH;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC7C;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAE7B;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAGzD;AAoCD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,eAAe,CAWzF;AAyBD,sEAAsE;AACtE,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,eAAe,CA+DtE"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAGzC,OAAO,EAAW,KAAK,MAAM,EAAmB,MAAM,eAAe,CAAC;AAEtE,OAAO,6BAA6B,CAAC;AAErC,8DAA8D;AAC9D,MAAM,MAAM,QAAQ,GAChB,KAAK,GACL,QAAQ,GACR;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD,SAAS,CAAC;AAEd,yFAAyF;AACzF,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,GAAG,SAAS,CAAC;AAEjI,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,GAAG,CAAC,GAAG,SAAS,CAAC;IACjE;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,MAAM,EAAE,CAAC;IACzB,mFAAmF;IACnF,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,0FAA0F;IAC1F,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACvH;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC7C,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAE7B;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAGzD;AAyBD,8BAA8B;AAC9B,wBAAgB,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,eAAe,CAWzF;AAYD,sEAAsE;AACtE,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrC;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,eAAe,CAkEtE"}
package/dist/storage.js CHANGED
@@ -9,18 +9,7 @@ export function declaresStorage(dbConf) {
9
9
  return false;
10
10
  return true;
11
11
  }
12
- /**
13
- * The app as ONE source sees it: the entities that live there, and the names of those
14
- * that do not.
15
- *
16
- * The second half is what lets the DDL stop lying. A batch holding every entity could
17
- * never tell a cross-source target from a typo, so it derived a table name and emitted
18
- * a foreign key against a table that may not exist. Cut per source, `elsewhere` says
19
- * which misses are legitimate — and a target in neither list is a mistake, out loud.
20
- *
21
- * Auth entities ride with the default source: a provider's tables are the app's own,
22
- * and nothing yet lets one declare where it lives.
23
- */
12
+ /** The app as ONE source sees it. */
24
13
  function viewOf(app, holds, withAuth) {
25
14
  const typed = app;
26
15
  const fronds = typed.fronds
@@ -34,14 +23,7 @@ function viewOf(app, holds, withAuth) {
34
23
  elsewhere: Fronds.hosting(typed.fronds).entityNames().filter((name) => !holds(name)),
35
24
  };
36
25
  }
37
- /**
38
- * Resolve the data layer. `db: false` (or absent) means a frond with no
39
- * persistence of its own — the caller decides what to fall back to.
40
- *
41
- * `sources` names the places that are NOT the default one. An entity it does not
42
- * name stays in `db`, so an app with one database declares nothing and behaves
43
- * exactly as before.
44
- */
26
+ /** Resolve the data layer. */
45
27
  export function resolveStorage(dbConf, sources) {
46
28
  if (!declaresStorage(dbConf))
47
29
  return { storageFactory: undefined };
@@ -54,45 +36,14 @@ export function resolveStorage(dbConf, sources) {
54
36
  sources: named,
55
37
  });
56
38
  }
57
- /**
58
- * One config entry, resolved to the adapter it names.
59
- *
60
- * `source:` defaults to `'sql'` — the convention a first run meets, and the reason a config
61
- * saying only `db: 'sqlite'` keeps working. What the entry says BELOW that key belongs to the
62
- * adapter it named, which is also the only one that can refuse it: this function knows no
63
- * dialect and no driver.
64
- */
39
+ /** One config entry, resolved to the adapter it names. */
65
40
  function built(conf, field) {
66
41
  const name = conf.source ?? DEFAULT_ADAPTER;
67
- if (!Sources.answers(name)) {
68
- throw new Error(`${field}.source '${name}' is not answered — import the adapter that does. `
69
- + `This process answers ${Sources.answered().join(', ') || 'nothing yet'}.`);
70
- }
71
- return Sources.resolve(name, conf);
42
+ return Sources.open(name, conf, `${field}.source`);
72
43
  }
73
44
  /** What a config naming no adapter means. */
74
45
  const DEFAULT_ADAPTER = 'sql';
75
- /**
76
- * The same routing `resolveStorage` performs, over engines the CALLER built.
77
- *
78
- * `resolveStorage` reads a config file, and a config file cannot hold a live Kysely
79
- * dialect — so it can only ever resolve sqlite, the one driver this package depends
80
- * on. That was fine while `db:` was alone, because the escape hatch was to abandon
81
- * the convention entirely and hand `configureFougere` your own factory. With several
82
- * sources that stopped being an escape: a user wanting Postgres for ONE of them had
83
- * to re-implement the routing and the per-source migration to keep the other.
84
- *
85
- * So the two jobs are separated. Resolving a NAME into an engine is sqlite-only and
86
- * stays there; placing entities and migrating each source is engine-agnostic and
87
- * lives here, where any `Setup` is welcome:
88
- *
89
- * ```ts
90
- * configureFougere(storageFrom({
91
- * db: setupSqlite({ path: '.data/app.db' }),
92
- * sources: { legacy: { setup: setupKysely(pgDialect, 'postgres'), entities: ['Book'] } },
93
- * }));
94
- * ```
95
- */
46
+ /** The same routing `resolveStorage` performs, over engines the CALLER built. */
96
47
  export function storageFrom(declared) {
97
48
  const { db: base, sources } = declared;
98
49
  // Where each named entity lives. An entity claimed by two sources is refused naming
@@ -127,16 +78,19 @@ export function storageFrom(declared) {
127
78
  sourceOf,
128
79
  dbOf: (source) => engineOf(source)?.db,
129
80
  sources: () => [DEFAULT, ...engines.keys()],
130
- // A source that hands out no transaction leaves the key absent, and a frame reads the
131
- // absence: `boot/together.ts` compensates instead, and says which of the two it built.
132
- transacted: base.transacted ? async (source, fn) => {
81
+ // Asked of the source that will run the work, never of the default one: a frame whose
82
+ // members all live in a transactional source gets its transaction even when `db:` has
83
+ // none. A source that hands out none leaves the answer `false`, and a frame reads it:
84
+ // `boot/together.ts` compensates instead, and says which of the two it built.
85
+ transacts: (source) => engineOf(source)?.transacted !== undefined,
86
+ transacted: async (source, fn) => {
133
87
  const engine = engineOf(source);
134
88
  if (!engine)
135
89
  throw new Error(`No source named '${source}' — declared sources are ${[DEFAULT, ...engines.keys()].join(', ')}.`);
136
90
  if (!engine.transacted)
137
91
  throw new Error(`Source '${source}' hands out no transaction.`);
138
92
  return engine.transacted(fn);
139
- } : undefined,
93
+ },
140
94
  // One pass per source, each seeing only its own entities and the NAMES of the others —
141
95
  // which is what makes a cross-source `ref()` a miss rather than a constraint against a
142
96
  // stranger. What a pass DOES is the source's own: it knows its engine, this does not.
@@ -1 +1 @@
1
- {"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fougere/defaults",
3
- "version": "0.6.0-alpha.0",
3
+ "version": "0.7.0-alpha.0",
4
4
  "description": "The conventional boot of a Fougere app — the one place storage is wired.",
5
5
  "keywords": [
6
6
  "fougere",
@@ -29,10 +29,10 @@
29
29
  "src"
30
30
  ],
31
31
  "dependencies": {
32
- "@fougere/core": "0.6.0-alpha.0",
33
- "@fougere/container": "0.6.0-alpha.0",
34
- "@fougere/adapter-sql": "0.6.0-alpha.0",
35
- "@fougere/transport-http": "0.6.0-alpha.0"
32
+ "@fougere/core": "0.7.0-alpha.0",
33
+ "@fougere/adapter-sql": "0.7.0-alpha.0",
34
+ "@fougere/container": "0.7.0-alpha.0",
35
+ "@fougere/transport-http": "0.7.0-alpha.0"
36
36
  },
37
37
  "publishConfig": {
38
38
  "access": "public"
@@ -41,7 +41,7 @@
41
41
  "kysely": "^0.28.17",
42
42
  "better-sqlite3": "^13.0.3",
43
43
  "@types/better-sqlite3": "^7.6.13",
44
- "@fougere/schema": "0.6.0-alpha.0"
44
+ "@fougere/schema": "0.7.0-alpha.0"
45
45
  },
46
46
  "scripts": {
47
47
  "build": "rm -rf dist && tsc",
package/src/index.ts CHANGED
@@ -1,13 +1,4 @@
1
- /**
2
- * @fougere/defaults — the conventional boot, declared once.
3
- *
4
- * Booting an app from `fougere.config.ts` means the same three opinionated
5
- * bindings every time: the container is `container`, `db: sqlite`
6
- * realizes through `schema-sql`, and `remotes:` are reached over
7
- * `transport-http`. core stays pure (it knows none of these); this layer-2
8
- * package supplies them on top of `core.boot()`. Nuxt's fallback, the CLI's
9
- * `serve`/`call`, and a standalone frond host are all projections of it.
10
- */
1
+ /** @fougere/defaults — the conventional boot, declared once. */
11
2
  import { type App, type CreateAppOptions } from '@fougere/core';
12
3
  import { boot, loadConfig } from '@fougere/core/node';
13
4
  import { createContainer } from '@fougere/container';
package/src/storage.ts CHANGED
@@ -1,13 +1,4 @@
1
- /**
2
- * Storage resolution — `config.db` → a working data layer.
3
- *
4
- * THE single place that names a storage package. Every host (the conventional
5
- * boot, the Nuxt fallback, the CLI's frond host) calls this instead of wiring an
6
- * engine itself; swapping the implementation is a change here and nowhere else.
7
- *
8
- * Before this existed, each host re-resolved `db: 'sqlite'` inline — which is
9
- * why an engine change looked like it touched seven files.
10
- */
1
+ /** Storage resolution — `config.db` → a working data layer. */
11
2
  import type { App } from '@fougere/core';
12
3
  import { Fronds, type FrondDescriptor } from '@fougere/core';
13
4
  import { lowerFirst } from '@fougere/core/contract';
@@ -30,13 +21,8 @@ export interface ResolvedStorage {
30
21
  db?: unknown;
31
22
  storageFactory: ((entity: any, name: string) => any) | undefined;
32
23
  /**
33
- * The source an entity's rows live in — what decides whether a frame gets a real
34
- * transaction or an unwind it replays itself.
35
- *
36
- * Absent when the caller built a `ResolvedStorage` by hand: there is then one factory
37
- * and no routing, so every entity IS on one engine — but nothing here can reach into it
38
- * for a transaction, and a frame falls back to compensating. Not knowing and promising
39
- * atomicity are two different things.
24
+ * The source an entity's rows live in — what decides whether a frame gets a real transaction or
25
+ * an unwind it replays itself.
40
26
  */
41
27
  sourceOf?: (entityName: string) => string;
42
28
  /**
@@ -46,22 +32,16 @@ export interface ResolvedStorage {
46
32
  dbOf?: (source: string) => unknown;
47
33
  /** Every source that has an engine, the default one first. */
48
34
  sources?: () => string[];
35
+ /** Whether that source hands out a transaction — the dual of running one in it. */
36
+ transacts?: (source: string) => boolean;
49
37
  /** Run `fn` inside one transaction of that source, with a storage factory bound to it. */
50
38
  transacted?: <R>(source: string, fn: (storageFactory: (entity: any, name: string) => any) => Promise<R>) => Promise<R>;
51
39
  /**
52
40
  * Brings the schema up to date once the app is scanned — the storage's `up`, handed to
53
- * `migrating()`. It was called `afterBoot`, a word that also meant the host's own
54
- * post-boot and was read in four places under the two senses.
41
+ * `migrating()`.
55
42
  */
56
43
  migrate?: (app: App) => Promise<void> | void;
57
- /**
58
- * Close every engine this opened — the dual of opening them, declared by whoever did.
59
- *
60
- * `boot()` calls the factory that lands here, so `boot()` is what owns closing it: a
61
- * container disposes what IT built, and this connection was handed in. Without this
62
- * the pool of a discarded app stayed open, which is what turning the ring makes
63
- * ordinary rather than rare.
64
- */
44
+ /** Close every engine this opened — the dual of opening them, declared by whoever did. */
65
45
  close?: () => Promise<void>;
66
46
  /** Raw synchronous handle, when the engine exposes one. */
67
47
  }
@@ -73,18 +53,7 @@ export function declaresStorage(dbConf: DbConfig): boolean {
73
53
  }
74
54
 
75
55
 
76
- /**
77
- * The app as ONE source sees it: the entities that live there, and the names of those
78
- * that do not.
79
- *
80
- * The second half is what lets the DDL stop lying. A batch holding every entity could
81
- * never tell a cross-source target from a typo, so it derived a table name and emitted
82
- * a foreign key against a table that may not exist. Cut per source, `elsewhere` says
83
- * which misses are legitimate — and a target in neither list is a mistake, out loud.
84
- *
85
- * Auth entities ride with the default source: a provider's tables are the app's own,
86
- * and nothing yet lets one declare where it lives.
87
- */
56
+ /** The app as ONE source sees it. */
88
57
  function viewOf(
89
58
  app: App,
90
59
  holds: (name: string) => boolean,
@@ -106,14 +75,7 @@ function viewOf(
106
75
  };
107
76
  }
108
77
 
109
- /**
110
- * Resolve the data layer. `db: false` (or absent) means a frond with no
111
- * persistence of its own — the caller decides what to fall back to.
112
- *
113
- * `sources` names the places that are NOT the default one. An entity it does not
114
- * name stays in `db`, so an app with one database declares nothing and behaves
115
- * exactly as before.
116
- */
78
+ /** Resolve the data layer. */
117
79
  export function resolveStorage(dbConf: DbConfig, sources?: SourcesConfig): ResolvedStorage {
118
80
  if (!declaresStorage(dbConf)) return { storageFactory: undefined };
119
81
 
@@ -127,24 +89,11 @@ export function resolveStorage(dbConf: DbConfig, sources?: SourcesConfig): Resol
127
89
  });
128
90
  }
129
91
 
130
- /**
131
- * One config entry, resolved to the adapter it names.
132
- *
133
- * `source:` defaults to `'sql'` — the convention a first run meets, and the reason a config
134
- * saying only `db: 'sqlite'` keeps working. What the entry says BELOW that key belongs to the
135
- * adapter it named, which is also the only one that can refuse it: this function knows no
136
- * dialect and no driver.
137
- */
92
+ /** One config entry, resolved to the adapter it names. */
138
93
  function built(conf: Record<string, unknown>, field: string): Source {
139
94
  const name = (conf.source as string | undefined) ?? DEFAULT_ADAPTER;
140
- if (!Sources.answers(name)) {
141
- throw new Error(
142
- `${field}.source '${name}' is not answered — import the adapter that does. `
143
- + `This process answers ${Sources.answered().join(', ') || 'nothing yet'}.`,
144
- );
145
- }
146
95
 
147
- return Sources.resolve(name, conf as never);
96
+ return Sources.open(name, conf as never, `${field}.source`);
148
97
  }
149
98
 
150
99
  /** What a config naming no adapter means. */
@@ -163,27 +112,7 @@ export interface DeclaredStorage {
163
112
  sources?: Record<string, Placement>;
164
113
  }
165
114
 
166
- /**
167
- * The same routing `resolveStorage` performs, over engines the CALLER built.
168
- *
169
- * `resolveStorage` reads a config file, and a config file cannot hold a live Kysely
170
- * dialect — so it can only ever resolve sqlite, the one driver this package depends
171
- * on. That was fine while `db:` was alone, because the escape hatch was to abandon
172
- * the convention entirely and hand `configureFougere` your own factory. With several
173
- * sources that stopped being an escape: a user wanting Postgres for ONE of them had
174
- * to re-implement the routing and the per-source migration to keep the other.
175
- *
176
- * So the two jobs are separated. Resolving a NAME into an engine is sqlite-only and
177
- * stays there; placing entities and migrating each source is engine-agnostic and
178
- * lives here, where any `Setup` is welcome:
179
- *
180
- * ```ts
181
- * configureFougere(storageFrom({
182
- * db: setupSqlite({ path: '.data/app.db' }),
183
- * sources: { legacy: { setup: setupKysely(pgDialect, 'postgres'), entities: ['Book'] } },
184
- * }));
185
- * ```
186
- */
115
+ /** The same routing `resolveStorage` performs, over engines the CALLER built. */
187
116
  export function storageFrom(declared: DeclaredStorage): ResolvedStorage {
188
117
  const { db: base, sources } = declared;
189
118
 
@@ -223,14 +152,17 @@ export function storageFrom(declared: DeclaredStorage): ResolvedStorage {
223
152
  sourceOf,
224
153
  dbOf: (source) => (engineOf(source) as { db?: unknown } | undefined)?.db,
225
154
  sources: () => [DEFAULT, ...engines.keys()],
226
- // A source that hands out no transaction leaves the key absent, and a frame reads the
227
- // absence: `boot/together.ts` compensates instead, and says which of the two it built.
228
- transacted: base.transacted ? async (source, fn) => {
155
+ // Asked of the source that will run the work, never of the default one: a frame whose
156
+ // members all live in a transactional source gets its transaction even when `db:` has
157
+ // none. A source that hands out none leaves the answer `false`, and a frame reads it:
158
+ // `boot/together.ts` compensates instead, and says which of the two it built.
159
+ transacts: (source) => engineOf(source)?.transacted !== undefined,
160
+ transacted: async (source, fn) => {
229
161
  const engine = engineOf(source);
230
162
  if (!engine) throw new Error(`No source named '${source}' — declared sources are ${[DEFAULT, ...engines.keys()].join(', ')}.`);
231
163
  if (!engine.transacted) throw new Error(`Source '${source}' hands out no transaction.`);
232
164
  return engine.transacted(fn);
233
- } : undefined,
165
+ },
234
166
  // One pass per source, each seeing only its own entities and the NAMES of the others —
235
167
  // which is what makes a cross-source `ref()` a miss rather than a constraint against a
236
168
  // stranger. What a pass DOES is the source's own: it knows its engine, this does not.