lemon-core 5.0.4 → 5.0.6
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 +168 -136
- package/bin/lemon-fields-types.mjs +12 -0
- package/bin/lib/fields-types.mjs +629 -0
- package/dist/common/test-helper.js +6 -3
- package/dist/common/test-helper.js.map +1 -1
- package/dist/cores/aws/aws-sns-service.d.ts +6 -0
- package/dist/cores/aws/aws-sns-service.js +22 -3
- package/dist/cores/aws/aws-sns-service.js.map +1 -1
- package/dist/cores/aws/aws-sqs-service.js +5 -0
- package/dist/cores/aws/aws-sqs-service.js.map +1 -1
- package/dist/cores/config/config-service.js +3 -1
- package/dist/cores/config/config-service.js.map +1 -1
- package/dist/cores/lambda/lambda-alb-handler.js +5 -0
- package/dist/cores/lambda/lambda-alb-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-handler.js +4 -1
- package/dist/cores/lambda/lambda-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-notification-handler.js +4 -1
- package/dist/cores/lambda/lambda-notification-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-sns-handler.d.ts +7 -1
- package/dist/cores/lambda/lambda-sns-handler.js +26 -3
- package/dist/cores/lambda/lambda-sns-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-sqs-handler.d.ts +7 -1
- package/dist/cores/lambda/lambda-sqs-handler.js +26 -3
- package/dist/cores/lambda/lambda-sqs-handler.js.map +1 -1
- package/dist/cores/lambda/lambda-web-handler.js +63 -15
- package/dist/cores/lambda/lambda-web-handler.js.map +1 -1
- package/dist/cores/protocol/aws-lambda-helper.d.ts +13 -0
- package/dist/cores/protocol/aws-lambda-helper.js +64 -41
- package/dist/cores/protocol/aws-lambda-helper.js.map +1 -1
- package/dist/cores/protocol/local-transport.d.ts +135 -0
- package/dist/cores/protocol/local-transport.js +392 -0
- package/dist/cores/protocol/local-transport.js.map +1 -0
- package/dist/cores/protocol/protocol-relay.d.ts +123 -0
- package/dist/cores/protocol/protocol-relay.js +339 -0
- package/dist/cores/protocol/protocol-relay.js.map +1 -0
- package/dist/cores/protocol/protocol-service.d.ts +11 -4
- package/dist/cores/protocol/protocol-service.js +140 -36
- package/dist/cores/protocol/protocol-service.js.map +1 -1
- package/dist/cores/protocol/protocol-sign.d.ts +22 -0
- package/dist/cores/protocol/protocol-sign.js +30 -3
- package/dist/cores/protocol/protocol-sign.js.map +1 -1
- package/dist/engine/engine.js +35 -15
- package/dist/engine/engine.js.map +1 -1
- package/dist/esm/index.mjs +2 -0
- package/dist/extended/cores/abstract-controllers.d.ts +18 -4
- package/dist/extended/cores/abstract-controllers.js +59 -19
- package/dist/extended/cores/abstract-controllers.js.map +1 -1
- package/dist/extended/cores/abstract-services.d.ts +54 -4
- package/dist/extended/cores/abstract-services.js +159 -14
- package/dist/extended/cores/abstract-services.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/log-mask.d.ts +19 -0
- package/dist/lib/log-mask.js +55 -0
- package/dist/lib/log-mask.js.map +1 -0
- package/dist/lib/safe-json.d.ts +23 -0
- package/dist/lib/safe-json.js +78 -0
- package/dist/lib/safe-json.js.map +1 -0
- package/package.json +14 -4
package/README.md
CHANGED
|
@@ -2,47 +2,69 @@
|
|
|
2
2
|
[](https://badge.fury.io/js/lemon-core)
|
|
3
3
|
[](https://badge.fury.io/gh/lemoncloud-io%2Flemon-core)
|
|
4
4
|
|
|
5
|
-
# lemon-core
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
5
|
+
# lemon-core
|
|
6
|
+
|
|
7
|
+
Bootloader for serverless micro-services on AWS Lambda: one function, several event sources, an engine with modules, a protocol service.
|
|
8
|
+
This README is the entry point for people and AI agents; every path and command below is in this repo. `§` refers to `HOW_TO_UPGRADE_V5.md`.
|
|
9
|
+
v5 status: npm `latest` is `5.0.4`. The `v5` branch holds all 5.x work, unreleased changes included; `develop` is the default branch.
|
|
10
|
+
`CONTRIBUTING.md` describes the `develop` flow; 5.x changes are merged into `v5` until it lands on `develop`.
|
|
11
|
+
|
|
12
|
+
## At a glance
|
|
13
|
+
|
|
14
|
+
| Item | Value |
|
|
15
|
+
|---|---|
|
|
16
|
+
| Runtime | Node `>=24.0.0` (`engines.node`), `.nvmrc` `24.15.0` |
|
|
17
|
+
| Build | TypeScript `^5.9.3`. `npm run build` = `build-ts` (`tsc`) + `scripts/gen-esm-wrapper.cjs` |
|
|
18
|
+
| Tests | vitest `^4.1.4`: `src/**/*.spec.ts`, `bin/**/*.spec.mjs` (`vitest.config.ts`) |
|
|
19
|
+
| Formats | CJS `dist/` + ESM `dist/esm/*.mjs`. `exports`: `.`, `./testing`, `./dist/environ`, `./dist/cores/lambda/lambda-web-handler`, `./dist/extended/cores`, `./dist/*` (until v6), `./package.json` |
|
|
20
|
+
| Dependencies | `@aws-sdk/client-dynamodb, @aws-sdk/lib-dynamodb, @opensearch-project/opensearch, @smithy/signature-v4, @types/aws-lambda, @types/jsonwebtoken, async, crypto-js, js-yaml, jsonwebtoken, lemon-model, mime-types, node-cache, qs, source-map-support` |
|
|
21
|
+
| Optional peers | 8 AWS SDK packages `^3.1159.0`, loaded on first use. `typescript` `>=4.7` (CLI) |
|
|
22
|
+
| Published | `files`: `dist/**/*`, `bin/lemon-fields-types.mjs`, `bin/lib/fields-types.mjs`. CLI `lemon-fields-types` (merged in the `v5` branch after 5.0.4; see § 13.5) |
|
|
23
|
+
| Branches | `develop` is the default branch (its `version` is 4.3.0). `v5` holds the 5.x work. `master` was last updated in 2024 (3.2.9). |
|
|
24
|
+
| Version | The `version` field of `package.json`. |
|
|
25
|
+
|
|
26
|
+
## Repository map
|
|
27
|
+
|
|
28
|
+
| Path | What it holds | Who changes it |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `src/index.ts` | Root barrel | Only through the `api:check` allow list |
|
|
31
|
+
| `src/engine/` | `$engine` singleton, `$U`, `_log`/`_inf`/`_err` | Rarely; every module and service depends on it |
|
|
32
|
+
| `src/cores/` | `lambda/`, `protocol/`, `config/`, `aws/`, `dynamo/`, `elastic/`, `storage/`, `cache/`, `api/` | Developer |
|
|
33
|
+
| `src/extended/` | `CoreService`, `ManagerProxy`; `cores/`: template layer (`MyCoreService`, `checkFieldsAdmin()`) | Developer |
|
|
34
|
+
| `src/controllers/`, `tools/`, `helpers/` | Controllers, `express`, `$T`, `$protocol()` | Developer |
|
|
35
|
+
| `src/lib/` | Internal: `safe-json`, `log-mask`, `qs-compat`, `http-fetch`, `lazy`, `perf`. `lib` barrel: `dynamodb-value` only | Developer. Internal; never re-exported from a barrel |
|
|
36
|
+
| `src/common/test-helper.ts`, `src/environ.ts` | Sub-paths `lemon-core/testing`, `lemon-core/dist/environ` | Rarely; both are published sub-paths |
|
|
37
|
+
| `bin/` | `lemon-fields-types` CLI, `lib/` logic, spec, fixtures | Developer |
|
|
38
|
+
| `scripts/` | Build and API gates, lazy-load probes | Developer |
|
|
39
|
+
| `etc/api-names.v4.txt`, `etc/api-names.allow.txt` | v4 public-name baseline; allowed `+Name`/`-Name` | The baseline stays; add lines to the allow list only |
|
|
40
|
+
| `env/` | Configuration profiles | **Agents do not open it** |
|
|
41
|
+
| `docs/v5/`, `docs/specs/` | v5 design record (B0–B13); `$T`/`$U` specs | Updated with the change they describe |
|
|
42
|
+
| `dist/`, `coverage/` | Build and test output, ignored by git | **Never edited by hand** |
|
|
43
|
+
| `.github/workflows/` | `docgen.yaml`: typedoc on push to `develop`. No test job | A person |
|
|
44
|
+
|
|
45
|
+
## Request flow
|
|
46
|
+
|
|
47
|
+
```mermaid
|
|
48
|
+
flowchart LR
|
|
49
|
+
SRC["API Gateway, ALB, WebSocket, SNS, SQS,<br/>cron, DynamoDB stream, Cognito"] --> LH["LambdaHandler<br/>findService()"]
|
|
50
|
+
LH -- web --> WEB["LambdaWEBHandler"]
|
|
51
|
+
LH -- "sns / sqs" --> MQ["LambdaSNSHandler, LambdaSQSHandler"]
|
|
52
|
+
LH -- "alb, cron, dds, ..." --> SUB["other handlers"]
|
|
53
|
+
MQ -- "x-protocol-service" --> WEB
|
|
54
|
+
MQ -- other --> LIS["addListener()"]
|
|
55
|
+
WEB --> CTRL["NextDecoder → NextHandler"]
|
|
56
|
+
CTRL --> PS["ProtocolService"]
|
|
57
|
+
PS -- "execute(): Lambda invoke" --> OUT["other service"]
|
|
58
|
+
PS -- "notify(), broadcast(): SNS" --> OUT
|
|
59
|
+
PS -- "enqueue(): SQS" --> OUT
|
|
44
60
|
```
|
|
45
61
|
|
|
62
|
+
- `LambdaModule` (`cores/lambda/`) runs `$engine.initialize()`, then `LambdaHandler.handle()`.
|
|
63
|
+
- Web: the type's controller (`addController()`) decodes to a `NextHandler` with a `NextContext`.
|
|
64
|
+
- SNS/SQS with `Subject` `x-protocol-service` pass a signature check, then `handleProtocol()`.
|
|
65
|
+
- `ProtocolService` (`core-services.ts`): `execute()` waits (unless `useEvent`); `notify()`, `enqueue()`, `broadcast()` do not.
|
|
66
|
+
- Failures resolve (Cognito rethrows); SQS/stream return `batchItemFailures` (§ 11.4).
|
|
67
|
+
|
|
46
68
|
## Usage
|
|
47
69
|
|
|
48
70
|
### 1. Install
|
|
@@ -51,132 +73,136 @@ const queueId = await service.enqueue(protocol, callback, 30);
|
|
|
51
73
|
npm install lemon-core --save
|
|
52
74
|
```
|
|
53
75
|
|
|
54
|
-
|
|
76
|
+
Add the AWS SDK peers you use to your own `dependencies` (§ 8.1).
|
|
55
77
|
|
|
56
78
|
### 2. Minimal bootstrap — engine initialization
|
|
57
79
|
|
|
58
|
-
Importing `lemon-core` creates the `$engine` singleton immediately at module
|
|
59
|
-
load time (not lazily):
|
|
60
|
-
|
|
61
80
|
```ts
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
// src/engine/index.ts:26,30-32
|
|
65
|
-
// export const $U = $engine.U;
|
|
66
|
-
// export const _log = $engine.log; export const _inf = $engine.inf; export const _err = $engine.err;
|
|
67
|
-
import { $U, _log, _inf, _err } from 'lemon-core';
|
|
68
|
-
|
|
81
|
+
// `$engine` is built at the first import, not lazily: set `process.env` before.
|
|
82
|
+
import $lemon, { $U, _inf } from 'lemon-core'; // default: { engine, cores, tools, controllers }
|
|
69
83
|
_inf('lemon-core loaded, NS=', $U.env('NS', 'TT'));
|
|
84
|
+
await $lemon.engine.initialize(); // resolves once every module's initModule() settles
|
|
70
85
|
```
|
|
71
86
|
|
|
72
|
-
|
|
73
|
-
top-level groups (`engine`, `cores`, `tools`, `controllers`):
|
|
74
|
-
|
|
75
|
-
```ts
|
|
76
|
-
// src/index.ts:68 — export default { engine, cores, tools, controllers };
|
|
77
|
-
import $lemon from 'lemon-core';
|
|
78
|
-
|
|
79
|
-
await $lemon.engine.initialize(); // resolves once every registered module's initModule() settles
|
|
80
|
-
```
|
|
87
|
+
ESM `import` gives the same instances (§ 2). Specs use `lemon-core/testing` (§ 4).
|
|
81
88
|
|
|
82
89
|
### 3. Engine module registration — the "3-piece set"
|
|
83
90
|
|
|
84
|
-
Any module that hangs off `$engine` (built-in or your own) follows the same
|
|
85
|
-
contract: register in the constructor, name itself, expose an init level.
|
|
86
|
-
The built-in `ProtocolModule` is the smallest real example:
|
|
87
|
-
|
|
88
91
|
```ts
|
|
89
|
-
// src/cores/protocol/index.ts
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
92
|
+
// src/cores/protocol/index.ts (excerpt)
|
|
93
|
+
export class ProtocolModule implements EngineModule {
|
|
94
|
+
public constructor(engine?: LemonEngine) {
|
|
95
|
+
this.engine = engine || $engine;
|
|
96
|
+
if (this.engine) this.engine.register(this); // (1) register; a same-name module is ignored
|
|
97
|
+
}
|
|
98
|
+
public getModuleName = () => 'protocol'; // (2) name
|
|
99
|
+
public async initModule(level?: number): Promise<number> {
|
|
100
|
+
const $conf = this.engine.module<ConfigModule>('config'); // (3) init level
|
|
101
|
+
if (level === undefined) return $conf ? (await $conf.initModule()) + 1 : 1;
|
|
102
|
+
}
|
|
103
|
+
public readonly service: ProtocolService = new MyProtocolService();
|
|
104
|
+
}
|
|
105
|
+
export default new ProtocolModule(); // import-time instance, not lazy (`cores` group)
|
|
103
106
|
```
|
|
104
107
|
|
|
105
|
-
`cores/index.ts:33` re-exports it as part of the `cores` default group
|
|
106
|
-
(`export default { aws, config, lambda, protocol }`), which is why the
|
|
107
|
-
existing `$engine.cores.protocol.service` example below resolves.
|
|
108
|
-
|
|
109
108
|
### 4. Manager / proxy registration — inter-service call example
|
|
110
109
|
|
|
111
|
-
`ProtocolService` (registered above) is the mechanism for calling another
|
|
112
|
-
micro-service — synchronously via `execute()`, or asynchronously via
|
|
113
|
-
`notify()` / `enqueue()` / `broadcast()`:
|
|
114
|
-
|
|
115
110
|
```ts
|
|
116
|
-
|
|
117
|
-
// (ProtocolParam: :99, CallbackParam: :88, ProtocolService: :150)
|
|
118
|
-
import $engine, { ProtocolParam, ProtocolService, CallbackParam } from 'lemon-core';
|
|
111
|
+
import $lemon, { CallbackParam, ProtocolParam, ProtocolService } from 'lemon-core';
|
|
119
112
|
|
|
120
|
-
const service: ProtocolService = $
|
|
113
|
+
const service: ProtocolService = $lemon.cores.protocol.service;
|
|
121
114
|
const protocol: ProtocolParam = service.fromURL(context, 'api://lemon-hello-api/hello/echo', param, body);
|
|
122
115
|
const callback: CallbackParam = { type: 'hooks', id: `${id}` };
|
|
123
|
-
|
|
124
|
-
const queueId = await service.enqueue(protocol, callback, 30);
|
|
116
|
+
const queueId = await service.enqueue(protocol, callback, 30); // 30 seconds delayed
|
|
125
117
|
```
|
|
126
118
|
|
|
127
|
-
|
|
128
|
-
below) is meant to be **subclassed**, not used directly — `AbstractManager`
|
|
129
|
-
and `MyCoreService` are abstract:
|
|
119
|
+
Controllers: `$lemon.cores.lambda.web.addController()`. Models: subclass `MyCoreService` (abstract `createProxy()`), `MyCoreManager`, `MyCoreProxy`. v5: `guardProxy()` saves on a throw only with `{ saveOnError: true }`; managers sync to OpenSearch only with `{ enableSync: true }` (§ 11.6).
|
|
130
120
|
|
|
131
|
-
|
|
132
|
-
// class contracts (all exported from the root barrel):
|
|
133
|
-
// - CoreService src/extended/abstract-service.ts:115 (table/ns/idName, makeStorageService())
|
|
134
|
-
// - AbstractManager src/cores/storage/model-manager.ts:23 (storage owner; must implement
|
|
135
|
-
// `protected abstract prepareDefault($def: T): T` — model-manager.ts:66)
|
|
136
|
-
// - MyCoreService src/extended/cores/abstract-services.ts:171
|
|
137
|
-
// (adds `guardProxy(context, cb)` — auto-saves via `proxy.saveAllUpdates()`
|
|
138
|
-
// on both success and throw — abstract-services.ts:189-202)
|
|
139
|
-
// - MyCoreProxy src/extended/cores/abstract-services.ts:912
|
|
140
|
-
// - ManagerProxy src/extended/abstract-service.ts:399 (auto-registers via `proxy.register(this)`
|
|
141
|
-
// in its own constructor — abstract-service.ts:406)
|
|
142
|
-
// - AbstractProxy src/extended/abstract-service.ts:652 (container; `saveAllUpdates()` persists
|
|
143
|
-
// every registered ManagerProxy's changes in one call)
|
|
144
|
-
// - NextContext re-exported from the `lemon-model` package via
|
|
145
|
-
// `export * from 'lemon-model';` — src/cores/index.ts:12
|
|
146
|
-
|
|
147
|
-
class MyService extends MyCoreService<MyModel, 'my-type', MyProxy> {
|
|
148
|
-
createProxy(context: NextContext): MyProxy {
|
|
149
|
-
return new MyProxy(context, this);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
121
|
+
## Commands
|
|
152
122
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
123
|
+
| Command | What it does | Note |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| `npm test` | `LS=1 vitest run` | Writes `coverage/`. |
|
|
126
|
+
| `npm run test:watch` | `LS=1 vitest` | Re-runs on file changes. |
|
|
127
|
+
| `npm run build` | `tsc` + ESM wrapper | Writes `dist/`. |
|
|
128
|
+
| `npx tsc --noEmit` | Type check only | Writes nothing. |
|
|
129
|
+
| `npm run lint` | `tsc --noEmit` + `eslint --fix` | **Rewrites files.** |
|
|
130
|
+
| `npm run format` | `prettier --write` on `src/` | **Rewrites files.** |
|
|
131
|
+
| `npm run api:names` | Root public names of `dist/index.d.ts` | Run `npm run build` first. |
|
|
132
|
+
| `npm run api:check` | Names vs `etc/api-names.v4.txt` + allow list | Run after `build`. Expect `not-allowed=0`; otherwise exit 1. |
|
|
133
|
+
| `npm run esm:smoke` | ESM and CJS entries are one instance | Run after `build`. Expect `esm-smoke: ok …`. |
|
|
134
|
+
| `npm run dup:check` | One declaring file per exported name | Expect `not-allowed=0`. |
|
|
135
|
+
| `npm run l1l2:probe` | Root/L1/L2 identity, deep paths (`dist/`) | Run after `build`. Expect `fails=0`. |
|
|
136
|
+
| `npm run fields:types` | `lemon-fields-types` here | Reports `models=0` in this repo. Consumers run `npx lemon-fields-types --root .`. |
|
|
137
|
+
| `npm audit --omit=dev` | Audit runtime dependencies | Expect `found 0 vulnerabilities`. |
|
|
159
138
|
|
|
160
|
-
|
|
161
|
-
worked model + manager + proxy example.
|
|
139
|
+
## Verifying a change
|
|
162
140
|
|
|
163
|
-
|
|
141
|
+
Before saying a change is done, run:
|
|
164
142
|
|
|
165
143
|
```sh
|
|
166
|
-
|
|
144
|
+
npm test # all test files pass, exit 0
|
|
145
|
+
npm run build # exit 0
|
|
146
|
+
npx tsc --noEmit # no output
|
|
147
|
+
npm run api:check # api-check: … not-allowed=0
|
|
148
|
+
npm run esm:smoke # esm-smoke: ok …
|
|
149
|
+
npm audit --omit=dev # found 0 vulnerabilities
|
|
167
150
|
```
|
|
168
151
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
-
|
|
152
|
+
- `api:check`: no root name changes without an allow-list line.
|
|
153
|
+
- `esm:smoke`: the dual package keeps one `$engine`.
|
|
154
|
+
- `npm audit --omit=dev`: runtime dependencies stay at 0 (§ 14).
|
|
155
|
+
- Moved exports: also `dup:check`, `l1l2:probe`.
|
|
156
|
+
|
|
157
|
+
## Agent rules
|
|
158
|
+
|
|
159
|
+
- Public names change only via `api:check`: a `+Name`/`-Name` line in `etc/api-names.allow.txt`; the v4 baseline stays.
|
|
160
|
+
- `src/lib/*` is internal: never re-export it from `src/index.ts` or any barrel.
|
|
161
|
+
- No new runtime dependency unless `npm audit --omit=dev` stays 0 (§ 14).
|
|
162
|
+
- The 8 AWS SDK peers stay optional; SDK code loads on first use (§ 8).
|
|
163
|
+
- No `npm publish`, deploy or version bump: a person does those.
|
|
164
|
+
- 5.x work branches from `v5`.
|
|
165
|
+
- `lint` and `format` rewrite files: run them on purpose.
|
|
166
|
+
- Never open or print `env/*` or configuration values.
|
|
167
|
+
- When the docs and the source disagree, the source is right.
|
|
168
|
+
- New functions and blocks get a one-line comment (`src/lib/log-mask.ts`).
|
|
169
|
+
|
|
170
|
+
## Document index
|
|
171
|
+
|
|
172
|
+
| Document | Content |
|
|
173
|
+
|---|---|
|
|
174
|
+
| [HOW_TO_UPGRADE_V5.md](HOW_TO_UPGRADE_V5.md) | § 1 Node 24 · § 2 ESM · § 3 `exports` · § 4 testing · § 5 modules · § 6 deps · § 7 OpenSearch · § 8 AWS SDK · § 9 L1/L2 · § 10 `@field()` · § 11 trust · § 12 `src/cores/` · § 13 B10 · § 14 audit |
|
|
175
|
+
| [HOW_TO_UPGRADE_V4.md](HOW_TO_UPGRADE_V4.md) | v3 → v4 (historical) |
|
|
176
|
+
| [baseline.md](docs/v5/baseline.md) | B0-a baseline: link state, boot, run modes, test counts, public names |
|
|
177
|
+
| [B0-local-harness.md](docs/v5/B0-local-harness.md) | B0 local harness: the local run path as the verification gate |
|
|
178
|
+
| [B1-packaging.md](docs/v5/B1-packaging.md) | B1 packaging: dual entry, `exports`, single instance |
|
|
179
|
+
| [B2-inventory.md](docs/v5/B2-inventory.md) | B2 (dependencies and coupling): measured inventory |
|
|
180
|
+
| [B2-a-deps.md](docs/v5/B2-a-deps.md) | B2-a: dependencies out: `request`, `lodash`, `ioredis`, `memcached` |
|
|
181
|
+
| [B2-b-inventory.md](docs/v5/B2-b-inventory.md) | B2-b (search): measured inventory |
|
|
182
|
+
| [B2-b-search.md](docs/v5/B2-b-search.md) | B2-b search: OpenSearch client, ES names out, lazy `$OS2` |
|
|
183
|
+
| [B2-c-inventory.md](docs/v5/B2-c-inventory.md) | B2-c (AWS SDK soft coupling): measured inventory |
|
|
184
|
+
| [B2-c-aws.md](docs/v5/B2-c-aws.md) | B2-c AWS SDK: optional peers, lazy loading, local types, `PERF` lines |
|
|
185
|
+
| [B3-inventory.md](docs/v5/B3-inventory.md) | B3 (L1/L2 integration): measured inventory |
|
|
186
|
+
| [B3-l1-l2.md](docs/v5/B3-l1-l2.md) | B3 L1/L2 merge: one definition per name, removed aliases, renamed files |
|
|
187
|
+
| [B4-inventory.md](docs/v5/B4-inventory.md) | B4 (field annotations): measured inventory and experiments |
|
|
188
|
+
| [B4-field-annotation.md](docs/v5/B4-field-annotation.md) | B4: `@field()` in lemon-model, generated registry removed |
|
|
189
|
+
| [B5-inventory.md](docs/v5/B5-inventory.md) | B5 inventory: trust boundary and behaviour contract |
|
|
190
|
+
| [B5-trust-boundary.md](docs/v5/B5-trust-boundary.md) | B5: trust boundary and behaviour contract |
|
|
191
|
+
| [B6-dou-migration.md](docs/v5/B6-dou-migration.md) | B6: migrating a service that carries a `src/cores/` copy |
|
|
192
|
+
| [B7-perf-trace.md](docs/v5/B7-perf-trace.md) | B7: per-request `PERF` lines (`handle`, `request` + 4 steps) |
|
|
193
|
+
| [B8-kms-fetch.md](docs/v5/B8-kms-fetch.md) | B8: KMS `Decrypt` without the SDK (SigV4 + Node `https`) |
|
|
194
|
+
| [B10-context-source.md](docs/v5/B10-context-source.md) | B10: the first request path in `context.source` (Korean) |
|
|
195
|
+
| [B10-fields-types.md](docs/v5/B10-fields-types.md) | B10: field name/type consistency check `lemon-fields-types` (Korean) |
|
|
196
|
+
| [B10-header-log-mask.md](docs/v5/B10-header-log-mask.md) | B10: masking sensitive headers in logs (Korean) |
|
|
197
|
+
| [B10-report-account.md](docs/v5/B10-report-account.md) | B10: choosing the SNS account number in `doReportError()` (Korean) |
|
|
198
|
+
| [B10-report-circular.md](docs/v5/B10-report-circular.md) | B10: circular structures in error reports (Korean) |
|
|
199
|
+
| [B10-verify-enforce.md](docs/v5/B10-verify-enforce.md) | B10: runbook for switching to `PROTOCOL_VERIFY=enforce` (Korean) |
|
|
200
|
+
| [B11-deps-audit.md](docs/v5/B11-deps-audit.md) | B11: `npm audit --omit=dev` 0, `query-string` → `qs`, `uuid` removed (Korean) |
|
|
201
|
+
| [B13-access-policy.md](docs/v5/B13-access-policy.md) | B13: default data-access policy of `AbstractCRUDController` (`AccessPolicy`, `canDo` scopes) |
|
|
202
|
+
| [docs/specs/](docs/specs/) | `$T`, `$U` characterization specs |
|
|
203
|
+
| [docs/header-identity-token.md](docs/header-identity-token.md) | Identity token header |
|
|
204
|
+
| [CONTRIBUTING](CONTRIBUTING.md), [SECURITY](SECURITY.md), [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md) | PR process; supported versions; conduct |
|
|
205
|
+
| [CHANGELOG.md](CHANGELOG.md) | Unreleased 5.x entry (B13), then stops at 1.2.0 (2019); see VERSION INFO |
|
|
180
206
|
|
|
181
207
|
## Contribution
|
|
182
208
|
|
|
@@ -194,6 +220,12 @@ See [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md)
|
|
|
194
220
|
|
|
195
221
|
| Version | Description
|
|
196
222
|
|-- |--
|
|
223
|
+
| unreleased (v5) | B10: `getHelloArn()` account (§ 13.1), circular-safe reports (§ 13.2), masked header logs (§ 13.3), enforce runbook + masked config log (§ 13.4), `lemon-fields-types` (§ 13.5); `LOCAL_TRANSPORT=mock` opt-in (§ 11.3.1).
|
|
224
|
+
| 5.0.4 | `context.source` carries the first request path; `npm audit --omit=dev` 0 (`qs`, `randomUUID()`, AWS SDK `^3.1159.0`).
|
|
225
|
+
| 5.0.3 | KMS `Decrypt` via SigV4 + Node `https`, without `@aws-sdk/client-kms` on the boot path.
|
|
226
|
+
| 5.0.2 | per-request `PERF` lines (`request`, `handle`).
|
|
227
|
+
| 5.0.1 | `GET /<type>/fields/admin` + `checkFieldsAdmin()`; env `DEFAULT_TIME_ZONE`, `DATE_ONLY_CLOCK`, `SID_LEGACY_ACCESS`.
|
|
228
|
+
| 5.0.0 | Node 24, ESM entry + `exports`, AWS SDK optional peers, OpenSearch client, `@field()`, signed protocol calls.
|
|
197
229
|
| 4.3.0 | embed cores template layer as extended/cores
|
|
198
230
|
| 4.2.6 | optimized `$protocol.execute()` to support async lambda invocation.
|
|
199
231
|
| 4.2.5 | optimized `isBase64Encoded` to support apigwBinary. (from `4.1.17`)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `bin/lemon-fields-types.mjs` (lemon-core)
|
|
4
|
+
* - check that one field name has one type across the stored models of one OpenSearch index (`$FIELD` models).
|
|
5
|
+
* - usage: `lemon-fields-types [options]` (installed bin) / `npx lemon-fields-types` / `npm run fields:types -- [options]`.
|
|
6
|
+
* - all logic is in `lib/fields-types.mjs`; this file only sets the exit code.
|
|
7
|
+
*/
|
|
8
|
+
//* v5 B10-5: the CLI entry of the shared field-type checker (ported from lemon-templates-api `bin/fields-types.mjs`).
|
|
9
|
+
import { run } from './lib/fields-types.mjs';
|
|
10
|
+
|
|
11
|
+
// run on the real file system; `run` never throws and returns the exit code.
|
|
12
|
+
process.exitCode = run(process.argv.slice(2));
|