@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 CHANGED
@@ -1,12 +1,100 @@
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 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
- 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
+ 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
- * What is generic and once lived in a ChRIS package moves here, so a layer
5
- * that is not about CUBE can use it without loading CUBE's client. fond
6
- * depends on nothing in `@fnndsc` (law of docs/backend-neutral.adoc, held by
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
- * What is generic and once lived in a ChRIS package moves here, so a layer
21
- * that is not about CUBE can use it without loading CUBE's client. fond
22
- * depends on nothing in `@fnndsc` (law of docs/backend-neutral.adoc, held by
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.0",
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.",
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",