@fnndsc/fond 0.1.0 → 0.1.1

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 (2) hide show
  1. package/README.md +96 -6
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,12 +1,102 @@
1
1
  # @fnndsc/fond
2
2
 
3
- The neutral base under mise's engine (`brasa`) and session host (`calypso`): *fonds de cuisine*, the base stocks a kitchen cooks everything from.
3
+ The neutral base of the mise stack: the small, generic pieces that the engine (`@fnndsc/brasa`), the session host (`@fnndsc/calypso`) and the ChRIS packages all stand on, and that have nothing to do with ChRIS.
4
4
 
5
- It holds what is generic and once lived in a ChRIS package, so a layer that is not about CUBE can use it without loading CUBE's client:
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
- * `Result`, `Ok`, `Err`, `result_isOk`, `result_isErr`: explicit success or failure.
8
- * `errorStack`: the process-wide, async-context-aware message stack.
7
+ ```
8
+ npm install @fnndsc/fond
9
+ ```
9
10
 
10
- Later steps of the backend-neutral work add the VFS framework and the output sink and surface interfaces. See [docs/backend-neutral.adoc](../../docs/backend-neutral.adoc).
11
+ ## Why it exists
11
12
 
12
- fond depends on nothing in `@fnndsc`. `@fnndsc/cumin` re-exports what moved here, so existing imports keep working.
13
+ mise is being made backend-neutral: one engine, one session host, one wire and one surface frame, with ChRIS (CUBE) as the first backend among possibly several (see [docs/backend-neutral.adoc](https://github.com/FNNDSC/mise/blob/main/docs/backend-neutral.adoc)). For that to be true, the generic pieces cannot live inside a ChRIS package. Before fond, `Result` and the error stack lived in `@fnndsc/cumin`, whose root also loads CUBE's API client, so any layer that wanted an `Ok()` loaded CUBE with it.
14
+
15
+ fond is where those pieces go instead. Its one rule: **it depends on nothing in `@fnndsc`**. CI holds it to that (`npm run lint:fond`), so a layer that is not about CUBE can use fond without loading CUBE.
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
+ The steps after this one add the VFS framework (mount interface and dispatcher) and the output sink and surface interfaces the engine and the session host share.
26
+
27
+ ## Using `Result`
28
+
29
+ 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.
30
+
31
+ ```typescript
32
+ import { Ok, Err, errorStack, type Result } from '@fnndsc/fond';
33
+
34
+ async function config_read(path: string): Promise<Result<Config>> {
35
+ const text: string | null = await file_read(path);
36
+ if (text === null) {
37
+ errorStack.stack_push('error', `No configuration at ${path}.`);
38
+ return Err();
39
+ }
40
+ return Ok(config_parse(text));
41
+ }
42
+
43
+ const config: Result<Config> = await config_read('~/.config/app.yml');
44
+ if (!config.ok) {
45
+ // config.value does not exist here; TypeScript says so.
46
+ return;
47
+ }
48
+ config_apply(config.value);
49
+ ```
50
+
51
+ ## Using the error stack
52
+
53
+ `errorStack` is a single instance for the whole process. Each message is stamped with the name of the function that pushed it:
54
+
55
+ ```typescript
56
+ errorStack.stack_push('error', 'CUBE refused the login');
57
+ errorStack.stack_pop();
58
+ // { type: 'error', message: '[login_run ] | CUBE refused the login' }
59
+ ```
60
+
61
+ Reading and clearing:
62
+
63
+ | Method | Does |
64
+ | --- | --- |
65
+ | `stack_push(type, message)` | Pushes an `error` or a `warning`. |
66
+ | `stack_pop()`, `stack_getAll()` | Takes the newest message; lists them all. |
67
+ | `stack_search(text)`, `messagesOfType_search(type, text)` | Finds messages containing some text. |
68
+ | `allOfType_get(type)`, `messages_has()`, `messagesOfType_has(type)` | Reads by type; asks whether anything is there. |
69
+ | `stack_clear()`, `type_clear(type)` | Empties the stack, or one type. |
70
+
71
+ Two features keep concurrent work from mixing up its errors:
72
+
73
+ * **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.
74
+ * **Checkpoints.** A command calls `checkpoint_mark()` before it works and `checkpoint_drain(mark)` after, and gets exactly the messages pushed in between.
75
+
76
+ ```typescript
77
+ const mark: number = errorStack.checkpoint_mark();
78
+ const answer: Result<Listing> = await listing_fetch(path);
79
+ const reasons: StackMessage[] = errorStack.checkpoint_drain(mark);
80
+ ```
81
+
82
+ `errorStack_configure({ functionNamePadWidth })` sets how wide the function-name stamp is padded.
83
+
84
+ ## One instance, whoever loads it
85
+
86
+ 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 still imports them from cumin shares that stack too. If you bundle code that uses fond, keep it to one copy.
87
+
88
+ ## Where it sits
89
+
90
+ ```
91
+ brasa (engine) calypso (session host) cumin, salsa (the ChRIS backend)
92
+ │ │ │
93
+ └─────────────────────┼──────────────────────────┘
94
+ ▼
95
+ ┌───────────────┐
96
+ │ fond │ depends on nothing in @fnndsc
97
+ └───────────────┘
98
+ ```
99
+
100
+ ## License
101
+
102
+ MIT. Part of [mise](https://github.com/FNNDSC/mise).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fnndsc/fond",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "The neutral base under mise's engine and session host: Result, the error stack, and (in later steps) the VFS framework and the sink and surface interfaces. Depends on nothing in @fnndsc.",
5
5
  "repository": {
6
6
  "type": "git",