@softacus-software/elwis-data-mcp 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/CHANGELOG.md +15 -0
- package/LICENSE +6 -0
- package/README.md +183 -0
- package/dist/app-scope.js +92 -0
- package/dist/app-scope.js.map +1 -0
- package/dist/artifact-read.js +114 -0
- package/dist/artifact-read.js.map +1 -0
- package/dist/audit.js +36 -0
- package/dist/audit.js.map +1 -0
- package/dist/builders/artifact-type-execute.js +100 -0
- package/dist/builders/artifact-type-execute.js.map +1 -0
- package/dist/builders/artifact-type-plan.js +139 -0
- package/dist/builders/artifact-type-plan.js.map +1 -0
- package/dist/builders/design-interview.js +246 -0
- package/dist/builders/design-interview.js.map +1 -0
- package/dist/builders/entity-lifecycle-execute.js +12 -0
- package/dist/builders/entity-lifecycle-execute.js.map +1 -0
- package/dist/builders/entity-lifecycle-plan.js +345 -0
- package/dist/builders/entity-lifecycle-plan.js.map +1 -0
- package/dist/builders/links-execute.js +50 -0
- package/dist/builders/links-execute.js.map +1 -0
- package/dist/builders/links-plan.js +62 -0
- package/dist/builders/links-plan.js.map +1 -0
- package/dist/builders/page-execute.js +38 -0
- package/dist/builders/page-execute.js.map +1 -0
- package/dist/builders/page-plan.js +148 -0
- package/dist/builders/page-plan.js.map +1 -0
- package/dist/builders/records-execute.js +24 -0
- package/dist/builders/records-execute.js.map +1 -0
- package/dist/builders/records-lifecycle-execute.js +30 -0
- package/dist/builders/records-lifecycle-execute.js.map +1 -0
- package/dist/builders/records-lifecycle-plan.js +199 -0
- package/dist/builders/records-lifecycle-plan.js.map +1 -0
- package/dist/builders/records-plan.js +74 -0
- package/dist/builders/records-plan.js.map +1 -0
- package/dist/builders/update-page-execute.js +38 -0
- package/dist/builders/update-page-execute.js.map +1 -0
- package/dist/builders/update-page-plan.js +137 -0
- package/dist/builders/update-page-plan.js.map +1 -0
- package/dist/builders/workflow-execute.js +11 -0
- package/dist/builders/workflow-execute.js.map +1 -0
- package/dist/builders/workflow-plan.js +115 -0
- package/dist/builders/workflow-plan.js.map +1 -0
- package/dist/cli/client-configs.js +98 -0
- package/dist/cli/client-configs.js.map +1 -0
- package/dist/cli/login.js +64 -0
- package/dist/cli/login.js.map +1 -0
- package/dist/cli/prompter.js +77 -0
- package/dist/cli/prompter.js.map +1 -0
- package/dist/cli/setup.js +214 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/config.js +38 -0
- package/dist/config.js.map +1 -0
- package/dist/confirm.js +22 -0
- package/dist/confirm.js.map +1 -0
- package/dist/elwis-api.js +96 -0
- package/dist/elwis-api.js.map +1 -0
- package/dist/http-client.js +142 -0
- package/dist/http-client.js.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/jwt.js +18 -0
- package/dist/jwt.js.map +1 -0
- package/dist/prune.js +9 -0
- package/dist/prune.js.map +1 -0
- package/dist/resolve.js +71 -0
- package/dist/resolve.js.map +1 -0
- package/dist/result.js +16 -0
- package/dist/result.js.map +1 -0
- package/dist/server.js +82 -0
- package/dist/server.js.map +1 -0
- package/dist/session-store.js +51 -0
- package/dist/session-store.js.map +1 -0
- package/dist/tools/build-artifact-type.js +36 -0
- package/dist/tools/build-artifact-type.js.map +1 -0
- package/dist/tools/build-links.js +33 -0
- package/dist/tools/build-links.js.map +1 -0
- package/dist/tools/build-page.js +40 -0
- package/dist/tools/build-page.js.map +1 -0
- package/dist/tools/build-workflow.js +36 -0
- package/dist/tools/build-workflow.js.map +1 -0
- package/dist/tools/create-application.js +44 -0
- package/dist/tools/create-application.js.map +1 -0
- package/dist/tools/create-artifacts.js +33 -0
- package/dist/tools/create-artifacts.js.map +1 -0
- package/dist/tools/create-folder.js +55 -0
- package/dist/tools/create-folder.js.map +1 -0
- package/dist/tools/delete-artifacts.js +33 -0
- package/dist/tools/delete-artifacts.js.map +1 -0
- package/dist/tools/delete-entity.js +35 -0
- package/dist/tools/delete-entity.js.map +1 -0
- package/dist/tools/explain-access.js +40 -0
- package/dist/tools/explain-access.js.map +1 -0
- package/dist/tools/get-entity.js +36 -0
- package/dist/tools/get-entity.js.map +1 -0
- package/dist/tools/get-page.js +75 -0
- package/dist/tools/get-page.js.map +1 -0
- package/dist/tools/list-apps.js +22 -0
- package/dist/tools/list-apps.js.map +1 -0
- package/dist/tools/list-entities.js +43 -0
- package/dist/tools/list-entities.js.map +1 -0
- package/dist/tools/propose-page-design.js +17 -0
- package/dist/tools/propose-page-design.js.map +1 -0
- package/dist/tools/raw-api.js +132 -0
- package/dist/tools/raw-api.js.map +1 -0
- package/dist/tools/read-artifacts.js +197 -0
- package/dist/tools/read-artifacts.js.map +1 -0
- package/dist/tools/resolve-entity.js +22 -0
- package/dist/tools/resolve-entity.js.map +1 -0
- package/dist/tools/update-artifacts.js +33 -0
- package/dist/tools/update-artifacts.js.map +1 -0
- package/dist/tools/update-entity.js +41 -0
- package/dist/tools/update-entity.js.map +1 -0
- package/dist/tools/update-page.js +40 -0
- package/dist/tools/update-page.js.map +1 -0
- package/dist/write-gate.js +25 -0
- package/dist/write-gate.js.map +1 -0
- package/package.json +55 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres
|
|
5
|
+
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-06-30
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- Initial standalone release of the write-capable ELWIS Data MCP server.
|
|
11
|
+
- Four STDIO tools: `explain_elwis_access`, `list_elwis_apps`, `resolve_elwis_entity`, `build_artifact_type`.
|
|
12
|
+
- `build_artifact_type` supports dry-run preview, entity reuse by name, and reverse-order soft-delete rollback on partial failure.
|
|
13
|
+
- Write gate: all create/delete operations require `ELWIS_WRITE_ENABLED=true`.
|
|
14
|
+
- Permanent session JWT authentication via `ELWIS_SESSION_JWT` (cookie-based, token never logged).
|
|
15
|
+
- OpenAPI spec snapshot loader for field validation.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
Copyright (c) 2026 Softacus. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software and its source code are proprietary and confidential to Softacus.
|
|
4
|
+
No part of this package may be copied, modified, distributed, published, or used
|
|
5
|
+
except with the express prior written permission of Softacus, or under the terms
|
|
6
|
+
of a separate written agreement. Unauthorized use is prohibited.
|
package/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# @softacus-software/elwis-data-mcp
|
|
2
|
+
|
|
3
|
+
A [Model Context Protocol](https://modelcontextprotocol.io) server that lets your chat client work with ELWIS. You ask in plain words, it reads and builds real ELWIS things: applications, folders, data types, attributes, artifact types, records, links, pages, and workflows. Every change is shown to you as a plan first and happens only after you say yes.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
+-------------------+ +---------------------+ +-----------+
|
|
7
|
+
| Your chat client | <--> | elwis-data-mcp | <--> | ELWIS |
|
|
8
|
+
| (Claude Desktop, | | (this server, | | (your |
|
|
9
|
+
| Codex, Gemini) | | runs on your | | tenant) |
|
|
10
|
+
| | | computer) | | |
|
|
11
|
+
+-------------------+ +---------------------+ +-----------+
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Set up in five minutes
|
|
15
|
+
|
|
16
|
+
You need three things before you start:
|
|
17
|
+
|
|
18
|
+
- the address of your ELWIS (copy it from your browser)
|
|
19
|
+
- your own ELWIS email and password (the same ones you use to sign in)
|
|
20
|
+
- an npm account invited to the softacus organization (ask your administrator)
|
|
21
|
+
|
|
22
|
+
### Step 1. Install Node.js (one time)
|
|
23
|
+
|
|
24
|
+
Go to [nodejs.org](https://nodejs.org), download the LTS installer, run it, accept the defaults.
|
|
25
|
+
|
|
26
|
+
Check it worked. Open a terminal (macOS: the Terminal app, Windows: PowerShell) and type:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
node --version
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
You should see a version number like `v22.x.x`.
|
|
33
|
+
|
|
34
|
+
### Step 2. Sign in to npm (one time)
|
|
35
|
+
|
|
36
|
+
The package is private to the Softacus team. Create a free account at npmjs.com if you do not have one, ask your administrator to invite it to the softacus organization, then run:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm login
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
A browser window opens; sign in and return to the terminal.
|
|
43
|
+
|
|
44
|
+
### Step 3. Run the setup and answer its questions
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx -y @softacus-software/elwis-data-mcp setup
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
It asks, in order:
|
|
51
|
+
|
|
52
|
+
1. Where is your ELWIS? Paste the address from your browser.
|
|
53
|
+
2. Your email and password. Nothing is shown while you type the password and it is never stored. Only the resulting session stays, on this computer only.
|
|
54
|
+
3. Read-only or building? Read-only can never change anything. Building shows a plan and asks before every change.
|
|
55
|
+
4. Which applications may it see? Pick from the list, or all.
|
|
56
|
+
5. Which client do you use? It writes the configuration for Claude Desktop, Codex, or Gemini by itself and backs up anything it touches.
|
|
57
|
+
|
|
58
|
+
### Step 4. Check it works
|
|
59
|
+
|
|
60
|
+
Fully quit your chat client (on a Mac press Cmd+Q, closing the window is not enough), open it again, and ask:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Are you connected to ELWIS?
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
It should answer with your name and your tenant. Done.
|
|
67
|
+
|
|
68
|
+
## Daily use
|
|
69
|
+
|
|
70
|
+
Just ask for what you want:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
List the applications I can see in ELWIS.
|
|
74
|
+
Show me the records of type Product.
|
|
75
|
+
Make me a page to track support tickets.
|
|
76
|
+
Rename the Priority attribute to Urgency.
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
In building mode every change comes back as a short plan ("I will create X and Y, ok?"). Nothing happens until you agree.
|
|
80
|
+
|
|
81
|
+
You stay signed in about as long as a normal ELWIS browser login (around two weeks) and the session refreshes itself while you use it. When it runs out, sign in again:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npx -y @softacus-software/elwis-data-mcp login
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
To sign out on this computer:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
npx -y @softacus-software/elwis-data-mcp logout
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
If anything fails, send your administrator the exact text of the error.
|
|
94
|
+
|
|
95
|
+
## For administrators
|
|
96
|
+
|
|
97
|
+
### Manual client configuration
|
|
98
|
+
|
|
99
|
+
The setup wizard writes these for you; use the blocks below only if you prefer to do it by hand. Instead of a personal login you can pass a long-lived access token via `ELWIS_SESSION_JWT` (see [Getting a token](#getting-a-token)).
|
|
100
|
+
|
|
101
|
+
Claude Desktop (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows) and Claude Code (`.mcp.json` in the project root, same shape):
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"mcpServers": {
|
|
106
|
+
"elwis-data": {
|
|
107
|
+
"command": "npx",
|
|
108
|
+
"args": ["-y", "@softacus-software/elwis-data-mcp"],
|
|
109
|
+
"env": {
|
|
110
|
+
"ELWIS_API_URL": "https://<your-elwis-host>",
|
|
111
|
+
"ELWIS_TENANT": "<24-char tenant id>",
|
|
112
|
+
"ELWIS_SESSION_JWT": "<token, or omit when a saved login exists>",
|
|
113
|
+
"ELWIS_WRITE_ENABLED": "false",
|
|
114
|
+
"ELWIS_ALLOWED_APPS": "<AppName1,AppName2>"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Codex (`~/.codex/config.toml`):
|
|
122
|
+
|
|
123
|
+
```toml
|
|
124
|
+
[mcp_servers.elwis-data]
|
|
125
|
+
command = "npx"
|
|
126
|
+
args = ["-y", "@softacus-software/elwis-data-mcp"]
|
|
127
|
+
|
|
128
|
+
[mcp_servers.elwis-data.env]
|
|
129
|
+
ELWIS_API_URL = "https://<your-elwis-host>"
|
|
130
|
+
ELWIS_TENANT = "<24-char tenant id>"
|
|
131
|
+
ELWIS_SESSION_JWT = "<token, or omit when a saved login exists>"
|
|
132
|
+
ELWIS_WRITE_ENABLED = "false"
|
|
133
|
+
ELWIS_ALLOWED_APPS = "<AppName1,AppName2>"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Gemini CLI (`~/.gemini/settings.json`): same JSON shape as Claude Desktop.
|
|
137
|
+
|
|
138
|
+
Any other MCP client: register a STDIO server with `command: "npx"`, `args: ["-y", "@softacus-software/elwis-data-mcp"]` and the same `env`. After connecting, call `explain_elwis_access` to verify identity, tenant, and the write gates.
|
|
139
|
+
|
|
140
|
+
### Configuration
|
|
141
|
+
|
|
142
|
+
| Variable | Required | What it does |
|
|
143
|
+
|---|---|---|
|
|
144
|
+
| `ELWIS_API_URL` | yes | Address of the ELWIS backend, e.g. `https://your-elwis-host` |
|
|
145
|
+
| `ELWIS_TENANT` | yes | The 24-character tenant id this connection is locked to. Without it the data tools refuse to work; with the wrong one every call is rejected before touching anything. The wizard fills it automatically, `explain_elwis_access` shows it. |
|
|
146
|
+
| `ELWIS_SESSION_JWT` | no | Long-lived access token. When omitted, the saved login from the setup or `login` command is used and refreshed automatically. An explicit token wins over a saved login. |
|
|
147
|
+
| `ELWIS_WRITE_ENABLED` | no | `true` allows building and deleting. Default `false`: read-only, build tools return an error before any request is made. |
|
|
148
|
+
| `ELWIS_ALLOWED_APPS` | no | Comma-separated application allowlist (names or ids). Everything outside the list is rejected before touching the backend. Default: all applications the user can access. |
|
|
149
|
+
| `ELWIS_REQUIRE_CONFIRMATION` | no | Default `true`: every write is two-step, the preview returns a token and execution requires it, so nothing is written that nobody saw. Set `false` only for scripted automation. |
|
|
150
|
+
| `ELWIS_AUDIT_LOG` | no | Path of the write-audit log. Default `~/.elwis/data-mcp-audit.jsonl`. Every executed write is recorded with tool, tenant, user, and result. |
|
|
151
|
+
|
|
152
|
+
### Getting a token
|
|
153
|
+
|
|
154
|
+
For automation the server accepts a permanent session JWT minted via the `noRefresh` flow:
|
|
155
|
+
|
|
156
|
+
1. As a tenant admin, open an ELWIS session-flow connection.
|
|
157
|
+
2. `POST /api/tenant/session` with body `{ "sessionFlowId": "<id>", "userId": "<id>", "sessionJwtRefreshMode": 2 }`.
|
|
158
|
+
3. Copy `clientData.sessionJwt` from the response.
|
|
159
|
+
|
|
160
|
+
The token carries the full rights of its user and never expires. Keep it in environment variables or a secrets manager, never in source control. Revoke it any time by disconnecting the session (`DELETE /api/tenant/session/<id>`); it stops working immediately. Rotate on a schedule. The strongest scoping is to mint it for a dedicated restricted user whose group memberships cover only what the server should see, combined with `ELWIS_WRITE_ENABLED=false` and `ELWIS_ALLOWED_APPS`.
|
|
161
|
+
|
|
162
|
+
## Tools
|
|
163
|
+
|
|
164
|
+
| Group | Tools | What they do |
|
|
165
|
+
|---|---|---|
|
|
166
|
+
| Check | `explain_elwis_access` | Who am I, which tenant, what is allowed. Call this first. |
|
|
167
|
+
| Read | `list_elwis_apps`, `list_elwis_entities`, `resolve_elwis_entity`, `get_elwis_entity`, `list_elwis_artifacts`, `get_elwis_artifact`, `list_elwis_artifact_links`, `get_elwis_page` | Browse applications, configuration, records, links, and pages. |
|
|
168
|
+
| Create | `create_elwis_application`, `create_elwis_folder`, `build_artifact_type`, `create_elwis_artifacts`, `build_links`, `build_page`, `build_workflow` | Build new things. Existing entities with the same name are reused, partial failures roll back where possible. |
|
|
169
|
+
| Change | `update_elwis_entity`, `update_elwis_artifacts`, `update_elwis_page` | Rename, edit fields, move folders, change enum values, edit records and pages. Only the fields you pass change. |
|
|
170
|
+
| Delete | `delete_elwis_entity`, `delete_elwis_artifacts` | Soft delete with a preview of everything that still depends on the target. |
|
|
171
|
+
| Design | `propose_page_design` | An interview that asks what data a page should manage before anything is built. |
|
|
172
|
+
|
|
173
|
+
Every write supports `dryRun: true` (a full preview without touching the backend) and, by default, requires the confirmation token from that preview to execute.
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npm install
|
|
179
|
+
npm run build # compile to dist/, mark the bin executable
|
|
180
|
+
npm test # unit tests
|
|
181
|
+
npm run lint # eslint
|
|
182
|
+
npm run dev # run from source via tsx
|
|
183
|
+
```
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { IsObjectId } from './resolve.js';
|
|
2
|
+
export class AppScopeError extends Error {
|
|
3
|
+
constructor(ref) {
|
|
4
|
+
super(`Application "${ref}" is outside the MCP application allowlist (ELWIS_ALLOWED_APPS)`);
|
|
5
|
+
this.name = 'AppScopeError';
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export function FilterApplicationId(filter) {
|
|
9
|
+
const value = filter.applicationId;
|
|
10
|
+
if (typeof value === 'string')
|
|
11
|
+
return value;
|
|
12
|
+
if (value && typeof value === 'object' && typeof value.$oid === 'string')
|
|
13
|
+
return value.$oid;
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
export class TenantMismatchError extends Error {
|
|
17
|
+
constructor(expected, actual) {
|
|
18
|
+
super(`No data was read or written. This connection is locked to tenant ${expected}, but the access token belongs to a different tenant (${actual ?? 'unknown'}). The saved connection settings are stale or mixed up. Re-run the setup, or fix ELWIS_TENANT if you configured it by hand.`);
|
|
19
|
+
this.name = 'TenantMismatchError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class NoTenantError extends Error {
|
|
23
|
+
constructor() {
|
|
24
|
+
super('No tenant is set, so I do not know which ELWIS environment to work in, and ELWIS has many (dev, pre-prod, prod). Set ELWIS_TENANT to the tenant you mean before reading or changing anything. Run explain_elwis_access to see the tenant id this connection\'s login belongs to, or re-run the setup wizard, which fills it in for you.');
|
|
25
|
+
this.name = 'NoTenantError';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export class AppScope {
|
|
29
|
+
api;
|
|
30
|
+
entries;
|
|
31
|
+
expectedTenant;
|
|
32
|
+
ids = null;
|
|
33
|
+
tenantVerified = false;
|
|
34
|
+
cachedIdentity = null;
|
|
35
|
+
constructor(api, entries, expectedTenant) {
|
|
36
|
+
this.api = api;
|
|
37
|
+
this.entries = entries;
|
|
38
|
+
this.expectedTenant = expectedTenant;
|
|
39
|
+
}
|
|
40
|
+
identity() {
|
|
41
|
+
this.cachedIdentity = this.cachedIdentity ?? this.api.whoAmI().catch(() => null);
|
|
42
|
+
return this.cachedIdentity;
|
|
43
|
+
}
|
|
44
|
+
async assertTenant() {
|
|
45
|
+
if (!this.expectedTenant || this.tenantVerified)
|
|
46
|
+
return;
|
|
47
|
+
const identity = await this.identity();
|
|
48
|
+
if (identity?.tenantId !== this.expectedTenant)
|
|
49
|
+
throw new TenantMismatchError(this.expectedTenant, identity?.tenantId ?? null);
|
|
50
|
+
this.tenantVerified = true;
|
|
51
|
+
}
|
|
52
|
+
get restricted() {
|
|
53
|
+
return this.entries.length > 0;
|
|
54
|
+
}
|
|
55
|
+
describe() {
|
|
56
|
+
return { restricted: this.restricted, entries: [...this.entries] };
|
|
57
|
+
}
|
|
58
|
+
async allowedIds() {
|
|
59
|
+
if (!this.restricted)
|
|
60
|
+
return null;
|
|
61
|
+
if (this.ids)
|
|
62
|
+
return this.ids;
|
|
63
|
+
const ids = new Set();
|
|
64
|
+
for (const entry of this.entries) {
|
|
65
|
+
if (IsObjectId(entry)) {
|
|
66
|
+
ids.add(entry);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const rows = await this.api.list('application', { name: entry });
|
|
70
|
+
for (const row of rows)
|
|
71
|
+
ids.add(row.id);
|
|
72
|
+
}
|
|
73
|
+
this.ids = ids;
|
|
74
|
+
return ids;
|
|
75
|
+
}
|
|
76
|
+
async assertAllowed(applicationId) {
|
|
77
|
+
await this.assertTenant();
|
|
78
|
+
const ids = await this.allowedIds();
|
|
79
|
+
if (ids && !ids.has(applicationId))
|
|
80
|
+
throw new AppScopeError(applicationId);
|
|
81
|
+
}
|
|
82
|
+
async assertListAllowed(kind, filter) {
|
|
83
|
+
await this.assertTenant();
|
|
84
|
+
if (!this.restricted || kind === 'application')
|
|
85
|
+
return;
|
|
86
|
+
const applicationId = FilterApplicationId(filter);
|
|
87
|
+
if (!applicationId)
|
|
88
|
+
throw new AppScopeError('unspecified, when ELWIS_ALLOWED_APPS is set, list calls require an applicationId filter');
|
|
89
|
+
await this.assertAllowed(applicationId);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=app-scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-scope.js","sourceRoot":"","sources":["../src/app-scope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { AmbiguityError, IsObjectId } from './resolve.js';
|
|
2
|
+
const VALUE_CHAR_LIMIT = 4000;
|
|
3
|
+
const ARRAY_ELEMENT_LIMIT = 50;
|
|
4
|
+
const MAP_FETCH_LIMIT = 500;
|
|
5
|
+
export async function LoadAttributeMap(api, applicationId) {
|
|
6
|
+
const rows = await api.list('attribute', { applicationId: { $oid: applicationId } }, MAP_FETCH_LIMIT + 1);
|
|
7
|
+
if (rows.length > MAP_FETCH_LIMIT)
|
|
8
|
+
throw new Error(`The application has more than ${MAP_FETCH_LIMIT} attributes; pass explicit attribute ids instead of names`);
|
|
9
|
+
const byId = new Map();
|
|
10
|
+
const byName = new Map();
|
|
11
|
+
for (const r of rows) {
|
|
12
|
+
byId.set(r.id, r.name);
|
|
13
|
+
const key = r.name.toLowerCase();
|
|
14
|
+
byName.set(key, [...(byName.get(key) ?? []), { id: r.id, name: r.name }]);
|
|
15
|
+
}
|
|
16
|
+
return { byId, byName };
|
|
17
|
+
}
|
|
18
|
+
export function ResolveAttributeId(map, ref) {
|
|
19
|
+
if (IsObjectId(ref))
|
|
20
|
+
return ref;
|
|
21
|
+
const matches = map.byName.get(ref.toLowerCase()) ?? [];
|
|
22
|
+
if (matches.length === 1)
|
|
23
|
+
return matches[0].id;
|
|
24
|
+
if (matches.length === 0)
|
|
25
|
+
throw new Error(`No attribute named "${ref}" in the application`);
|
|
26
|
+
throw new AmbiguityError(`Multiple attributes named "${ref}"; pass an explicit id`, matches);
|
|
27
|
+
}
|
|
28
|
+
export async function ResolveUnknownAttributeNames(api, map, ids) {
|
|
29
|
+
const unknown = [...new Set(ids)].filter(id => !map.byId.has(id));
|
|
30
|
+
await Promise.all(unknown.map(async (id) => {
|
|
31
|
+
try {
|
|
32
|
+
const doc = await api.getOne('attribute', id);
|
|
33
|
+
map.byId.set(id, doc.name);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
map.byId.set(id, id);
|
|
37
|
+
}
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
const WHERE_OPS = {
|
|
41
|
+
equals: (v) => v,
|
|
42
|
+
contains: (v) => ({ $regex: EscapeRegex(String(v)), $options: 'i' }),
|
|
43
|
+
gt: (v) => ({ $gt: v }),
|
|
44
|
+
gte: (v) => ({ $gte: v }),
|
|
45
|
+
lt: (v) => ({ $lt: v }),
|
|
46
|
+
lte: (v) => ({ $lte: v }),
|
|
47
|
+
in: (v) => ({ $in: Array.isArray(v) ? v : [v] }),
|
|
48
|
+
};
|
|
49
|
+
export function EscapeRegex(value) {
|
|
50
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
51
|
+
}
|
|
52
|
+
export function BuildWhereClauses(map, where) {
|
|
53
|
+
return where.map(clause => {
|
|
54
|
+
const attrId = ResolveAttributeId(map, clause.attribute);
|
|
55
|
+
return { [`attributes.${attrId}.value`]: WHERE_OPS[clause.op ?? 'equals'](clause.value) };
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export function TruncateValue(value) {
|
|
59
|
+
if (typeof value === 'string' && value.length > VALUE_CHAR_LIMIT) {
|
|
60
|
+
return `${value.slice(0, VALUE_CHAR_LIMIT)}…[truncated ${value.length - VALUE_CHAR_LIMIT} chars]`;
|
|
61
|
+
}
|
|
62
|
+
if (Array.isArray(value)) {
|
|
63
|
+
const head = value.slice(0, ARRAY_ELEMENT_LIMIT).map(TruncateValue);
|
|
64
|
+
if (value.length > ARRAY_ELEMENT_LIMIT)
|
|
65
|
+
head.push(`…[+${value.length - ARRAY_ELEMENT_LIMIT} more]`);
|
|
66
|
+
return head;
|
|
67
|
+
}
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
export function SummarizeArtifact(artifact, nameAttributeId) {
|
|
71
|
+
return {
|
|
72
|
+
id: artifact.id,
|
|
73
|
+
name: TruncateValue(artifact.attributes?.[nameAttributeId]?.value ?? null),
|
|
74
|
+
artifactTypeId: artifact.artifactTypeId,
|
|
75
|
+
format: artifact.format,
|
|
76
|
+
folderPath: artifact.folderData?.path,
|
|
77
|
+
created: artifact.created?.on,
|
|
78
|
+
updated: artifact.updated?.on,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function TranslateArtifact(artifact, map) {
|
|
82
|
+
const values = {};
|
|
83
|
+
const unmappedValuesById = {};
|
|
84
|
+
const nameCollisions = [];
|
|
85
|
+
for (const [attrId, entry] of Object.entries(artifact.attributes ?? {})) {
|
|
86
|
+
const value = TruncateValue(entry?.value ?? null);
|
|
87
|
+
const name = map.byId.get(attrId);
|
|
88
|
+
if (name !== undefined && !Object.hasOwn(values, name))
|
|
89
|
+
values[name] = value;
|
|
90
|
+
else if (name !== undefined) {
|
|
91
|
+
nameCollisions.push(name);
|
|
92
|
+
unmappedValuesById[attrId] = value;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
unmappedValuesById[attrId] = value;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
id: artifact.id,
|
|
100
|
+
artifactTypeId: artifact.artifactTypeId,
|
|
101
|
+
format: artifact.format,
|
|
102
|
+
folderPath: artifact.folderData?.path,
|
|
103
|
+
folderId: artifact.folderData?.folderId ?? artifact.folderData?.id,
|
|
104
|
+
values,
|
|
105
|
+
...(Object.keys(unmappedValuesById).length ? { unmappedValuesById } : {}),
|
|
106
|
+
...(nameCollisions.length ? { nameCollisions } : {}),
|
|
107
|
+
created: artifact.created?.on,
|
|
108
|
+
updated: artifact.updated?.on,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
export function PageMeta(meta, returned) {
|
|
112
|
+
return { total: meta.totalCount, returned, skip: meta.skip, hasMore: meta.skip + returned < meta.totalCount };
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=artifact-read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-read.js","sourceRoot":"","sources":["../src/artifact-read.ts"],"names":[],"mappings":"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"}
|
package/dist/audit.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { DecodeJwtClaims } from './jwt.js';
|
|
4
|
+
export async function AuditWrite(cfg, scope, tool, confirmationToken, result) {
|
|
5
|
+
try {
|
|
6
|
+
const identity = await scope.identity();
|
|
7
|
+
const claims = DecodeJwtClaims(cfg.token);
|
|
8
|
+
const entry = {
|
|
9
|
+
at: new Date().toISOString(),
|
|
10
|
+
tool,
|
|
11
|
+
tenant: identity?.tenantId ?? claims.tenant ?? cfg.expectedTenant ?? null,
|
|
12
|
+
user: identity?.email ?? identity?.userId ?? claims.sub ?? null,
|
|
13
|
+
host: cfg.baseUrl,
|
|
14
|
+
confirmationToken,
|
|
15
|
+
confirmationRequired: cfg.requireConfirmation,
|
|
16
|
+
result,
|
|
17
|
+
};
|
|
18
|
+
mkdirSync(dirname(cfg.auditLog), { recursive: true });
|
|
19
|
+
appendFileSync(cfg.auditLog, `${JSON.stringify(entry)}\n`);
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
process.stderr.write(`audit log write failed: ${e.message}\n`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export async function AuditedExecute(cfg, scope, tool, token, run, summarize) {
|
|
26
|
+
try {
|
|
27
|
+
const result = await run();
|
|
28
|
+
await AuditWrite(cfg, scope, tool, token, summarize(result));
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
await AuditWrite(cfg, scope, tool, token, { error: e.message });
|
|
33
|
+
throw e;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAgB,EAAE,KAAe,EAAE,IAAY,EAAE,iBAAyB,EAAE,MAAe;IAC1H,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG;YACZ,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,IAAI;YACJ,MAAM,EAAE,QAAQ,EAAE,QAAQ,IAAK,MAAM,CAAC,MAAiB,IAAI,GAAG,CAAC,cAAc,IAAI,IAAI;YACrF,IAAI,EAAE,QAAQ,EAAE,KAAK,IAAI,QAAQ,EAAE,MAAM,IAAK,MAAM,CAAC,GAAc,IAAI,IAAI;YAC3E,IAAI,EAAE,GAAG,CAAC,OAAO;YACjB,iBAAiB;YACjB,oBAAoB,EAAE,GAAG,CAAC,mBAAmB;YAC7C,MAAM;SACP,CAAC;QACF,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA4B,CAAW,CAAC,OAAO,IAAI,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAI,GAAgB,EAAE,KAAe,EAAE,IAAY,EAAE,KAAa,EAAE,GAAqB,EAAE,SAAiC;IAC9J,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC;QAC3B,MAAM,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7D,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAG,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3E,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { HttpErrorDetail } from '../http-client.js';
|
|
2
|
+
export async function ExecuteArtifactTypePlan(api, plan) {
|
|
3
|
+
const created = [];
|
|
4
|
+
const report = { artifactType: { id: '', name: plan.artifactType.name }, createdDataTypes: [], createdAttributes: [], reused: [] };
|
|
5
|
+
const dtIdByName = new Map();
|
|
6
|
+
const attrIdByName = new Map();
|
|
7
|
+
const isFile = plan.artifactType.format === 'FILE';
|
|
8
|
+
try {
|
|
9
|
+
const sys = await api.systemAttributes();
|
|
10
|
+
if (!isFile && sys.primaryTextAttributeId && !sys.fileArtifactTypeId) {
|
|
11
|
+
throw new Error('Could not resolve the system File artifact type (tenant.fileArtifactTypeId) required by the Primary Text attribute');
|
|
12
|
+
}
|
|
13
|
+
for (const dt of plan.dataTypes) {
|
|
14
|
+
if (dt.action === 'reuse') {
|
|
15
|
+
dtIdByName.set(dt.name, dt.id);
|
|
16
|
+
report.reused.push({ id: dt.id, name: dt.name, kind: 'data-type' });
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const res = await api.create('data-type', dt.detail);
|
|
20
|
+
created.push({ kind: 'data-type', id: res.id });
|
|
21
|
+
dtIdByName.set(dt.name, res.id);
|
|
22
|
+
report.createdDataTypes.push({ id: res.id, name: res.name });
|
|
23
|
+
}
|
|
24
|
+
for (let i = 0; i < plan.attributes.length; i++) {
|
|
25
|
+
const at = plan.attributes[i];
|
|
26
|
+
if (at.action === 'reuse') {
|
|
27
|
+
attrIdByName.set(at.name, at.id);
|
|
28
|
+
report.reused.push({ id: at.id, name: at.name, kind: 'attribute' });
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const dtName = at.dataTypeRef;
|
|
32
|
+
const body = { ...at.detail, dataTypeId: dtIdByName.get(dtName) };
|
|
33
|
+
const res = await api.create('attribute', body);
|
|
34
|
+
created.push({ kind: 'attribute', id: res.id });
|
|
35
|
+
attrIdByName.set(at.name, res.id);
|
|
36
|
+
report.createdAttributes.push({ id: res.id, name: res.name });
|
|
37
|
+
}
|
|
38
|
+
const attributeMap = {};
|
|
39
|
+
attributeMap[sys.nameAttributeId] = { isMandatory: !isFile };
|
|
40
|
+
if (sys.sequenceAttributeId)
|
|
41
|
+
attributeMap[sys.sequenceAttributeId] = { isMandatory: false };
|
|
42
|
+
if (!isFile && sys.primaryTextAttributeId)
|
|
43
|
+
attributeMap[sys.primaryTextAttributeId] = { isMandatory: false, fileArtifactTypeId: sys.fileArtifactTypeId };
|
|
44
|
+
for (let i = 0; i < plan.attributes.length; i++) {
|
|
45
|
+
const item = plan.attributes[i];
|
|
46
|
+
const id = attrIdByName.get(item.name);
|
|
47
|
+
const entry = { isMandatory: item.isMandatory ?? false, ...(item.mapEntry ?? {}) };
|
|
48
|
+
const fileArtifactTypeId = item.fileArtifactTypeId ?? (item.needsFile ? sys.fileArtifactTypeId : undefined);
|
|
49
|
+
if (fileArtifactTypeId)
|
|
50
|
+
entry.fileArtifactTypeId = fileArtifactTypeId;
|
|
51
|
+
attributeMap[id] = entry;
|
|
52
|
+
}
|
|
53
|
+
const primaryId = attrIdByName.get(plan.artifactType.primaryAttributeName);
|
|
54
|
+
const a = plan.artifactType;
|
|
55
|
+
const atBody = {
|
|
56
|
+
applicationId: plan.applicationId,
|
|
57
|
+
name: a.name,
|
|
58
|
+
description: a.description ?? '',
|
|
59
|
+
icon: a.icon ?? '',
|
|
60
|
+
format: a.format,
|
|
61
|
+
attributes: attributeMap,
|
|
62
|
+
primaryAttributes: [primaryId],
|
|
63
|
+
defaultFolderId: a.defaultFolderId ?? null,
|
|
64
|
+
defaultPageId: a.defaultPageId ?? null,
|
|
65
|
+
delimiter: a.delimiter ?? null,
|
|
66
|
+
avrMapper: a.avrMapper ?? {},
|
|
67
|
+
};
|
|
68
|
+
if (a.color !== undefined)
|
|
69
|
+
atBody.color = a.color;
|
|
70
|
+
if (a.isLoggingDisabled !== undefined)
|
|
71
|
+
atBody.isLoggingDisabled = a.isLoggingDisabled;
|
|
72
|
+
if (a.inheritableAcl !== undefined)
|
|
73
|
+
atBody.inheritableAcl = a.inheritableAcl;
|
|
74
|
+
if (a.defaultIsHeading !== undefined)
|
|
75
|
+
atBody.defaultIsHeading = a.defaultIsHeading;
|
|
76
|
+
if (a.defaultWidgets !== undefined)
|
|
77
|
+
atBody.defaultWidgets = a.defaultWidgets;
|
|
78
|
+
if (a.avrTriggers !== undefined)
|
|
79
|
+
atBody.avrTriggers = a.avrTriggers;
|
|
80
|
+
if (a.preferredArtifactTypeIds !== undefined)
|
|
81
|
+
atBody.preferredArtifactTypeIds = a.preferredArtifactTypeIds;
|
|
82
|
+
const at = await api.create('artifact-type', atBody);
|
|
83
|
+
created.push({ kind: 'artifact-type', id: at.id });
|
|
84
|
+
report.artifactType = { id: at.id, name: at.name };
|
|
85
|
+
return report;
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
for (const c of [...created].reverse()) {
|
|
89
|
+
try {
|
|
90
|
+
await api.softDelete(c.kind, c.id);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const createdSummary = created.map(c => `${c.kind}:${c.id}`).join(', ');
|
|
97
|
+
throw new Error(`build_artifact_type failed: ${e.message}${HttpErrorDetail(e)}. Rolled back: ${createdSummary || 'nothing'}`, { cause: e });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=artifact-type-execute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-type-execute.js","sourceRoot":"","sources":["../../src/builders/artifact-type-execute.ts"],"names":[],"mappings":"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"}
|