@fnndsc/fond 0.1.0 → 0.1.2
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 +94 -6
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,12 +1,100 @@
|
|
|
1
1
|
# @fnndsc/fond
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The pieces every layer of mise needs, whatever the backend: the small, generic base that the engine (`@fnndsc/brasa`), the session host (`@fnndsc/calypso`) and a backend's own packages all stand on.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The name is from the kitchen, like the rest of the stack: *fonds de cuisine* are the base stocks a kitchen cooks everything else from.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
```
|
|
8
|
+
npm install @fnndsc/fond
|
|
9
|
+
```
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
## Why it exists
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
A backend such as ChRIS (CUBE) brings its own client and its own world. The pieces every layer needs, whatever the backend, live here rather than in a backend's package, so a layer that is not about CUBE can use them without loading CUBE (see [docs/backend-neutral.adoc](https://github.com/FNNDSC/mise/blob/main/docs/backend-neutral.adoc)).
|
|
14
|
+
|
|
15
|
+
fond's one rule: **it depends on nothing in `@fnndsc`**. CI holds it to that (`npm run lint:fond`).
|
|
16
|
+
|
|
17
|
+
## What's in it
|
|
18
|
+
|
|
19
|
+
| Export | What it is |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| `Result<T>`, `Ok`, `Err`, `result_isOk`, `result_isErr` | An explicit success-or-failure value. A function returns `Result<T>` rather than `T \| null`, and TypeScript will not let a caller read `.value` until it has checked `.ok`. |
|
|
22
|
+
| `errorStack` | The process-wide message stack that failures are reported on, with context-isolated scopes and checkpoints. |
|
|
23
|
+
| `errorStack_configure`, `errorStack_getAllOfType`, `StackMessage` | Configuration, a convenience reader, and the message type. |
|
|
24
|
+
|
|
25
|
+
## Using `Result`
|
|
26
|
+
|
|
27
|
+
A failure carries no payload of its own: the reason goes on the error stack, where a surface can show it, and the `Result` says only that it failed.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { Ok, Err, errorStack, type Result } from '@fnndsc/fond';
|
|
31
|
+
|
|
32
|
+
async function config_read(path: string): Promise<Result<Config>> {
|
|
33
|
+
const text: string | null = await file_read(path);
|
|
34
|
+
if (text === null) {
|
|
35
|
+
errorStack.stack_push('error', `No configuration at ${path}.`);
|
|
36
|
+
return Err();
|
|
37
|
+
}
|
|
38
|
+
return Ok(config_parse(text));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const config: Result<Config> = await config_read('~/.config/app.yml');
|
|
42
|
+
if (!config.ok) {
|
|
43
|
+
// config.value does not exist here; TypeScript says so.
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
config_apply(config.value);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Using the error stack
|
|
50
|
+
|
|
51
|
+
`errorStack` is a single instance for the whole process. Each message is stamped with the name of the function that pushed it:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
errorStack.stack_push('error', 'CUBE refused the login');
|
|
55
|
+
errorStack.stack_pop();
|
|
56
|
+
// { type: 'error', message: '[login_run ] | CUBE refused the login' }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Reading and clearing:
|
|
60
|
+
|
|
61
|
+
| Method | Does |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| `stack_push(type, message)` | Pushes an `error` or a `warning`. |
|
|
64
|
+
| `stack_pop()`, `stack_getAll()` | Takes the newest message; lists them all. |
|
|
65
|
+
| `stack_search(text)`, `messagesOfType_search(type, text)` | Finds messages containing some text. |
|
|
66
|
+
| `allOfType_get(type)`, `messages_has()`, `messagesOfType_has(type)` | Reads by type; asks whether anything is there. |
|
|
67
|
+
| `stack_clear()`, `type_clear(type)` | Empties the stack, or one type. |
|
|
68
|
+
|
|
69
|
+
Two features keep concurrent work from mixing up its errors:
|
|
70
|
+
|
|
71
|
+
* **Scopes.** Work run inside `errorStack.scope_run(fn)` pushes to and pops from its own isolated stack, carried by Node's `AsyncLocalStorage` through every `await` inside it. Background work (cache warming, refreshes) runs in a scope so its failures never land in a foreground command's report.
|
|
72
|
+
* **Checkpoints.** A command calls `checkpoint_mark()` before it works and `checkpoint_drain(mark)` after, and gets exactly the messages pushed in between.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const mark: number = errorStack.checkpoint_mark();
|
|
76
|
+
const answer: Result<Listing> = await listing_fetch(path);
|
|
77
|
+
const reasons: StackMessage[] = errorStack.checkpoint_drain(mark);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`errorStack_configure({ functionNamePadWidth })` sets how wide the function-name stamp is padded.
|
|
81
|
+
|
|
82
|
+
## One instance, whoever loads it
|
|
83
|
+
|
|
84
|
+
The error stack only works if the whole process shares one. fond is built as CommonJS, so packages that `require` it (cumin) and packages that `import` it (salsa, brasa, calypso) load the same module and so the same stack. `@fnndsc/cumin` re-exports fond's `Result` and `errorStack` rather than keeping copies, so code that imports them from cumin shares that stack too. If you bundle code that uses fond, keep it to one copy.
|
|
85
|
+
|
|
86
|
+
## Where it sits
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
brasa (engine) calypso (session host) cumin, salsa (the ChRIS backend)
|
|
90
|
+
│ │ │
|
|
91
|
+
└─────────────────────┼──────────────────────────┘
|
|
92
|
+
▼
|
|
93
|
+
┌───────────────┐
|
|
94
|
+
│ fond │ depends on nothing in @fnndsc
|
|
95
|
+
└───────────────┘
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
MIT. Part of [mise](https://github.com/FNNDSC/mise).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file fond: the neutral base under mise's engine and session host.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The pieces every layer needs, whatever the backend, so a layer that is not
|
|
5
|
+
* about CUBE can use them without loading CUBE's client. fond depends on
|
|
6
|
+
* nothing in `@fnndsc` (docs/backend-neutral.adoc, held by
|
|
7
7
|
* `npm run lint:fond`).
|
|
8
8
|
*
|
|
9
9
|
* @module
|
package/dist/index.js
CHANGED
|
@@ -17,9 +17,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
/**
|
|
18
18
|
* @file fond: the neutral base under mise's engine and session host.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* The pieces every layer needs, whatever the backend, so a layer that is not
|
|
21
|
+
* about CUBE can use them without loading CUBE's client. fond depends on
|
|
22
|
+
* nothing in `@fnndsc` (docs/backend-neutral.adoc, held by
|
|
23
23
|
* `npm run lint:fond`).
|
|
24
24
|
*
|
|
25
25
|
* @module
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fnndsc/fond",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "The
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "The pieces every layer of mise needs, whatever the backend. Depends on nothing in @fnndsc.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/FNNDSC/mise.git",
|