@fougere/defaults 0.19.1-alpha.0 → 0.20.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/README.md +3 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/storage/DeclaredStorage.d.ts +2 -10
- package/dist/storage/DeclaredStorage.d.ts.map +1 -1
- package/dist/storage/DeclaredStorage.js +2 -4
- package/dist/storage/DeclaredStorage.js.map +1 -1
- package/dist/storage/ResolvedStorage.d.ts +8 -10
- package/dist/storage/ResolvedStorage.d.ts.map +1 -1
- package/dist/storage/ResolvedStorage.js +35 -35
- package/dist/storage/ResolvedStorage.js.map +1 -1
- package/dist/storage/SourceEntities.d.ts +2 -2
- package/dist/storage/SourceEntities.d.ts.map +1 -1
- package/package.json +9 -9
- package/src/index.ts +3 -4
- package/src/storage/DeclaredStorage.ts +3 -14
- package/src/storage/ResolvedStorage.ts +40 -45
- package/src/storage/SourceEntities.ts +2 -2
- package/dist/storage/DbConfig.d.ts +0 -7
- package/dist/storage/DbConfig.d.ts.map +0 -1
- package/dist/storage/DbConfig.js +0 -2
- package/dist/storage/DbConfig.js.map +0 -1
- package/dist/storage/SourcesConfig.d.ts +0 -8
- package/dist/storage/SourcesConfig.d.ts.map +0 -1
- package/dist/storage/SourcesConfig.js +0 -2
- package/dist/storage/SourcesConfig.js.map +0 -1
- package/src/storage/DbConfig.ts +0 -6
- package/src/storage/SourcesConfig.ts +0 -2
package/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# @fougere/defaults
|
|
2
2
|
> The conventional boot
|
|
3
|
-
`bootApp()` and `resolveStorage()` — **the single** place that names
|
|
4
|
-
|
|
3
|
+
`bootApp()` and `resolveStorage()` — **the single** place that reads `sources:`. It names no
|
|
4
|
+
engine: the config imports the adapters it uses, and memory, the fallback for an app that
|
|
5
|
+
declares no source, is the only one it brings.
|
|
5
6
|
|
|
6
7
|
## Installation
|
|
7
8
|
```bash
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type App, type CreateAppOptions } from '@fougere/core';
|
|
|
3
3
|
export { remoteTransport } from './transport/RemoteTransport.js';
|
|
4
4
|
export { declaresStorage } from './storage/DeclaredStorage.js';
|
|
5
5
|
export { layerOf, resolveStorage, storageFrom } from './storage/ResolvedStorage.js';
|
|
6
|
-
export type {
|
|
6
|
+
export type { SourceEntities } from './storage/SourceEntities.js';
|
|
7
7
|
export type { ResolvedStorage } from './storage/ResolvedStorage.js';
|
|
8
8
|
export interface BootAppOptions {
|
|
9
9
|
/** Boot only these fronds, by name. Absent = every discovered frond. */
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,OAAO,EAAa,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,OAAO,EAAa,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAM3E,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACpF,YAAY,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,YAAY,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAC5C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,GAAG,CAAC,CAmBnF"}
|
package/dist/index.js
CHANGED
|
@@ -25,8 +25,8 @@ export async function bootApp(root, opts = {}) {
|
|
|
25
25
|
// `{}` and never undefined: `boot` reads the config's own `fronds:` when handed nothing.
|
|
26
26
|
remotes: useRemotes ? elsewhere : {},
|
|
27
27
|
remoteTransport: useRemotes ? await remoteTransport() : undefined,
|
|
28
|
-
// One resolver, one place that
|
|
29
|
-
|
|
28
|
+
// One resolver, one place that reads `sources:`.
|
|
29
|
+
storage: (cfg) => (storage = resolveStorage(cfg.sources, root)),
|
|
30
30
|
extensions: [...(opts.migrates ? [migrating((app) => storage?.migrate?.(app))] : []), ...(opts.extensions ?? [])],
|
|
31
31
|
});
|
|
32
32
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,OAAO,EAAE,SAAS,EAAmC,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,OAAO,EAAE,SAAS,EAAmC,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAwB,MAAM,8BAA8B,CAAC;AACpF,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEjE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAsBpF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAY,EAAE,IAAI,GAAmB,EAAE;IACnE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACtC,2FAA2F;IAC3F,sFAAsF;IACtF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAChH,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACrD,IAAI,OAAoC,CAAC;IAEzC,OAAO,IAAI,CAAC;QACV,IAAI;QACJ,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM;QAC9B,yFAAyF;QACzF,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;QACpC,eAAe,EAAE,UAAU,CAAC,CAAC,CAAC,MAAM,eAAe,EAAE,CAAC,CAAC,CAAC,SAAS;QACjE,iDAAiD;QACjD,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC/D,UAAU,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;KAClH,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { DbConfig } from './DbConfig.js';
|
|
3
|
-
import type { SourceEntities } from './SourceEntities.js';
|
|
1
|
+
import type { SourceConfig } from '@fougere/core';
|
|
4
2
|
/** Does this config ask for persistence at all? */
|
|
5
|
-
export declare function declaresStorage(
|
|
6
|
-
export interface DeclaredStorage {
|
|
7
|
-
/** The default source — where an entity no placement names lands. */
|
|
8
|
-
db: Source;
|
|
9
|
-
/** The other places. Absent means one source, the way it always was. */
|
|
10
|
-
sources?: Record<string, SourceEntities>;
|
|
11
|
-
}
|
|
3
|
+
export declare function declaresStorage(sources: Record<string, SourceConfig> | undefined): boolean;
|
|
12
4
|
//# sourceMappingURL=DeclaredStorage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeclaredStorage.d.ts","sourceRoot":"","sources":["../../src/storage/DeclaredStorage.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"DeclaredStorage.d.ts","sourceRoot":"","sources":["../../src/storage/DeclaredStorage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,SAAS,GAAG,OAAO,CAE1F"}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/** Does this config ask for persistence at all? */
|
|
2
|
-
export function declaresStorage(
|
|
3
|
-
|
|
4
|
-
return false;
|
|
5
|
-
return true;
|
|
2
|
+
export function declaresStorage(sources) {
|
|
3
|
+
return Object.keys(sources ?? {}).length > 0;
|
|
6
4
|
}
|
|
7
5
|
//# sourceMappingURL=DeclaredStorage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeclaredStorage.js","sourceRoot":"","sources":["../../src/storage/DeclaredStorage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DeclaredStorage.js","sourceRoot":"","sources":["../../src/storage/DeclaredStorage.ts"],"names":[],"mappings":"AAEA,mDAAmD;AACnD,MAAM,UAAU,eAAe,CAAC,OAAiD;IAC/E,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import '@fougere/adapter-sql/sqlite';
|
|
2
1
|
import type { App } from '@fougere/core';
|
|
3
|
-
import { type Constraint } from '@fougere/core';
|
|
4
|
-
import type {
|
|
5
|
-
import type { SourcesConfig } from './SourcesConfig.js';
|
|
6
|
-
import type { DeclaredStorage } from './DeclaredStorage.js';
|
|
2
|
+
import { type Constraint, type SourceConfig } from '@fougere/core';
|
|
3
|
+
import type { SourceEntities } from './SourceEntities.js';
|
|
7
4
|
export interface ResolvedStorage {
|
|
8
|
-
/** The default source's engine handle — what `fougere migrate` reads the live tables through. */
|
|
9
|
-
db?: unknown;
|
|
10
5
|
storageFactory: ((entity: any, name: string) => any) | undefined;
|
|
11
6
|
/**
|
|
12
7
|
* The source an entity's rows live in — what decides whether a frame gets a real transaction or
|
|
@@ -36,8 +31,11 @@ export interface ResolvedStorage {
|
|
|
36
31
|
/** Close every engine this opened — the dual of opening them, declared by whoever did. */
|
|
37
32
|
close?: () => Promise<void>;
|
|
38
33
|
}
|
|
39
|
-
/**
|
|
40
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Resolve the data layer from `sources:`. The one entry listing no entities holds the rest; none
|
|
36
|
+
* at all keeps the rows in memory, and saying so is the whole fallback.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveStorage(sources: Record<string, SourceConfig> | undefined,
|
|
41
39
|
/**
|
|
42
40
|
* Where a relative `path:` is counted from — the directory of the config that named it.
|
|
43
41
|
*
|
|
@@ -49,7 +47,7 @@ export declare function resolveStorage(dbConf: DbConfig, sources?: SourcesConfig
|
|
|
49
47
|
*/
|
|
50
48
|
root?: string): ResolvedStorage;
|
|
51
49
|
/** The same routing `resolveStorage` performs, over engines the CALLER built. */
|
|
52
|
-
export declare function storageFrom(
|
|
50
|
+
export declare function storageFrom(sources: Record<string, SourceEntities>): ResolvedStorage;
|
|
53
51
|
/**
|
|
54
52
|
* The data layer as `createApp` takes it — one gesture, not eight named by hand.
|
|
55
53
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResolvedStorage.d.ts","sourceRoot":"","sources":["../../src/storage/ResolvedStorage.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ResolvedStorage.d.ts","sourceRoot":"","sources":["../../src/storage/ResolvedStorage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAIzC,OAAO,EAAiC,KAAK,UAAU,EAAe,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAE/G,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC9B,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,kGAAkG;IAClG,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC;IAC/D,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,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/C,0FAA0F;IAC1F,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1C,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAE7B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,SAAS;AACjD;;;;;;;;GAQG;AACH,IAAI,CAAC,EAAE,MAAM,GACZ,eAAe,CAQjB;AA8CD,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,eAAe,CAmFpF;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,eAAe;IAE5C,cAAc,YApMU,GAAG,QAAQ,MAAM,KAAK,GAAG;IAqMjD,QAAQ,gBAhMc,MAAM,KAAK,MAAM;IAiMvC,SAAS,YAxLU,MAAM,KAAK,OAAO;IAyLrC,QAAQ,YAvLU,MAAM,cAAc,UAAU,KAAK,OAAO;IAwL5D,UAAU,EAAwB,KAAK;IACvC,OAAO,SAhLO,GAAG,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;EAkL1C"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import '@fougere/adapter-sql/sqlite';
|
|
2
1
|
import { lowerFirst } from '@fougere/core/contract';
|
|
3
2
|
import { existsSync } from 'node:fs';
|
|
4
3
|
import { isAbsolute, resolve } from 'node:path';
|
|
5
4
|
import { Logger, Sources, sourceViewOf } from '@fougere/core';
|
|
6
5
|
import { createMemorySource } from '@fougere/adapter-memory';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the data layer from `sources:`. The one entry listing no entities holds the rest; none
|
|
8
|
+
* at all keeps the rows in memory, and saying so is the whole fallback.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveStorage(sources,
|
|
10
11
|
/**
|
|
11
12
|
* Where a relative `path:` is counted from — the directory of the config that named it.
|
|
12
13
|
*
|
|
@@ -17,33 +18,21 @@ export function resolveStorage(dbConf, sources,
|
|
|
17
18
|
* seeds ran, and the app served an empty domain with a green boot.
|
|
18
19
|
*/
|
|
19
20
|
root) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
for (const [name, conf] of Object.entries(sources ?? {})) {
|
|
26
|
-
named[name] = { source: built(conf, `sources.${name}`, root), entities: conf.entities };
|
|
27
|
-
}
|
|
28
|
-
return storageFrom({
|
|
29
|
-
db: built(typeof dbConf === 'object' ? dbConf : {}, 'db', root),
|
|
30
|
-
sources: named,
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
/** One config entry, resolved to the adapter it names. */
|
|
34
|
-
function built(conf, field, root) {
|
|
35
|
-
const name = conf.source ?? DEFAULT_ADAPTER;
|
|
36
|
-
return Sources.open(name, anchored(conf, root), `${field}.source`);
|
|
21
|
+
const opened = Object.fromEntries(Object.entries(sources ?? {}).map(([name, entry]) => {
|
|
22
|
+
const { entities, ...rest } = entry;
|
|
23
|
+
return [name, { source: Sources.open(anchored(rest, root), `sources.${name}`), entities }];
|
|
24
|
+
}));
|
|
25
|
+
return storageFrom(opened);
|
|
37
26
|
}
|
|
38
27
|
/**
|
|
39
28
|
* A relative path, counted from the config that named it. `:memory:` names no file and an
|
|
40
29
|
* absolute path already says where it is — both pass through untouched, which is what
|
|
41
30
|
* keeps this from being a second reader of what a path means.
|
|
42
31
|
*/
|
|
43
|
-
function anchored(
|
|
44
|
-
const path =
|
|
32
|
+
function anchored(entry, root) {
|
|
33
|
+
const path = entry.path;
|
|
45
34
|
if (!root || typeof path !== 'string' || path === ':memory:' || isAbsolute(path))
|
|
46
|
-
return
|
|
35
|
+
return entry;
|
|
47
36
|
const anchoredPath = resolve(root, path);
|
|
48
37
|
// Anchoring MOVES a database that a deployment has been running against, and the driver
|
|
49
38
|
// would create the new one without a word: additive migration, seeds, an empty domain
|
|
@@ -53,19 +42,33 @@ function anchored(conf, root) {
|
|
|
53
42
|
process.emitWarning(`${path} resolves to ${anchoredPath} beside the config that named it, and a database `
|
|
54
43
|
+ `already sits at ${beside}. Fougere opens the first; move the file, or write the path you mean.`);
|
|
55
44
|
}
|
|
56
|
-
return { ...
|
|
45
|
+
return { ...entry, path: anchoredPath };
|
|
46
|
+
}
|
|
47
|
+
/** Where an entity no source names lives, and what it is called — the one entry listing none. */
|
|
48
|
+
function defaultOf(sources) {
|
|
49
|
+
const unlisted = Object.entries(sources).filter(([, placement]) => placement.entities === undefined);
|
|
50
|
+
if (unlisted.length > 1) {
|
|
51
|
+
throw new Error(`sources: ${unlisted.map(([name]) => `'${name}'`).join(' and ')} list no entities, and nothing says which `
|
|
52
|
+
+ 'one holds the rest. Give all but one of them their entities.');
|
|
53
|
+
}
|
|
54
|
+
if (unlisted.length === 1)
|
|
55
|
+
return [unlisted[0][0], unlisted[0][1].source];
|
|
56
|
+
new Logger('storage').warn(Object.keys(sources).length === 0
|
|
57
|
+
? 'no `sources:` declared — rows live in memory and are gone when the process exits'
|
|
58
|
+
: 'no source lists no entities — the rows of every entity no source names live in memory and are gone when the process exits');
|
|
59
|
+
return ['memory', createMemorySource()];
|
|
57
60
|
}
|
|
58
|
-
/** What a config naming no adapter means. */
|
|
59
|
-
const DEFAULT_ADAPTER = 'sql';
|
|
60
61
|
/** The same routing `resolveStorage` performs, over engines the CALLER built. */
|
|
61
|
-
export function storageFrom(
|
|
62
|
-
const
|
|
62
|
+
export function storageFrom(sources) {
|
|
63
|
+
const [DEFAULT, base] = defaultOf(sources);
|
|
63
64
|
// Where each named entity lives. An entity claimed by two sources is refused naming
|
|
64
65
|
// both: the rows would be read from one and written to the other, by whichever
|
|
65
66
|
// registration ran last — the same silent duplicate `remotes:` refuses one level up.
|
|
66
67
|
const home = new Map();
|
|
67
68
|
const engines = new Map();
|
|
68
|
-
for (const [name, placement] of Object.entries(sources
|
|
69
|
+
for (const [name, placement] of Object.entries(sources)) {
|
|
70
|
+
if (placement.entities === undefined)
|
|
71
|
+
continue;
|
|
69
72
|
engines.set(name, placement.source);
|
|
70
73
|
for (const entity of placement.entities) {
|
|
71
74
|
const key = lowerFirst(entity);
|
|
@@ -78,7 +81,6 @@ export function storageFrom(declared) {
|
|
|
78
81
|
}
|
|
79
82
|
// The default source answers to the name the config gave it, so a refusal naming two
|
|
80
83
|
// sources names things the author can find in their own file.
|
|
81
|
-
const DEFAULT = 'db';
|
|
82
84
|
const sourceOf = (entityName) => home.get(lowerFirst(entityName)) ?? DEFAULT;
|
|
83
85
|
const engineOf = (source) => (source === DEFAULT ? base : engines.get(source));
|
|
84
86
|
const engineFor = (entityName) => {
|
|
@@ -86,15 +88,13 @@ export function storageFrom(declared) {
|
|
|
86
88
|
return (source && engines.get(source)) || base;
|
|
87
89
|
};
|
|
88
90
|
return {
|
|
89
|
-
// Opaque, and narrowed by whoever needs it — auth wants a handle, the CLI wants Kysely.
|
|
90
|
-
db: base.db,
|
|
91
91
|
storageFactory: (entity, name) => engineFor(name).storageFactory(entity, name),
|
|
92
92
|
sourceOf,
|
|
93
93
|
dbOf: (source) => engineOf(source)?.db,
|
|
94
94
|
sources: () => [DEFAULT, ...engines.keys()],
|
|
95
95
|
// Asked of the source that will run the work, never of the default one: a frame whose
|
|
96
|
-
// members all live in a transactional source gets its transaction even when
|
|
97
|
-
// none. A source that hands out none leaves the answer `false`, and a frame reads it:
|
|
96
|
+
// members all live in a transactional source gets its transaction even when the default
|
|
97
|
+
// source has none. A source that hands out none leaves the answer `false`, and a frame reads it:
|
|
98
98
|
// `boot/together.ts` compensates instead, and says which of the two it built.
|
|
99
99
|
transacts: (source) => engineOf(source)?.transacted !== undefined,
|
|
100
100
|
// Absent means the judge is alone with it: a source that keeps no constraint of its own
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResolvedStorage.js","sourceRoot":"","sources":["../../src/storage/ResolvedStorage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ResolvedStorage.js","sourceRoot":"","sources":["../../src/storage/ResolvedStorage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Source } from '@fougere/core';
|
|
2
|
-
/** One source: what realizes it, and the entities that live there. */
|
|
2
|
+
/** One source: what realizes it, and the entities that live there — none listed on the default one. */
|
|
3
3
|
export interface SourceEntities {
|
|
4
4
|
source: Source;
|
|
5
|
-
entities
|
|
5
|
+
entities?: string[];
|
|
6
6
|
}
|
|
7
7
|
//# sourceMappingURL=SourceEntities.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SourceEntities.d.ts","sourceRoot":"","sources":["../../src/storage/SourceEntities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,
|
|
1
|
+
{"version":3,"file":"SourceEntities.d.ts","sourceRoot":"","sources":["../../src/storage/SourceEntities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,uGAAuG;AACvG,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fougere/defaults",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.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,21 +29,21 @@
|
|
|
29
29
|
"src"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@fougere/core": "0.
|
|
33
|
-
"@fougere/
|
|
34
|
-
"@fougere/
|
|
35
|
-
"@fougere/
|
|
36
|
-
"@fougere/
|
|
37
|
-
"@fougere/adapter-memory": "0.19.1-alpha.0"
|
|
32
|
+
"@fougere/core": "0.20.0-alpha.0",
|
|
33
|
+
"@fougere/transport-http": "0.20.0-alpha.0",
|
|
34
|
+
"@fougere/container": "0.20.0-alpha.0",
|
|
35
|
+
"@fougere/compiler": "0.20.0-alpha.0",
|
|
36
|
+
"@fougere/adapter-memory": "0.20.0-alpha.0"
|
|
38
37
|
},
|
|
39
38
|
"publishConfig": {
|
|
40
39
|
"access": "public"
|
|
41
40
|
},
|
|
42
41
|
"devDependencies": {
|
|
43
|
-
"@fougere/schema": "0.
|
|
42
|
+
"@fougere/schema": "0.20.0-alpha.0",
|
|
44
43
|
"kysely": "^0.28.17",
|
|
45
44
|
"better-sqlite3": "^13.0.3",
|
|
46
|
-
"@types/better-sqlite3": "^7.6.13"
|
|
45
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
46
|
+
"@fougere/adapter-sql": "0.20.0-alpha.0"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "rm -rf dist && tsc",
|
package/src/index.ts
CHANGED
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
import { migrating, type App, type CreateAppOptions } from '@fougere/core';
|
|
3
3
|
import { boot } from '@fougere/compiler';
|
|
4
4
|
import { loadConfig, remotesOf } from '@fougere/core/node';
|
|
5
|
-
import { type DbConfig } from './storage/DbConfig.js';
|
|
6
5
|
import { resolveStorage, type ResolvedStorage } from './storage/ResolvedStorage.js';
|
|
7
6
|
import { remoteTransport } from './transport/RemoteTransport.js';
|
|
8
7
|
|
|
9
8
|
export { remoteTransport } from './transport/RemoteTransport.js';
|
|
10
9
|
export { declaresStorage } from './storage/DeclaredStorage.js';
|
|
11
10
|
export { layerOf, resolveStorage, storageFrom } from './storage/ResolvedStorage.js';
|
|
12
|
-
export type {
|
|
11
|
+
export type { SourceEntities } from './storage/SourceEntities.js';
|
|
13
12
|
export type { ResolvedStorage } from './storage/ResolvedStorage.js';
|
|
14
13
|
|
|
15
14
|
export interface BootAppOptions {
|
|
@@ -49,8 +48,8 @@ export async function bootApp(root: string, opts: BootAppOptions = {}): Promise<
|
|
|
49
48
|
// `{}` and never undefined: `boot` reads the config's own `fronds:` when handed nothing.
|
|
50
49
|
remotes: useRemotes ? elsewhere : {},
|
|
51
50
|
remoteTransport: useRemotes ? await remoteTransport() : undefined,
|
|
52
|
-
// One resolver, one place that
|
|
53
|
-
|
|
51
|
+
// One resolver, one place that reads `sources:`.
|
|
52
|
+
storage: (cfg) => (storage = resolveStorage(cfg.sources, root)),
|
|
54
53
|
extensions: [...(opts.migrates ? [migrating((app) => storage?.migrate?.(app))] : []), ...(opts.extensions ?? [])],
|
|
55
54
|
});
|
|
56
55
|
}
|
|
@@ -1,17 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { DbConfig } from './DbConfig.js';
|
|
3
|
-
import type { SourceEntities } from './SourceEntities.js';
|
|
1
|
+
import type { SourceConfig } from '@fougere/core';
|
|
4
2
|
|
|
5
3
|
/** Does this config ask for persistence at all? */
|
|
6
|
-
export function declaresStorage(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return true;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface DeclaredStorage {
|
|
13
|
-
/** The default source — where an entity no placement names lands. */
|
|
14
|
-
db: Source;
|
|
15
|
-
/** The other places. Absent means one source, the way it always was. */
|
|
16
|
-
sources?: Record<string, SourceEntities>;
|
|
4
|
+
export function declaresStorage(sources: Record<string, SourceConfig> | undefined): boolean {
|
|
5
|
+
return Object.keys(sources ?? {}).length > 0;
|
|
17
6
|
}
|
|
@@ -1,19 +1,12 @@
|
|
|
1
|
-
import '@fougere/adapter-sql/sqlite';
|
|
2
1
|
import type { App } from '@fougere/core';
|
|
3
2
|
import { lowerFirst } from '@fougere/core/contract';
|
|
4
3
|
import { existsSync } from 'node:fs';
|
|
5
4
|
import { isAbsolute, resolve } from 'node:path';
|
|
6
|
-
import { Logger, Sources, sourceViewOf, type Constraint, type Source } from '@fougere/core';
|
|
5
|
+
import { Logger, Sources, sourceViewOf, type Constraint, type Source, type SourceConfig } from '@fougere/core';
|
|
7
6
|
import { createMemorySource } from '@fougere/adapter-memory';
|
|
8
|
-
import { declaresStorage } from './DeclaredStorage.js';
|
|
9
|
-
import type { DbConfig } from './DbConfig.js';
|
|
10
|
-
import type { SourcesConfig } from './SourcesConfig.js';
|
|
11
7
|
import type { SourceEntities } from './SourceEntities.js';
|
|
12
|
-
import type { DeclaredStorage } from './DeclaredStorage.js';
|
|
13
8
|
|
|
14
9
|
export interface ResolvedStorage {
|
|
15
|
-
/** The default source's engine handle — what `fougere migrate` reads the live tables through. */
|
|
16
|
-
db?: unknown;
|
|
17
10
|
storageFactory: ((entity: any, name: string) => any) | undefined;
|
|
18
11
|
/**
|
|
19
12
|
* The source an entity's rows live in — what decides whether a frame gets a real transaction or
|
|
@@ -45,10 +38,12 @@ export interface ResolvedStorage {
|
|
|
45
38
|
/** Raw synchronous handle, when the engine exposes one. */
|
|
46
39
|
}
|
|
47
40
|
|
|
48
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Resolve the data layer from `sources:`. The one entry listing no entities holds the rest; none
|
|
43
|
+
* at all keeps the rows in memory, and saying so is the whole fallback.
|
|
44
|
+
*/
|
|
49
45
|
export function resolveStorage(
|
|
50
|
-
|
|
51
|
-
sources?: SourcesConfig,
|
|
46
|
+
sources: Record<string, SourceConfig> | undefined,
|
|
52
47
|
/**
|
|
53
48
|
* Where a relative `path:` is counted from — the directory of the config that named it.
|
|
54
49
|
*
|
|
@@ -60,28 +55,13 @@ export function resolveStorage(
|
|
|
60
55
|
*/
|
|
61
56
|
root?: string,
|
|
62
57
|
): ResolvedStorage {
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
const opened = Object.fromEntries(Object.entries(sources ?? {}).map(([name, entry]) => {
|
|
59
|
+
const { entities, ...rest } = entry as { entities?: string[] } & Record<string, unknown>;
|
|
65
60
|
|
|
66
|
-
return
|
|
67
|
-
}
|
|
61
|
+
return [name, { source: Sources.open(anchored(rest, root), `sources.${name}`), entities }];
|
|
62
|
+
}));
|
|
68
63
|
|
|
69
|
-
|
|
70
|
-
for (const [name, conf] of Object.entries(sources ?? {})) {
|
|
71
|
-
named[name] = { source: built(conf, `sources.${name}`, root), entities: conf.entities };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return storageFrom({
|
|
75
|
-
db: built(typeof dbConf === 'object' ? dbConf : {}, 'db', root),
|
|
76
|
-
sources: named,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** One config entry, resolved to the adapter it names. */
|
|
81
|
-
function built(conf: Record<string, unknown>, field: string, root?: string): Source {
|
|
82
|
-
const name = (conf.source as string | undefined) ?? DEFAULT_ADAPTER;
|
|
83
|
-
|
|
84
|
-
return Sources.open(name, anchored(conf, root) as never, `${field}.source`);
|
|
64
|
+
return storageFrom(opened);
|
|
85
65
|
}
|
|
86
66
|
|
|
87
67
|
/**
|
|
@@ -89,9 +69,9 @@ function built(conf: Record<string, unknown>, field: string, root?: string): Sou
|
|
|
89
69
|
* absolute path already says where it is — both pass through untouched, which is what
|
|
90
70
|
* keeps this from being a second reader of what a path means.
|
|
91
71
|
*/
|
|
92
|
-
function anchored(
|
|
93
|
-
const path =
|
|
94
|
-
if (!root || typeof path !== 'string' || path === ':memory:' || isAbsolute(path)) return
|
|
72
|
+
function anchored(entry: Record<string, unknown>, root?: string): Record<string, unknown> {
|
|
73
|
+
const path = entry.path;
|
|
74
|
+
if (!root || typeof path !== 'string' || path === ':memory:' || isAbsolute(path)) return entry;
|
|
95
75
|
|
|
96
76
|
const anchoredPath = resolve(root, path);
|
|
97
77
|
// Anchoring MOVES a database that a deployment has been running against, and the driver
|
|
@@ -105,22 +85,40 @@ function anchored(conf: Record<string, unknown>, root?: string): Record<string,
|
|
|
105
85
|
);
|
|
106
86
|
}
|
|
107
87
|
|
|
108
|
-
return { ...
|
|
88
|
+
return { ...entry, path: anchoredPath };
|
|
109
89
|
}
|
|
110
90
|
|
|
111
|
-
/**
|
|
112
|
-
|
|
91
|
+
/** Where an entity no source names lives, and what it is called — the one entry listing none. */
|
|
92
|
+
function defaultOf(sources: Record<string, SourceEntities>): [string, Source] {
|
|
93
|
+
const unlisted = Object.entries(sources).filter(([, placement]) => placement.entities === undefined);
|
|
94
|
+
if (unlisted.length > 1) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`sources: ${unlisted.map(([name]) => `'${name}'`).join(' and ')} list no entities, and nothing says which `
|
|
97
|
+
+ 'one holds the rest. Give all but one of them their entities.',
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
if (unlisted.length === 1) return [unlisted[0]![0], unlisted[0]![1].source];
|
|
101
|
+
|
|
102
|
+
new Logger('storage').warn(
|
|
103
|
+
Object.keys(sources).length === 0
|
|
104
|
+
? 'no `sources:` declared — rows live in memory and are gone when the process exits'
|
|
105
|
+
: 'no source lists no entities — the rows of every entity no source names live in memory and are gone when the process exits',
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
return ['memory', createMemorySource()];
|
|
109
|
+
}
|
|
113
110
|
|
|
114
111
|
/** The same routing `resolveStorage` performs, over engines the CALLER built. */
|
|
115
|
-
export function storageFrom(
|
|
116
|
-
const
|
|
112
|
+
export function storageFrom(sources: Record<string, SourceEntities>): ResolvedStorage {
|
|
113
|
+
const [DEFAULT, base] = defaultOf(sources);
|
|
117
114
|
|
|
118
115
|
// Where each named entity lives. An entity claimed by two sources is refused naming
|
|
119
116
|
// both: the rows would be read from one and written to the other, by whichever
|
|
120
117
|
// registration ran last — the same silent duplicate `remotes:` refuses one level up.
|
|
121
118
|
const home = new Map<string, string>();
|
|
122
119
|
const engines = new Map<string, Source>();
|
|
123
|
-
for (const [name, placement] of Object.entries(sources
|
|
120
|
+
for (const [name, placement] of Object.entries(sources)) {
|
|
121
|
+
if (placement.entities === undefined) continue;
|
|
124
122
|
engines.set(name, placement.source);
|
|
125
123
|
for (const entity of placement.entities) {
|
|
126
124
|
const key = lowerFirst(entity);
|
|
@@ -136,7 +134,6 @@ export function storageFrom(declared: DeclaredStorage): ResolvedStorage {
|
|
|
136
134
|
|
|
137
135
|
// The default source answers to the name the config gave it, so a refusal naming two
|
|
138
136
|
// sources names things the author can find in their own file.
|
|
139
|
-
const DEFAULT = 'db';
|
|
140
137
|
const sourceOf = (entityName: string) => home.get(lowerFirst(entityName)) ?? DEFAULT;
|
|
141
138
|
const engineOf = (source: string) => (source === DEFAULT ? base : engines.get(source));
|
|
142
139
|
const engineFor = (entityName: string) => {
|
|
@@ -146,15 +143,13 @@ export function storageFrom(declared: DeclaredStorage): ResolvedStorage {
|
|
|
146
143
|
};
|
|
147
144
|
|
|
148
145
|
return {
|
|
149
|
-
// Opaque, and narrowed by whoever needs it — auth wants a handle, the CLI wants Kysely.
|
|
150
|
-
db: (base as { db?: unknown }).db,
|
|
151
146
|
storageFactory: (entity: any, name: string) => engineFor(name).storageFactory(entity, name),
|
|
152
147
|
sourceOf,
|
|
153
148
|
dbOf: (source) => (engineOf(source) as { db?: unknown } | undefined)?.db,
|
|
154
149
|
sources: () => [DEFAULT, ...engines.keys()],
|
|
155
150
|
// 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
|
|
157
|
-
// none. A source that hands out none leaves the answer `false`, and a frame reads it:
|
|
151
|
+
// members all live in a transactional source gets its transaction even when the default
|
|
152
|
+
// source has none. A source that hands out none leaves the answer `false`, and a frame reads it:
|
|
158
153
|
// `boot/together.ts` compensates instead, and says which of the two it built.
|
|
159
154
|
transacts: (source) => engineOf(source)?.transacted !== undefined,
|
|
160
155
|
// Absent means the judge is alone with it: a source that keeps no constraint of its own
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Source } from '@fougere/core';
|
|
2
2
|
|
|
3
|
-
/** One source: what realizes it, and the entities that live there. */
|
|
3
|
+
/** One source: what realizes it, and the entities that live there — none listed on the default one. */
|
|
4
4
|
export interface SourceEntities {
|
|
5
5
|
source: Source;
|
|
6
|
-
entities
|
|
6
|
+
entities?: string[];
|
|
7
7
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DbConfig.d.ts","sourceRoot":"","sources":["../../src/storage/DbConfig.ts"],"names":[],"mappings":"AAAA,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"}
|
package/dist/storage/DbConfig.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DbConfig.js","sourceRoot":"","sources":["../../src/storage/DbConfig.ts"],"names":[],"mappings":""}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/** A named source and the entities it holds — the `sources` field, read structurally. */
|
|
2
|
-
export type SourcesConfig = Record<string, {
|
|
3
|
-
source?: string;
|
|
4
|
-
dialect?: string;
|
|
5
|
-
path?: string;
|
|
6
|
-
entities: string[];
|
|
7
|
-
}> | undefined;
|
|
8
|
-
//# sourceMappingURL=SourcesConfig.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SourcesConfig.d.ts","sourceRoot":"","sources":["../../src/storage/SourcesConfig.ts"],"names":[],"mappings":"AAAA,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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SourcesConfig.js","sourceRoot":"","sources":["../../src/storage/SourcesConfig.ts"],"names":[],"mappings":""}
|
package/src/storage/DbConfig.ts
DELETED