@nexusm/mcp-server 0.1.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/LICENSE +21 -0
- package/README.md +13 -0
- package/RUNBOOK.md +190 -0
- package/dist/auth.d.ts +49 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +62 -0
- package/dist/auth.js.map +1 -0
- package/dist/errors.d.ts +211 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +245 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +146 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics.d.ts +146 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +245 -0
- package/dist/metrics.js.map +1 -0
- package/dist/tools/context.d.ts +48 -0
- package/dist/tools/context.d.ts.map +1 -0
- package/dist/tools/context.js +229 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/index.d.ts +12 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +19 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/memory_create.d.ts +37 -0
- package/dist/tools/memory_create.d.ts.map +1 -0
- package/dist/tools/memory_create.js +242 -0
- package/dist/tools/memory_create.js.map +1 -0
- package/dist/tools/memory_feedback.d.ts +44 -0
- package/dist/tools/memory_feedback.d.ts.map +1 -0
- package/dist/tools/memory_feedback.js +259 -0
- package/dist/tools/memory_feedback.js.map +1 -0
- package/dist/tools/memory_search.d.ts +44 -0
- package/dist/tools/memory_search.d.ts.map +1 -0
- package/dist/tools/memory_search.js +160 -0
- package/dist/tools/memory_search.js.map +1 -0
- package/dist/tools/types.d.ts +36 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +29 -0
- package/dist/tools/types.js.map +1 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 10CG
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# nexusm-mcp-server
|
|
2
|
+
|
|
3
|
+
Nexusm MCP Server — generic MCP server exposing Nexusm core capabilities (memory, conversation, knowledge, feedback, context) to MCP clients via `@modelcontextprotocol/sdk` stdio + Streamable HTTP transports.
|
|
4
|
+
|
|
5
|
+
Published to npm as **`@nexusm/mcp-server`**.
|
|
6
|
+
|
|
7
|
+
> Tracked in Nexusm main repo: [`packages/nexusm-mcp-server`](https://forgejo.10cg.pub/10CG/nexus/src/branch/main/packages/nexusm-mcp-server) (US-037 v7.0).
|
|
8
|
+
|
|
9
|
+
## Status
|
|
10
|
+
|
|
11
|
+
**Wave 2 done (2026-05-22)**: 4 tools fully wired to `@nexusm/sdk` (context_retrieve / memory_search / memory_create / memory_feedback) + full §M-3 HTTP→MCP error mapping (`mapHttpStatusToMcpError` + 2 new error codes Unauthorized/RateLimited) + Prometheus metrics with cardinality guard + cross-substory + E2E + schema_sync integration tests. Wave 3 (nexus-claude-plugin Anthropic marketplace) pending — see [proposal](https://forgejo.10cg.pub/10CG/nexus/src/branch/main/openspec/changes/us-037-mcp-server-exposure/proposal.md).
|
|
12
|
+
|
|
13
|
+
**Known Wave 2 limitations**: (1) CI red until Gate-1 — `@nexusm/sdk@1.3.0` npm publish pending (user action; SDK rename merged at `1fbdd69` in `nexus-sdk-js` main); (2) integration tests env-gated (require `NEXUS_TEST_API_URL/TOKEN/TENANT_ID` Forgejo secrets, currently dormant); (3) Python backend `mcp.py` metrics defined but emit-site wiring deferred to Wave 3 (FU-MCP-BACKEND-EMIT-WIRING); (4) HTTP transport per-request `server.connect()` is scaffold-only — Wave 3 entry condition (FU-MCP-HTTP-SESSION) before plugin TASK-019 E2E runs.
|
package/RUNBOOK.md
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# nexusm-mcp-server RUNBOOK
|
|
2
|
+
|
|
3
|
+
> **Status**: in place at `packages/nexusm-mcp-server/RUNBOOK.md`; moved into this submodule at Wave 0 close (2026-05-21).
|
|
4
|
+
> **Owner**: 10CG Backend / DevOps
|
|
5
|
+
> **Created**: 2026-05-09 (US-037 Phase B Wave 0)
|
|
6
|
+
> **Last revised**: 2026-05-22 (Wave 1 R1 audit amendments — removed `description-clean` row from §5 until Wave 2 CI matrix expansion)
|
|
7
|
+
> **Related**: [proposal.md §C-5](https://forgejo.10cg.pub/10CG/nexus/src/branch/main/openspec/changes/us-037-mcp-server-exposure/proposal.md) + [detailed-tasks.yaml TASK-002 / TASK-008](https://forgejo.10cg.pub/10CG/nexus/src/branch/main/openspec/changes/us-037-mcp-server-exposure/detailed-tasks.yaml)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. npm publish Failure Modes
|
|
12
|
+
|
|
13
|
+
### 1.1 Rate Limited (HTTP 429)
|
|
14
|
+
|
|
15
|
+
**Symptom**: `npm publish` fails with `429 Too Many Requests`.
|
|
16
|
+
|
|
17
|
+
**Cause**: npm registry has anti-abuse rate limits per token.
|
|
18
|
+
|
|
19
|
+
**Recovery**:
|
|
20
|
+
1. Wait 5-10 min before retry.
|
|
21
|
+
2. If persistent (> 30 min), check npm status page: https://status.npmjs.org/
|
|
22
|
+
3. Workaround: use `--registry https://registry.npmjs.org/` (force public, sometimes mirrors lag).
|
|
23
|
+
|
|
24
|
+
**Avoid**: Don't retry in tight loop — will trigger longer ban.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
### 1.2 Token Expired / Unauthorized (HTTP 401)
|
|
29
|
+
|
|
30
|
+
**Symptom**: `npm publish` fails with `401 Unauthorized` or `EAUTHIP`.
|
|
31
|
+
|
|
32
|
+
**Cause**: `NPM_TOKEN` granular access token expired (max 90-day lifetime since 2025 npm policy) or revoked.
|
|
33
|
+
|
|
34
|
+
**Recovery**:
|
|
35
|
+
1. Login to npmjs.com with org account.
|
|
36
|
+
2. Profile → Access Tokens → Granular Access Tokens → "Generate New Token". Configure:
|
|
37
|
+
- Bypass 2FA: ✅ (required for CI automation)
|
|
38
|
+
- Organizations → `nexusm` → Read and write
|
|
39
|
+
- Expiration: 90 days (max)
|
|
40
|
+
3. Update Forgejo repo secret (note: `PUT` method + `/actions/secrets/` path):
|
|
41
|
+
```bash
|
|
42
|
+
forgejo PUT /repos/10CG/nexusm-mcp-server/actions/secrets/NPM_TOKEN -d '{"data":"<new-token>"}'
|
|
43
|
+
```
|
|
44
|
+
4. Re-run failed CI workflow (Forgejo Actions → re-run).
|
|
45
|
+
|
|
46
|
+
**Rotation cadence**: Quarterly (Jan / Apr / Jul / Oct, 1st Monday) — required because npm granular tokens cap at 90 days. Schedule in calendar.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
### 1.3 Namespace Not Registered / Forbidden (HTTP 403)
|
|
51
|
+
|
|
52
|
+
**Symptom**: `npm publish` fails with `403 Forbidden — You do not have permission to publish "@nexusm/mcp-server"`.
|
|
53
|
+
|
|
54
|
+
**Cause**: `@nexusm` scoped namespace not registered to org account, or token doesn't have publish scope on this namespace.
|
|
55
|
+
|
|
56
|
+
**Recovery**:
|
|
57
|
+
1. Verify namespace ownership: `npm access ls-packages @nexusm`.
|
|
58
|
+
2. If namespace not owned, register via npmjs.com → "Add Organization" → name: `nexusm`, type: Free Open Source.
|
|
59
|
+
3. Re-link granular access token to org: Profile → Access Tokens → edit token → Organizations → `nexusm` → Read and write.
|
|
60
|
+
4. Retry publish.
|
|
61
|
+
|
|
62
|
+
**Long-term safeguard**: `@nexusm` scope is owned by 10CG since 2026-05-21 (Wave 0 closure). The original A2-D-1 unscoped fallback (`nexus-mcp-server`) is no longer available — that name is taken on npm by an unrelated party. If `@nexusm` is ever lost, immediately reclaim via npmjs.com support; do NOT fall back to unscoped.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### 1.4 Disaster Recovery: Bad Version Published
|
|
67
|
+
|
|
68
|
+
**Symptom**: Critical bug shipped in `0.x.y`, users hitting it.
|
|
69
|
+
|
|
70
|
+
**Recovery options** (in priority order):
|
|
71
|
+
|
|
72
|
+
1. **Hotfix `0.x.(y+1)`** (preferred): bump patch, fix bug, publish. Existing users get update via npm update.
|
|
73
|
+
2. **`npm deprecate @nexusm/mcp-server@0.x.y "reason"`**: marks version as deprecated; users see warning on install but version stays available.
|
|
74
|
+
3. **`npm unpublish @nexusm/mcp-server@0.x.y --force`**: removes from registry. **DANGEROUS** — only allowed within 72h of publish per npm policy. Will break any user who has it pinned.
|
|
75
|
+
|
|
76
|
+
**Decision matrix**:
|
|
77
|
+
| Severity | Action |
|
|
78
|
+
|----------|--------|
|
|
79
|
+
| Cosmetic / non-functional bug | Hotfix `0.x.(y+1)` |
|
|
80
|
+
| Security vuln (CVE level) | Hotfix + deprecate `0.x.y` |
|
|
81
|
+
| Critical breakage (data loss / DoS) | Hotfix + deprecate; consider unpublish if < 24h |
|
|
82
|
+
| Wrong file shipped (e.g., secret in tarball) | Unpublish IMMEDIATELY (within 72h window) + rotate any leaked credentials |
|
|
83
|
+
|
|
84
|
+
**Reference**: https://docs.npmjs.com/policies/unpublish
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 2. NPM_TOKEN Rotation
|
|
89
|
+
|
|
90
|
+
### Schedule
|
|
91
|
+
|
|
92
|
+
- **Quarterly**: Jan / Apr / Jul / Oct (1st Monday) — required because npm granular tokens cap at 90 days
|
|
93
|
+
- **Ad-hoc**: when leak suspected, when team member leaves, when 90-day expiration ≤ 2 weeks away
|
|
94
|
+
|
|
95
|
+
### Procedure
|
|
96
|
+
|
|
97
|
+
1. Generate new granular access token (npmjs.com → Profile → Access Tokens → Granular Access Tokens → "Generate New Token"). Settings:
|
|
98
|
+
- Bypass 2FA: ✅
|
|
99
|
+
- Organizations → `nexusm` → Read and write
|
|
100
|
+
- Expiration: 90 days
|
|
101
|
+
2. Test new token locally:
|
|
102
|
+
```bash
|
|
103
|
+
NPM_TOKEN=<new> npm whoami --registry https://registry.npmjs.org/
|
|
104
|
+
```
|
|
105
|
+
3. Update Forgejo repo secret (PUT + `/actions/secrets/`):
|
|
106
|
+
```bash
|
|
107
|
+
forgejo PUT /repos/10CG/nexusm-mcp-server/actions/secrets/NPM_TOKEN -d '{"data":"<new>"}'
|
|
108
|
+
```
|
|
109
|
+
4. Trigger a no-op CI run (push empty commit) to verify CI auth works with new token.
|
|
110
|
+
5. Revoke old token (npmjs.com → Access Tokens → Delete).
|
|
111
|
+
6. Update calendar reminder for next rotation (+3 months).
|
|
112
|
+
|
|
113
|
+
### Audit Trail
|
|
114
|
+
|
|
115
|
+
Log each rotation in `nexusm-mcp-server/CHANGELOG.md` under `## Operations`:
|
|
116
|
+
```
|
|
117
|
+
- 2026-04-XX: NPM_TOKEN rotated (rotated_by=<name>, old_token_revoked=2026-04-XX)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## 3. Disaster Recovery — Forgejo Repo Loss
|
|
123
|
+
|
|
124
|
+
### Scenario: `10CG/nexusm-mcp-server` Forgejo repo deleted / corrupted
|
|
125
|
+
|
|
126
|
+
**Recovery**:
|
|
127
|
+
|
|
128
|
+
1. **Local clones still have full history** — any team member with a local clone can restore.
|
|
129
|
+
2. Rebuild from local:
|
|
130
|
+
```bash
|
|
131
|
+
# In team member's local clone:
|
|
132
|
+
git remote rename origin forgejo-old # save old remote ref just in case
|
|
133
|
+
forgejo POST /orgs/10CG/repos -d '{"name":"nexusm-mcp-server",...}'
|
|
134
|
+
git remote add origin ssh://forgejo@forgejo.10cg.pub/10CG/nexusm-mcp-server.git
|
|
135
|
+
git push -u origin main --tags
|
|
136
|
+
```
|
|
137
|
+
3. Re-add Forgejo Actions secrets (NPM_TOKEN) per §2.
|
|
138
|
+
4. Update main nexus repo `.gitmodules` if URL changed.
|
|
139
|
+
5. Notify all submodule consumers to re-init: `git submodule update --init`.
|
|
140
|
+
|
|
141
|
+
### Scenario: GitHub mirror (`simonfishgit/nexus-claude-plugin`) lost
|
|
142
|
+
|
|
143
|
+
GitHub mirror is auto-synced from Forgejo via `.forgejo/workflows/mirror.yml` (TASK-024). If mirror disappears:
|
|
144
|
+
|
|
145
|
+
1. Recreate GitHub repo (any team member with PAT).
|
|
146
|
+
2. Re-add `GITHUB_PAT` secret in Forgejo `nexus-claude-plugin` repo.
|
|
147
|
+
3. Push current Forgejo HEAD: `git push github main`.
|
|
148
|
+
|
|
149
|
+
This is the Anthropic marketplace submission path (`plugin.json author=10CG`, mirror is just for discovery via simonfishgit).
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 4. Namespace Ownership
|
|
154
|
+
|
|
155
|
+
- npm: `@nexusm/*` scoped namespace owned by 10CG organization account on npmjs.com.
|
|
156
|
+
- Forgejo: `10CG/nexusm-mcp-server` repo, admin = 10CG org admins.
|
|
157
|
+
- GitHub mirror: `simonfishgit/nexus-claude-plugin` (personal account, bus factor mitigation via Forgejo Actions auto-sync per A2-D-3).
|
|
158
|
+
|
|
159
|
+
If 10CG npm org access lost (admin departure / account compromise):
|
|
160
|
+
1. Contact npm support (support@npmjs.com) with org admin proof.
|
|
161
|
+
2. Worst case: fallback to unscoped `nexusm-mcp-server` package, update all references (proposal A2-D-1 fallback).
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 5. CI Workflow Reference
|
|
166
|
+
|
|
167
|
+
`.forgejo/workflows/ci.yml` (TASK-008 / TASK-017 / TASK-025):
|
|
168
|
+
|
|
169
|
+
| Step | Trigger | Purpose | Failure → Action |
|
|
170
|
+
|------|---------|---------|-----------------|
|
|
171
|
+
| `lint` | push, PR | eslint + prettier | Fix code style; check `.eslintrc` |
|
|
172
|
+
| `tsc` | push, PR | TypeScript type-check | Fix type errors; SDK Zod schema drift may indicate need to bump @nexusm/sdk |
|
|
173
|
+
| `test:unit` | push, PR | vitest unit tests | Local repro: `npm test` |
|
|
174
|
+
| `test:integration` | push, PR | mcp-cli E2E (3 platform matrix Linux × Node 18/20 + macOS × Node 20) | Check matrix log; Aether runner Windows OOS Phase 1 |
|
|
175
|
+
| `schema_sync` | push, PR | MCP inputSchema vs @nexusm/sdk Zod schema | Update one or the other to match |
|
|
176
|
+
| `publish` | tag `v*` | npm publish + Forgejo release | Per §1 failure modes |
|
|
177
|
+
|
|
178
|
+
> **Wave 1 caveat (2026-05-22)**: Only `lint` + `tsc` (build) are currently implemented in `.forgejo/workflows/ci.yml`. `test:unit` / `test:integration` / `schema_sync` / `publish` are planned for Wave 2 TASK-014 (test matrix) and Wave 4 TASK-026 (publish). A `description-clean` step (grep `R[0-9]+|C-[0-9]+|M-[0-9]+` audit-marker leakage in `src/tools/*.ts` `description:` fields) was originally listed but deferred — for Wave 1 it is enforced via PR code review (R1 audit caught + fixed 2 leaks 2026-05-22).
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 6. Operations Log
|
|
183
|
+
|
|
184
|
+
(to be appended chronologically)
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
2026-XX-XX Initial repo created by <ops>; NPM_TOKEN automation token configured
|
|
188
|
+
2026-XX-XX Phase B Wave 1 first commit (TASK-003 MCP scaffold)
|
|
189
|
+
...
|
|
190
|
+
```
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth / env config loader for Nexusm MCP server (US-037b).
|
|
3
|
+
*
|
|
4
|
+
* Loads required env vars on startup and fails fast if any is missing.
|
|
5
|
+
*
|
|
6
|
+
* Per R2 C-1 (proposal §283): `NEXUS_USER_ID` is intentionally NOT loaded
|
|
7
|
+
* here — `user_id` is supplied per-call via MCP tool input args.
|
|
8
|
+
*
|
|
9
|
+
* SECURITY:
|
|
10
|
+
* - The Bearer token (NEXUS_API_TOKEN) MUST NEVER appear in stdout
|
|
11
|
+
* (would pollute MCP stdio transport, breaking the client),
|
|
12
|
+
* nor in stderr error messages, nor in any log line.
|
|
13
|
+
* - All diagnostic output uses env var *names* only, never values.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Loaded, validated auth configuration.
|
|
17
|
+
*
|
|
18
|
+
* Exported as a named interface so downstream modules (notably
|
|
19
|
+
* `errors.ts` per TASK-007 / TASK-013) can import the contract
|
|
20
|
+
* without re-declaring it.
|
|
21
|
+
*/
|
|
22
|
+
export interface AuthConfig {
|
|
23
|
+
/** Base URL of the Nexus HTTP API (no trailing slash enforced). */
|
|
24
|
+
readonly apiUrl: string;
|
|
25
|
+
/** Bearer token for Nexus API. NEVER log this value. */
|
|
26
|
+
readonly apiToken: string;
|
|
27
|
+
/** Tenant identifier for multi-tenant routing. */
|
|
28
|
+
readonly tenantId: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Stream sink for diagnostics. Injectable for testing only; defaults to
|
|
32
|
+
* `process.stderr` so that no diagnostic ever lands on stdout (which is
|
|
33
|
+
* reserved for the MCP stdio transport).
|
|
34
|
+
*/
|
|
35
|
+
export interface AuthIO {
|
|
36
|
+
stderr: NodeJS.WritableStream;
|
|
37
|
+
exit: (code: number) => never;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Load and validate auth config from `process.env`.
|
|
41
|
+
*
|
|
42
|
+
* On any missing required var, writes a clear, token-free error message to
|
|
43
|
+
* `stderr` and calls `process.exit(1)`. Empty string and whitespace-only
|
|
44
|
+
* values are treated as missing (env var inheritance from parent shells
|
|
45
|
+
* frequently produces empty values, which would otherwise produce a
|
|
46
|
+
* confusing "401 Unauthorized" downstream).
|
|
47
|
+
*/
|
|
48
|
+
export declare function loadAuthConfig(env?: NodeJS.ProcessEnv, io?: AuthIO): AuthConfig;
|
|
49
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAOH;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;GAIG;AACH,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;CAC/B;AAQD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,EAAE,GAAE,MAAkB,GACrB,UAAU,CAiCZ"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth / env config loader for Nexusm MCP server (US-037b).
|
|
3
|
+
*
|
|
4
|
+
* Loads required env vars on startup and fails fast if any is missing.
|
|
5
|
+
*
|
|
6
|
+
* Per R2 C-1 (proposal §283): `NEXUS_USER_ID` is intentionally NOT loaded
|
|
7
|
+
* here — `user_id` is supplied per-call via MCP tool input args.
|
|
8
|
+
*
|
|
9
|
+
* SECURITY:
|
|
10
|
+
* - The Bearer token (NEXUS_API_TOKEN) MUST NEVER appear in stdout
|
|
11
|
+
* (would pollute MCP stdio transport, breaking the client),
|
|
12
|
+
* nor in stderr error messages, nor in any log line.
|
|
13
|
+
* - All diagnostic output uses env var *names* only, never values.
|
|
14
|
+
*/
|
|
15
|
+
/** Required env var keys. Order is preserved when reporting missing vars. */
|
|
16
|
+
const REQUIRED_ENV_VARS = ['NEXUS_API_URL', 'NEXUS_API_TOKEN', 'NEXUS_TENANT_ID'];
|
|
17
|
+
const defaultIO = {
|
|
18
|
+
stderr: process.stderr,
|
|
19
|
+
// Cast: process.exit is typed as `(code?) => never` but TS sometimes widens.
|
|
20
|
+
exit: ((code) => process.exit(code)),
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Load and validate auth config from `process.env`.
|
|
24
|
+
*
|
|
25
|
+
* On any missing required var, writes a clear, token-free error message to
|
|
26
|
+
* `stderr` and calls `process.exit(1)`. Empty string and whitespace-only
|
|
27
|
+
* values are treated as missing (env var inheritance from parent shells
|
|
28
|
+
* frequently produces empty values, which would otherwise produce a
|
|
29
|
+
* confusing "401 Unauthorized" downstream).
|
|
30
|
+
*/
|
|
31
|
+
export function loadAuthConfig(env = process.env, io = defaultIO) {
|
|
32
|
+
const missing = [];
|
|
33
|
+
const values = {};
|
|
34
|
+
for (const key of REQUIRED_ENV_VARS) {
|
|
35
|
+
const raw = env[key];
|
|
36
|
+
if (raw === undefined || raw.trim() === '') {
|
|
37
|
+
missing.push(key);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
values[key] = raw.trim();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (missing.length > 0) {
|
|
44
|
+
// Build message from var *names* only — never values. This guarantees
|
|
45
|
+
// a leaked token cannot reach stderr via this path even if a future
|
|
46
|
+
// refactor accidentally passes `env` into the message.
|
|
47
|
+
const list = missing.join(', ');
|
|
48
|
+
const noun = missing.length === 1 ? 'variable is' : 'variables are';
|
|
49
|
+
const msg = `[nexusm-mcp-server] Required environment ${noun} missing: ${list}. ` +
|
|
50
|
+
`Set them before starting the server. See RUNBOOK.md.\n`;
|
|
51
|
+
io.stderr.write(msg);
|
|
52
|
+
io.exit(1);
|
|
53
|
+
// `exit` is typed `never`; unreachable, but satisfies control-flow analysis.
|
|
54
|
+
throw new Error('unreachable');
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
apiUrl: values.NEXUS_API_URL,
|
|
58
|
+
apiToken: values.NEXUS_API_TOKEN,
|
|
59
|
+
tenantId: values.NEXUS_TENANT_ID,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,6EAA6E;AAC7E,MAAM,iBAAiB,GAAG,CAAC,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,CAAU,CAAC;AA8B3F,MAAM,SAAS,GAAW;IACxB,MAAM,EAAE,OAAO,CAAC,MAAM;IACtB,6EAA6E;IAC7E,IAAI,EAAE,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAA4B;CACxE,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAyB,OAAO,CAAC,GAAG,EACpC,KAAa,SAAS;IAEtB,MAAM,OAAO,GAAqB,EAAE,CAAC;IACrC,MAAM,MAAM,GAA4C,EAAE,CAAC;IAE3D,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACrB,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,sEAAsE;QACtE,oEAAoE;QACpE,uDAAuD;QACvD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,eAAe,CAAC;QACpE,MAAM,GAAG,GACP,4CAA4C,IAAI,aAAa,IAAI,IAAI;YACrE,wDAAwD,CAAC;QAC3D,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACrB,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACX,6EAA6E;QAC7E,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IAED,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,aAAuB;QACtC,QAAQ,EAAE,MAAM,CAAC,eAAyB;QAC1C,QAAQ,EAAE,MAAM,CAAC,eAAyB;KAC3C,CAAC;AACJ,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error contract and HTTP→MCP mapping for the Nexusm MCP server.
|
|
3
|
+
*
|
|
4
|
+
* Wave 1 (TASK-007): declared the type surface — NexusError, McpErrorCode,
|
|
5
|
+
* interface stubs for AuthError / NetworkError / CancelError.
|
|
6
|
+
* Wave 2B (TASK-013): implements the full HTTP-status → MCP-error-code
|
|
7
|
+
* mapping (proposal §M-3) via `mapHttpStatusToMcpError` and
|
|
8
|
+
* `isAxiosLikeError`.
|
|
9
|
+
*
|
|
10
|
+
* SECURITY (matches auth.ts discipline):
|
|
11
|
+
* `toJSON()` deliberately omits `cause` and `stack`. An axios-style error
|
|
12
|
+
* attached as `cause` typically carries the original request config
|
|
13
|
+
* including the `Authorization: Bearer <token>` header. Leaking that via a
|
|
14
|
+
* JSON.stringify of a NexusError would defeat the token-redaction guarantee
|
|
15
|
+
* of auth.ts. If callers need to inspect the cause they must do so
|
|
16
|
+
* explicitly, not via serialization.
|
|
17
|
+
*/
|
|
18
|
+
import type { AuthConfig } from './auth.js';
|
|
19
|
+
/**
|
|
20
|
+
* MCP / JSON-RPC error codes surfaced by this server.
|
|
21
|
+
*
|
|
22
|
+
* Values mirror `@modelcontextprotocol/sdk` `ErrorCode` enum
|
|
23
|
+
* (`dist/esm/types.d.ts`). We re-declare locally rather than re-export
|
|
24
|
+
* the SDK enum so that:
|
|
25
|
+
* 1. errors.ts has zero runtime import from the SDK (keeps the
|
|
26
|
+
* contract layer independent of SDK version churn)
|
|
27
|
+
* 2. TASK-013's mapping logic and tests have a single source of truth
|
|
28
|
+
* for which codes this server is allowed to emit
|
|
29
|
+
*
|
|
30
|
+
* Scope decision (resolved ambiguity from spec):
|
|
31
|
+
* We enumerate the four JSON-RPC standard codes required by §M-3
|
|
32
|
+
* (`InvalidRequest`, `MethodNotFound`, `InvalidParams`, `InternalError`),
|
|
33
|
+
* plus `ParseError` (-32700) for completeness of the JSON-RPC base
|
|
34
|
+
* set, plus `ConnectionClosed` (-32000) and `RequestTimeout` (-32001)
|
|
35
|
+
* which the SDK defines and which `NetworkError` / `CancelError`
|
|
36
|
+
* downstream mappings will need. UrlElicitationRequired (-32042) is
|
|
37
|
+
* intentionally omitted — not in scope for Wave 1 / Wave 2.
|
|
38
|
+
*/
|
|
39
|
+
export declare enum McpErrorCode {
|
|
40
|
+
ParseError = -32700,
|
|
41
|
+
InvalidRequest = -32600,
|
|
42
|
+
MethodNotFound = -32601,
|
|
43
|
+
InvalidParams = -32602,
|
|
44
|
+
InternalError = -32603,
|
|
45
|
+
ConnectionClosed = -32000,
|
|
46
|
+
RequestTimeout = -32001,
|
|
47
|
+
/**
|
|
48
|
+
* TASK-013 additions: custom codes in the application-defined range
|
|
49
|
+
* (-32099..-32000 is reserved for implementation; we use the next
|
|
50
|
+
* available slots above -32000 for semantic clarity).
|
|
51
|
+
*
|
|
52
|
+
* Unauthorized (-32011): 401 / 403 from Nexus REST — semantically distinct
|
|
53
|
+
* from InvalidRequest (-32600) so clients can detect auth failures without
|
|
54
|
+
* parsing the message string.
|
|
55
|
+
* RateLimited (-32012): 429 Retry-After. Clients should honor
|
|
56
|
+
* `data.retry_after_seconds` before retrying.
|
|
57
|
+
*/
|
|
58
|
+
Unauthorized = -32011,
|
|
59
|
+
RateLimited = -32012
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Base error for all errors this MCP server emits.
|
|
63
|
+
*
|
|
64
|
+
* Carries enough structured context to translate a thrown `NexusError` into a
|
|
65
|
+
* JSON-RPC error response without re-inspecting the underlying axios / SDK
|
|
66
|
+
* error.
|
|
67
|
+
*/
|
|
68
|
+
export declare class NexusError extends Error {
|
|
69
|
+
/**
|
|
70
|
+
* Upstream HTTP status (Nexus REST), or `null` when the error did not
|
|
71
|
+
* originate from an HTTP response (e.g. DNS failure, abort, internal
|
|
72
|
+
* invariant violation).
|
|
73
|
+
*/
|
|
74
|
+
readonly httpStatus: number | null;
|
|
75
|
+
/** MCP/JSON-RPC error code that this error will surface as. */
|
|
76
|
+
readonly mcpErrorCode: McpErrorCode;
|
|
77
|
+
/**
|
|
78
|
+
* Whether the MCP client may safely retry this request.
|
|
79
|
+
* Populated by `mapHttpStatusToMcpError` and the NLI/network helpers.
|
|
80
|
+
*/
|
|
81
|
+
readonly retryable: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Additional structured data surfaced in the JSON-RPC `error.data` field.
|
|
84
|
+
* Safe to serialize — must never contain auth tokens or raw SDK internals.
|
|
85
|
+
* Populated by the mapping layer (e.g. `retry_after_seconds`, `network`,
|
|
86
|
+
* `timeout`).
|
|
87
|
+
*/
|
|
88
|
+
readonly data?: Record<string, unknown>;
|
|
89
|
+
/**
|
|
90
|
+
* Underlying cause. Per ES2022 `Error.cause`. **Not serialized** by
|
|
91
|
+
* `toJSON()` — see file header SECURITY note.
|
|
92
|
+
*/
|
|
93
|
+
readonly cause?: unknown;
|
|
94
|
+
constructor(message: string, mcpErrorCode: McpErrorCode, httpStatus?: number | null, cause?: unknown, options?: {
|
|
95
|
+
retryable?: boolean;
|
|
96
|
+
data?: Record<string, unknown>;
|
|
97
|
+
});
|
|
98
|
+
/**
|
|
99
|
+
* Safe serialization. Deliberately omits `cause` and `stack` to
|
|
100
|
+
* prevent accidental token leakage if a caller logs the JSON form.
|
|
101
|
+
*
|
|
102
|
+
* `data` IS included — it is caller-controlled structured metadata that
|
|
103
|
+
* must never contain raw SDK objects (that would be caught during review
|
|
104
|
+
* of `mapHttpStatusToMcpError` callers).
|
|
105
|
+
*/
|
|
106
|
+
toJSON(): {
|
|
107
|
+
name: string;
|
|
108
|
+
message: string;
|
|
109
|
+
httpStatus: number | null;
|
|
110
|
+
mcpErrorCode: McpErrorCode;
|
|
111
|
+
data?: Record<string, unknown>;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Canonical type for a function that maps an HTTP status + response body to
|
|
116
|
+
* a `McpErrorCode`. `headers` is optional — only needed for 429 Retry-After
|
|
117
|
+
* extraction. This type is the public contract; the concrete implementation
|
|
118
|
+
* is `mapHttpStatusToMcpError`.
|
|
119
|
+
*/
|
|
120
|
+
export type ErrorMapping = (httpStatus: number | null, body: unknown, headers?: Record<string, string | string[] | undefined>) => NexusError;
|
|
121
|
+
/**
|
|
122
|
+
* Shape of an axios-like error thrown by `@nexusm/sdk`.
|
|
123
|
+
* We cannot import axios types here (would add a hard dep); instead we use
|
|
124
|
+
* structural duck-typing checked by `isAxiosLikeError`.
|
|
125
|
+
*/
|
|
126
|
+
interface AxiosLikeError {
|
|
127
|
+
isAxiosError: true;
|
|
128
|
+
message: string;
|
|
129
|
+
response?: {
|
|
130
|
+
status: number;
|
|
131
|
+
data?: unknown;
|
|
132
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
133
|
+
};
|
|
134
|
+
code?: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Type guard for axios-compatible errors thrown by `@nexusm/sdk`.
|
|
138
|
+
*
|
|
139
|
+
* Matches any object with `isAxiosError === true`, which is the canonical
|
|
140
|
+
* axios duck-type flag. This guard intentionally does NOT import axios — it
|
|
141
|
+
* keeps `errors.ts` free of SDK runtime dependencies.
|
|
142
|
+
*/
|
|
143
|
+
export declare function isAxiosLikeError(err: unknown): err is AxiosLikeError;
|
|
144
|
+
/**
|
|
145
|
+
* Canonical entrypoint for converting an upstream HTTP response (or SDK
|
|
146
|
+
* network/timeout error) into a typed `NexusError` with the correct
|
|
147
|
+
* `McpErrorCode`, `retryable` flag, and `data` extras.
|
|
148
|
+
*
|
|
149
|
+
* Proposal §M-3 mapping table:
|
|
150
|
+
*
|
|
151
|
+
* | httpStatus | McpErrorCode | retryable | data extras |
|
|
152
|
+
* |-------------------------|-------------------|-----------|--------------------------|
|
|
153
|
+
* | 401, 403 | Unauthorized | false | — |
|
|
154
|
+
* | 404 | MethodNotFound | false | — |
|
|
155
|
+
* | 422 | InvalidParams | false | — |
|
|
156
|
+
* | 429 | RateLimited | true* | retry_after_seconds?: n |
|
|
157
|
+
* | 503 | ConnectionClosed | true | — |
|
|
158
|
+
* | 5xx (else) | InternalError | true | — |
|
|
159
|
+
* | null + network=true | InternalError | true | network: true |
|
|
160
|
+
* | null + timeout=true | RequestTimeout | true | timeout: true |
|
|
161
|
+
*
|
|
162
|
+
* *429: retryable "after Retry-After header elapses" — we set retryable=true
|
|
163
|
+
* and populate `data.retry_after_seconds` so clients can honour the window.
|
|
164
|
+
*
|
|
165
|
+
* Note: HTTP 200 + body.errors != null is NOT an error; that is the
|
|
166
|
+
* partial-degradation path handled in tool handlers (see context.ts). This
|
|
167
|
+
* function is only invoked on non-2xx responses or SDK error throws.
|
|
168
|
+
*
|
|
169
|
+
* @param httpStatus HTTP status code, or `null` for non-HTTP errors.
|
|
170
|
+
* @param body Raw response body (typed `unknown`; we do not parse it).
|
|
171
|
+
* @param headers Response headers, used only to extract Retry-After on 429.
|
|
172
|
+
*/
|
|
173
|
+
export declare function mapHttpStatusToMcpError(httpStatus: number | null, body: unknown, headers?: Record<string, string | string[] | undefined>): NexusError;
|
|
174
|
+
/**
|
|
175
|
+
* Auth-origin error (401 / 403 from Nexus REST, or local auth-config
|
|
176
|
+
* issues surfaced after `loadAuthConfig`).
|
|
177
|
+
*
|
|
178
|
+
* `authConfigKey` is optional because not every auth failure points at
|
|
179
|
+
* a specific config field (e.g. a token that was valid at load but
|
|
180
|
+
* since revoked has no `AuthConfig` key to blame).
|
|
181
|
+
*/
|
|
182
|
+
export interface AuthError extends NexusError {
|
|
183
|
+
readonly authConfigKey?: keyof AuthConfig;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Network-origin error (DNS failure, connection refused, TLS error,
|
|
187
|
+
* read timeout). Per proposal §M-3, these map to `InternalError` with
|
|
188
|
+
* `error.data.network = true`, and the MCP client may retry.
|
|
189
|
+
*
|
|
190
|
+
* `retryable` is a hint to the client; the server itself does not
|
|
191
|
+
* retry (avoids double-counting under quota / Retry-After).
|
|
192
|
+
*/
|
|
193
|
+
export interface NetworkError extends NexusError {
|
|
194
|
+
readonly retryable: boolean;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Cancellation error — fired when an in-flight tool call is aborted.
|
|
198
|
+
*
|
|
199
|
+
* - `client_cancel`: MCP cancel notification from the client
|
|
200
|
+
* - `timeout`: server-side deadline elapsed
|
|
201
|
+
* - `signal`: AbortSignal propagated from a higher layer
|
|
202
|
+
*
|
|
203
|
+
* Per proposal §M-3, the server does **not** return a result when a
|
|
204
|
+
* cancel arrives; this error type exists so handlers can distinguish
|
|
205
|
+
* cancel from other failures in logs / metrics.
|
|
206
|
+
*/
|
|
207
|
+
export interface CancelError extends NexusError {
|
|
208
|
+
readonly reason: 'client_cancel' | 'timeout' | 'signal';
|
|
209
|
+
}
|
|
210
|
+
export {};
|
|
211
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,oBAAY,YAAY;IAEtB,UAAU,SAAS;IACnB,cAAc,SAAS;IACvB,cAAc,SAAS;IACvB,aAAa,SAAS;IACtB,aAAa,SAAS;IAEtB,gBAAgB,SAAS;IACzB,cAAc,SAAS;IACvB;;;;;;;;;;OAUG;IACH,YAAY,SAAS;IACrB,WAAW,SAAS;CACrB;AAED;;;;;;GAMG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC;;;;OAIG;IACH,SAAgB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1C,+DAA+D;IAC/D,SAAgB,YAAY,EAAE,YAAY,CAAC;IAE3C;;;OAGG;IACH,SAAgB,SAAS,EAAE,OAAO,CAAC;IAEnC;;;;;OAKG;IACH,SAAgB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/C;;;OAGG;IACH,SAAyB,KAAK,CAAC,EAAE,OAAO,CAAC;gBAGvC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,YAAY,EAC1B,UAAU,GAAE,MAAM,GAAG,IAAW,EAChC,KAAK,CAAC,EAAE,OAAO,EACf,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAChC;IAkBH;;;;;;;OAOG;IACI,MAAM,IAAI;QACf,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,YAAY,EAAE,YAAY,CAAC;QAC3B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAChC;CAkBF;AAMD;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,KACpD,UAAU,CAAC;AAEhB;;;;GAIG;AACH,UAAU,cAAc;IACtB,YAAY,EAAE,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE;QACT,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;KACzD,CAAC;IACF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,cAAc,CAMpE;AA8BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GACtD,UAAU,CAsFZ;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,SAAU,SAAQ,UAAU;IAC3C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,UAAU,CAAC;CAC3C;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,GAAG,QAAQ,CAAC;CACzD"}
|