@softacus-software/elwis-docs-mcp 0.1.1 → 0.2.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.
Files changed (50) hide show
  1. package/README.md +122 -43
  2. package/dist/app-scope.js +92 -0
  3. package/dist/app-scope.js.map +1 -0
  4. package/dist/artifact-read.js +114 -0
  5. package/dist/artifact-read.js.map +1 -0
  6. package/dist/cli/client-configs.js +86 -0
  7. package/dist/cli/client-configs.js.map +1 -0
  8. package/dist/cli/login.js +64 -0
  9. package/dist/cli/login.js.map +1 -0
  10. package/dist/cli/prompter.js +85 -0
  11. package/dist/cli/prompter.js.map +1 -0
  12. package/dist/cli/setup.js +152 -0
  13. package/dist/cli/setup.js.map +1 -0
  14. package/dist/config.js +39 -0
  15. package/dist/config.js.map +1 -0
  16. package/dist/elwis-api.js +68 -0
  17. package/dist/elwis-api.js.map +1 -0
  18. package/dist/entity-read.js +192 -0
  19. package/dist/entity-read.js.map +1 -0
  20. package/dist/http-client.js +140 -0
  21. package/dist/http-client.js.map +1 -0
  22. package/dist/index.js +8 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/jwt.js +18 -0
  25. package/dist/jwt.js.map +1 -0
  26. package/dist/prune.js +9 -0
  27. package/dist/prune.js.map +1 -0
  28. package/dist/resolve.js +71 -0
  29. package/dist/resolve.js.map +1 -0
  30. package/dist/result.js +16 -0
  31. package/dist/result.js.map +1 -0
  32. package/dist/server.js +51 -0
  33. package/dist/server.js.map +1 -1
  34. package/dist/session-store.js +51 -0
  35. package/dist/session-store.js.map +1 -0
  36. package/dist/tools/explain-access.js +36 -0
  37. package/dist/tools/explain-access.js.map +1 -0
  38. package/dist/tools/get-entity.js +36 -0
  39. package/dist/tools/get-entity.js.map +1 -0
  40. package/dist/tools/get-page.js +75 -0
  41. package/dist/tools/get-page.js.map +1 -0
  42. package/dist/tools/list-apps.js +22 -0
  43. package/dist/tools/list-apps.js.map +1 -0
  44. package/dist/tools/list-entities.js +43 -0
  45. package/dist/tools/list-entities.js.map +1 -0
  46. package/dist/tools/read-artifacts.js +197 -0
  47. package/dist/tools/read-artifacts.js.map +1 -0
  48. package/dist/tools/resolve-entity.js +22 -0
  49. package/dist/tools/resolve-entity.js.map +1 -0
  50. package/package.json +2 -2
@@ -0,0 +1,85 @@
1
+ import { createInterface } from 'node:readline';
2
+ import { stdin, stdout } from 'node:process';
3
+ const CTRL_C = '';
4
+ const BACKSPACE = '';
5
+ export class Prompter {
6
+ rl;
7
+ queue = [];
8
+ waiters = [];
9
+ closed = false;
10
+ constructor() {
11
+ this.rl = createInterface({ input: stdin, output: stdout, terminal: stdin.isTTY === true });
12
+ this.rl.on('line', (line) => {
13
+ const waiter = this.waiters.shift();
14
+ if (waiter)
15
+ waiter(line);
16
+ else
17
+ this.queue.push(line);
18
+ });
19
+ this.rl.on('close', () => {
20
+ this.closed = true;
21
+ for (const waiter of this.waiters.splice(0))
22
+ waiter('');
23
+ });
24
+ }
25
+ ask(promptText, echoQueued = true) {
26
+ const queued = this.queue.shift();
27
+ if (queued !== undefined) {
28
+ stdout.write(`${promptText}${echoQueued ? queued : '***'}\n`);
29
+ return Promise.resolve(queued);
30
+ }
31
+ if (this.closed) {
32
+ stdout.write(promptText);
33
+ return Promise.resolve('');
34
+ }
35
+ this.rl.setPrompt(promptText);
36
+ this.rl.prompt();
37
+ return new Promise((resolveLine) => this.waiters.push(resolveLine));
38
+ }
39
+ async askHidden(promptText) {
40
+ if (!stdin.isTTY)
41
+ return (await this.ask(promptText, false)).trim();
42
+ stdout.write(promptText);
43
+ const detached = stdin.rawListeners('data').slice();
44
+ for (const listener of detached)
45
+ stdin.off('data', listener);
46
+ return await new Promise((resolveSecret) => {
47
+ const chars = [];
48
+ const wasRaw = stdin.isRaw;
49
+ stdin.setRawMode(true);
50
+ const finish = (value) => {
51
+ stdin.off('data', onData);
52
+ stdin.setRawMode(wasRaw ?? false);
53
+ for (const listener of detached)
54
+ stdin.on('data', listener);
55
+ stdout.write('\n');
56
+ if (value === null) {
57
+ process.exit(130);
58
+ }
59
+ resolveSecret(value);
60
+ };
61
+ const onData = (buffer) => {
62
+ for (const char of buffer.toString('utf8')) {
63
+ if (char === CTRL_C) {
64
+ finish(null);
65
+ return;
66
+ }
67
+ if (char === '\r' || char === '\n') {
68
+ finish(chars.join(''));
69
+ return;
70
+ }
71
+ if (char === BACKSPACE || char === '\b') {
72
+ chars.pop();
73
+ continue;
74
+ }
75
+ chars.push(char);
76
+ }
77
+ };
78
+ stdin.on('data', onData);
79
+ });
80
+ }
81
+ close() {
82
+ this.rl.close();
83
+ }
84
+ }
85
+ //# sourceMappingURL=prompter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompter.js","sourceRoot":"","sources":["../../src/cli/prompter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,152 @@
1
+ import { stdout } from 'node:process';
2
+ import { NormalizeHost, PerformLogin } from './login.js';
3
+ import { Prompter } from './prompter.js';
4
+ import { SaveSession } from '../session-store.js';
5
+ import { BuildEnv, DetectClients, ServerCommand, WriteClientConfig } from './client-configs.js';
6
+ const FETCH_TIMEOUT = 10000;
7
+ async function LooksLikeElwis(host) {
8
+ try {
9
+ const response = await fetch(`${host}/api/tenant/user/info`, { headers: { Origin: host }, signal: AbortSignal.timeout(FETCH_TIMEOUT) });
10
+ if (response.status !== 200 && response.status !== 401 && response.status !== 403)
11
+ return 'no';
12
+ const body = await response.text();
13
+ try {
14
+ JSON.parse(body);
15
+ return 'yes';
16
+ }
17
+ catch {
18
+ return 'no';
19
+ }
20
+ }
21
+ catch {
22
+ return 'unreachable';
23
+ }
24
+ }
25
+ function LooksLikeDomain(raw) {
26
+ const bare = raw.trim().replace(/^https?:\/\//i, '').split(/[/:?#]/)[0];
27
+ if (!bare || /\s/.test(bare))
28
+ return false;
29
+ return bare === 'localhost' || /^\d{1,3}(\.\d{1,3}){3}$/.test(bare) || /^[\w-]+(\.[\w-]+)+$/.test(bare);
30
+ }
31
+ export async function RunSetup() {
32
+ const prompter = new Prompter();
33
+ const say = (line = '') => stdout.write(`${line}\n`);
34
+ try {
35
+ say('Welcome! This connects your AI assistant to ELWIS for reading, in a few questions. It can never change anything. (Press Ctrl+C at any time to stop.)');
36
+ say();
37
+ let host = '';
38
+ for (;;) {
39
+ const answer = await prompter.ask('1) What is your ELWIS domain? (like elwis.your-company.com, copy it from your browser): ');
40
+ if (!answer.trim()) {
41
+ say(' I need the domain to continue, ask your administrator if you are not sure.');
42
+ continue;
43
+ }
44
+ if (!LooksLikeDomain(answer)) {
45
+ say(' That does not look like a domain. It should be something like elwis.your-company.com.');
46
+ continue;
47
+ }
48
+ host = NormalizeHost(answer);
49
+ const check = await LooksLikeElwis(host);
50
+ if (check === 'yes')
51
+ break;
52
+ if (check === 'no')
53
+ say(` ${host} answers, but it does not look like an ELWIS, double-check the domain with your administrator.`);
54
+ else
55
+ say(` I could not reach ${host}, check the domain (and your network) and try again.`);
56
+ }
57
+ say();
58
+ say('2) Sign in with your own ELWIS email and password (the same ones you use in the browser).');
59
+ let login = null;
60
+ let email = '';
61
+ for (let attempt = 1; attempt <= 3 && !login; attempt++) {
62
+ const emailPrompt = email ? ` Your ELWIS email [${email}]: ` : ' Your ELWIS email: ';
63
+ email = (await prompter.ask(emailPrompt)).trim() || email;
64
+ const password = await prompter.askHidden(' Your ELWIS password (not shown while typing): ');
65
+ try {
66
+ login = await PerformLogin(host, email, password);
67
+ }
68
+ catch (e) {
69
+ if (attempt === 3)
70
+ throw e;
71
+ say(` That did not work, ${e.message.replace(/^Sign-in failed, /, '')} (attempt ${attempt + 1} of 3)`);
72
+ }
73
+ }
74
+ if (!login)
75
+ throw new Error('Sign-in did not succeed after three attempts. Check your details with your administrator and run setup again.');
76
+ SaveSession({ host, token: login.token, tenantId: login.tenantId, email: login.email, updatedAt: new Date().toISOString() });
77
+ say(` Signed in as ${login.email}. You'll stay signed in about as long as a normal ELWIS browser login (typically two weeks).`);
78
+ const choices = { host, tenantId: login.tenantId, allowedApps: [] };
79
+ const entry = { ...ServerCommand(), env: BuildEnv(choices) };
80
+ say();
81
+ const clients = DetectClients();
82
+ say('3) Which assistant should I set up? I can configure these:');
83
+ clients.forEach((client, index) => say(` [${index + 1}] ${client.label}${client.exists ? '' : ' (not detected on this computer, I can still write its config)'}`));
84
+ const picked = (await prompter.ask(' Type numbers separated by commas (e.g. 1,2): '))
85
+ .split(',')
86
+ .map(s => Number.parseInt(s.trim(), 10))
87
+ .filter(n => Number.isInteger(n) && n >= 1 && n <= clients.length)
88
+ .map(n => clients[n - 1]);
89
+ for (const target of picked) {
90
+ const written = WriteClientConfig(target, entry);
91
+ say(` ${target.label}: updated ${written.path}${written.backup ? ` (previous version saved as ${written.backup})` : ''}`);
92
+ }
93
+ say();
94
+ if (picked.length === 0) {
95
+ say('Nothing was selected, so no assistant configs were changed. Your sign-in is saved, run setup again any time to finish.');
96
+ return;
97
+ }
98
+ say('Done! Now:');
99
+ say(' 1. Fully quit your assistant (on a Mac: Cmd+Q, not just closing the window) and open it again.');
100
+ say(' 2. Ask it in plain words: "Are you connected to ELWIS?"');
101
+ say('It should answer with your name and tenant.');
102
+ say(`Set up: ${login.email ?? 'you'} on ${host}. It can read the API documentation and your live ELWIS data, and it can never change anything.`);
103
+ say('If it does not connect: make sure you fully quit and reopened, then run this setup again.');
104
+ }
105
+ finally {
106
+ prompter.close();
107
+ }
108
+ }
109
+ export async function RunCli(argv) {
110
+ const command = argv[2];
111
+ if (command === 'setup') {
112
+ await RunSetup();
113
+ return true;
114
+ }
115
+ if (command === 'login') {
116
+ const { RunLogin } = await import('./login.js');
117
+ await RunLogin(argv[3]);
118
+ return true;
119
+ }
120
+ if (command === 'logout') {
121
+ const { DeleteSession, ListSessions } = await import('../session-store.js');
122
+ const { NormalizeHost: Normalize } = await import('./login.js');
123
+ let host = argv[3] ? Normalize(argv[3]) : null;
124
+ if (!host) {
125
+ const sessions = ListSessions();
126
+ if (sessions.length === 1)
127
+ host = sessions[0].host;
128
+ else {
129
+ stdout.write(sessions.length ? 'You are signed in to several ELWIS servers, tell me which one: elwis-docs-mcp logout <domain>\n' : 'You are not signed in anywhere on this computer.\n');
130
+ return true;
131
+ }
132
+ }
133
+ DeleteSession(host);
134
+ stdout.write(`Signed out of ${host} on this computer. Sessions can also be revoked centrally in ELWIS.\n`);
135
+ return true;
136
+ }
137
+ if (command === 'help' || command === '--help' || command === '-h') {
138
+ stdout.write([
139
+ 'elwis-docs-mcp, connects your AI assistant to ELWIS for reading',
140
+ '',
141
+ ' setup guided setup in plain language (start here)',
142
+ ' login [domain] sign in again after your session expires',
143
+ ' logout [domain] sign out on this computer',
144
+ '',
145
+ 'Without a command it starts the MCP server (used by your assistant, not by hand).',
146
+ '',
147
+ ].join('\n'));
148
+ return true;
149
+ }
150
+ return false;
151
+ }
152
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"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"}
package/dist/config.js ADDED
@@ -0,0 +1,39 @@
1
+ import { LoadSession } from './session-store.js';
2
+ export function LoadConfig(env = process.env) {
3
+ const baseUrl = env.ELWIS_API_URL;
4
+ if (!baseUrl)
5
+ throw new Error('ELWIS_API_URL is not set. Open Terminal and run: npx @softacus-software/elwis-docs-mcp@latest setup');
6
+ const normalized = baseUrl.replace(/\/$/, '');
7
+ let token = env.ELWIS_SESSION_JWT;
8
+ let authMode = 'token';
9
+ if (!token) {
10
+ const session = LoadSession(normalized, env.ELWIS_SESSIONS_DIR?.trim() || undefined);
11
+ if (session) {
12
+ token = session.token;
13
+ authMode = 'session';
14
+ }
15
+ }
16
+ if (!token) {
17
+ throw new Error(`No ELWIS login found for ${normalized}. Open Terminal and run: npx @softacus-software/elwis-docs-mcp@latest login`);
18
+ }
19
+ const expectedTenant = env.ELWIS_TENANT?.trim();
20
+ if (expectedTenant && !/^[a-f0-9]{24}$/i.test(expectedTenant)) {
21
+ throw new Error('ELWIS_TENANT must be the 24-character tenant id shown by explain_elwis_access');
22
+ }
23
+ return {
24
+ baseUrl: normalized,
25
+ token,
26
+ authMode,
27
+ allowedApps: (env.ELWIS_ALLOWED_APPS ?? '').split(',').map(s => s.trim()).filter(Boolean),
28
+ expectedTenant: expectedTenant || undefined,
29
+ };
30
+ }
31
+ export function LoadConfigOrNull(env = process.env) {
32
+ try {
33
+ return { config: LoadConfig(env), reason: null };
34
+ }
35
+ catch (e) {
36
+ return { config: null, reason: e instanceof Error ? e.message : String(e) };
37
+ }
38
+ }
39
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAUjD,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC;IAClC,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,qGAAqG,CAAC,CAAC;IACrI,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC9C,IAAI,KAAK,GAAG,GAAG,CAAC,iBAAiB,CAAC;IAClC,IAAI,QAAQ,GAAwB,OAAO,CAAC;IAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,WAAW,CAAC,UAAU,EAAE,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC,CAAC;QACrF,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;YACtB,QAAQ,GAAG,SAAS,CAAC;QACvB,CAAC;IACH,CAAC;IACD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,4BAA4B,UAAU,6EAA6E,CAAC,CAAC;IACvI,CAAC;IACD,MAAM,cAAc,GAAG,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;IAChD,IAAI,cAAc,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,+EAA+E,CAAC,CAAC;IACnG,CAAC;IACD,OAAO;QACL,OAAO,EAAE,UAAU;QACnB,KAAK;QACL,QAAQ;QACR,WAAW,EAAE,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QACzF,cAAc,EAAE,cAAc,IAAI,SAAS;KAC5C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACnE,IAAI,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACnD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,CAAC;AACH,CAAC"}
@@ -0,0 +1,68 @@
1
+ import { TenantMismatchError, NoTenantError } from './app-scope.js';
2
+ export class ElwisApi {
3
+ client;
4
+ expectedTenant;
5
+ identityPromise = null;
6
+ tenantCheck = null;
7
+ constructor(client, expectedTenant) {
8
+ this.client = client;
9
+ this.expectedTenant = expectedTenant;
10
+ }
11
+ async whoAmI() {
12
+ const info = await this.client.get('/api/tenant/user/info');
13
+ const user = info.sessionUser ?? info.guestUser;
14
+ return { userId: user?.id ?? null, email: user?.email ?? null, tenantId: user?.tenant?.id ?? null, tenantAdmin: user?.tenant?.isAdmin ?? null };
15
+ }
16
+ identity() {
17
+ this.identityPromise = this.identityPromise ?? this.whoAmI();
18
+ return this.identityPromise;
19
+ }
20
+ ensureTenant() {
21
+ if (!this.expectedTenant)
22
+ return Promise.reject(new NoTenantError());
23
+ this.tenantCheck = this.tenantCheck ?? this.identity().then(id => {
24
+ if (id.tenantId !== this.expectedTenant)
25
+ throw new TenantMismatchError(this.expectedTenant, id.tenantId);
26
+ });
27
+ return this.tenantCheck;
28
+ }
29
+ async systemAttributes() {
30
+ await this.ensureTenant();
31
+ const info = await this.client.get('/api/tenant/user/info');
32
+ const tenant = (info.sessionUser ?? info.guestUser)?.tenant;
33
+ const sys = tenant?.systemAttributes;
34
+ if (!sys?.nameAttributeId)
35
+ throw new Error('Could not resolve system attributes from /api/tenant/user/info');
36
+ return {
37
+ nameAttributeId: sys.nameAttributeId,
38
+ sequenceAttributeId: sys.sequenceAttributeId,
39
+ primaryTextAttributeId: sys.primaryTextAttributeId,
40
+ fileArtifactTypeId: tenant?.fileArtifactTypeId,
41
+ };
42
+ }
43
+ async list(kind, filter = {}, limit) {
44
+ await this.ensureTenant();
45
+ const params = new URLSearchParams();
46
+ params.set('filter', JSON.stringify({ ...filter, deleted: null }));
47
+ params.set('sort', JSON.stringify({ _id: -1 }));
48
+ if (limit !== undefined)
49
+ params.set('limit', String(limit));
50
+ const res = await this.client.get(`/api/tenant/${kind}?${params.toString()}`);
51
+ return res.data;
52
+ }
53
+ async getOne(kind, id) {
54
+ await this.ensureTenant();
55
+ return this.client.get(`/api/tenant/${kind}/${id}`);
56
+ }
57
+ async listRecords(collection, filter, opts = {}) {
58
+ await this.ensureTenant();
59
+ const body = { filter: JSON.stringify({ ...filter, deleted: null }) };
60
+ body.sort = JSON.stringify(opts.sort ?? { _id: -1 });
61
+ if (opts.skip !== undefined)
62
+ body.skip = opts.skip;
63
+ if (opts.limit !== undefined)
64
+ body.limit = opts.limit;
65
+ return this.client.post(`/api/tenant/${collection}/list`, body);
66
+ }
67
+ }
68
+ //# sourceMappingURL=elwis-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elwis-api.js","sourceRoot":"","sources":["../src/elwis-api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAUpE,MAAM,OAAO,QAAQ;IACF,MAAM,CAAkB;IACxB,cAAc,CAAU;IACjC,eAAe,GAA6B,IAAI,CAAC;IACjD,WAAW,GAAyB,IAAI,CAAC;IAEjD,YAAY,MAAuB,EAAE,cAAuB;QAC1D,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,MAAM;QAEV,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAmD,uBAAuB,CAAC,CAAC;QAC9G,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC;QAChD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,IAAI,IAAI,EAAE,CAAC;IAClJ,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAC7D,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED,YAAY;QACV,IAAI,CAAC,IAAI,CAAC,cAAc;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC;QACrE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;YAC/D,IAAI,EAAE,CAAC,QAAQ,KAAK,IAAI,CAAC,cAAc;gBAAE,MAAM,IAAI,mBAAmB,CAAC,IAAI,CAAC,cAAe,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;QAC5G,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAE1B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAyE,uBAAuB,CAAC,CAAC;QACpI,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAC5D,MAAM,GAAG,GAAG,MAAM,EAAE,gBAAgB,CAAC;QACrC,IAAI,CAAC,GAAG,EAAE,eAAe;YAAE,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QAC7G,OAAO;YACL,eAAe,EAAE,GAAG,CAAC,eAAe;YACpC,mBAAmB,EAAE,GAAG,CAAC,mBAAmB;YAC5C,sBAAsB,EAAE,GAAG,CAAC,sBAAsB;YAClD,kBAAkB,EAAE,MAAM,EAAE,kBAAkB;SAC/C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAgB,EAAE,SAAkC,EAAE,EAAE,KAAc;QAC/E,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACnE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAChD,IAAI,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAA0B,eAAe,IAAI,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACvG,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,MAAM,CAAkB,IAAsC,EAAE,EAAU;QAC9E,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAI,eAAe,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,UAA+B,EAAE,MAA+B,EAAE,OAA0E,EAAE;QAC9J,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC1B,MAAM,IAAI,GAA4B,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC/F,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QACrD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACnD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACtD,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAa,eAAe,UAAU,OAAO,EAAE,IAAI,CAAC,CAAC;IAC9E,CAAC;CACF"}
@@ -0,0 +1,192 @@
1
+ import { AmbiguityError, IsObjectId, ResolveOneId, ResolveApplicationId } from './resolve.js';
2
+ export const ENTITY_KINDS = ['application', 'dataType', 'attribute', 'artifactType', 'linkType', 'workflow', 'page', 'link', 'folder'];
3
+ const KIND_MAP = {
4
+ application: 'application',
5
+ dataType: 'data-type',
6
+ attribute: 'attribute',
7
+ artifactType: 'artifact-type',
8
+ linkType: 'link-type',
9
+ workflow: 'workflow',
10
+ page: 'page',
11
+ link: 'link',
12
+ folder: 'folder',
13
+ };
14
+ export async function ResolveDocument(api, entity, scope, target) {
15
+ const kind = KIND_MAP[entity];
16
+ let id;
17
+ if (IsObjectId(target)) {
18
+ id = target;
19
+ }
20
+ else if (entity === 'link') {
21
+ throw new Error('Links have no name; pass the 24-char hex link id');
22
+ }
23
+ else if (entity === 'application') {
24
+ id = await ResolveApplicationId(api, target);
25
+ }
26
+ else if (entity === 'folder') {
27
+ const folder = await ResolveFolder(api, scope.applicationId, target);
28
+ id = folder.id;
29
+ }
30
+ else if (entity === 'workflow') {
31
+ id = await ResolveWorkflowId(api, target);
32
+ }
33
+ else {
34
+ id = await ResolveOneId(api, kind, scope.applicationId, target);
35
+ }
36
+ const doc = entity === 'page' ? await FetchPage(api, id) : await api.getOne(kind, id);
37
+ if (doc.deleted)
38
+ throw new Error(`The ${entity} "${doc.name ?? id}" is deleted`);
39
+ await AssertOwnership(api, entity, doc, scope);
40
+ return doc;
41
+ }
42
+ async function FetchPage(api, id) {
43
+ const rows = await api.list('page', { _id: { $oid: id } }, 1);
44
+ if (!rows.length)
45
+ throw new Error(`No active page with id ${id}`);
46
+ return rows[0];
47
+ }
48
+ async function AssertOwnership(api, entity, doc, scope) {
49
+ if (entity === 'application') {
50
+ if (String(doc.id) !== scope.applicationId) {
51
+ throw new Error(`The resolved application "${doc.name}" (${String(doc.id)}) is not the one this call is scoped to`);
52
+ }
53
+ return;
54
+ }
55
+ if (entity === 'folder') {
56
+ const root = await AppRootFolder(api, scope.applicationId);
57
+ if (String(doc.id) === root.id)
58
+ return;
59
+ if (!FolderFullPath(doc).startsWith(root.fullPath)) {
60
+ throw new Error(`The folder "${String(doc.folderPath)}${doc.name}" lives outside this application's folder tree (${root.fullPath})`);
61
+ }
62
+ return;
63
+ }
64
+ if (entity === 'link') {
65
+ if (!doc.linkTypeId)
66
+ throw new Error('The link has no link type; cannot verify which application it belongs to');
67
+ const linkType = await api.getOne('link-type', String(doc.linkTypeId));
68
+ RequireSameApplication('link (via its link type)', linkType, scope.applicationId);
69
+ return;
70
+ }
71
+ if (entity === 'workflow') {
72
+ const candidates = new Set((Array.isArray(doc.usedIn) ? doc.usedIn : []).map(String));
73
+ if (doc.ownerType === 'application' && doc.ownerId)
74
+ candidates.add(String(doc.ownerId));
75
+ if (candidates.has(scope.applicationId))
76
+ return;
77
+ const ownerApp = await ResolveWorkflowOwnerApp(api, doc);
78
+ if (ownerApp) {
79
+ if (ownerApp !== scope.applicationId) {
80
+ throw new Error(`The workflow "${doc.name}" belongs to a different application (${ownerApp})`);
81
+ }
82
+ return;
83
+ }
84
+ if (scope.restricted) {
85
+ throw new Error(`The workflow "${doc.name}" is not owned by an allowlisted application (owner: ${doc.ownerType ?? 'unknown'})`);
86
+ }
87
+ return;
88
+ }
89
+ RequireSameApplication(entity, doc, scope.applicationId);
90
+ }
91
+ function RequireSameApplication(label, doc, applicationId) {
92
+ const owner = doc.applicationId;
93
+ if (owner === undefined || owner === null) {
94
+ throw new Error(`Could not determine which application owns this ${label}`);
95
+ }
96
+ if (String(owner) !== applicationId) {
97
+ throw new Error(`The ${label} "${doc.name ?? doc.id}" belongs to a different application (${String(owner)})`);
98
+ }
99
+ }
100
+ export function FolderFullPath(doc) {
101
+ return `${String(doc.folderPath ?? '/')}${String(doc.name ?? '')}/`;
102
+ }
103
+ export async function AppRootFolder(api, applicationId) {
104
+ const app = await api.getOne('application', applicationId);
105
+ if (!app.defaultFolderId)
106
+ throw new Error('Could not determine the application root folder');
107
+ const root = await api.getOne('folder', String(app.defaultFolderId));
108
+ return { id: String(root.id), fullPath: FolderFullPath(root) };
109
+ }
110
+ export async function ResolveFolder(api, applicationId, target) {
111
+ if (IsObjectId(target))
112
+ return api.getOne('folder', target);
113
+ const root = await AppRootFolder(api, applicationId);
114
+ if (target.includes('/')) {
115
+ const segments = target.split('/').filter(Boolean);
116
+ if (!segments.length)
117
+ throw new Error('Empty folder path');
118
+ const rootName = root.fullPath.split('/').filter(Boolean).pop() ?? '';
119
+ if (segments.length > 1 && segments[0] === rootName)
120
+ segments.shift();
121
+ if (segments.length === 1 && segments[0] === rootName)
122
+ return api.getOne('folder', root.id);
123
+ const name = segments[segments.length - 1];
124
+ const prefix = segments.slice(0, -1).join('/');
125
+ const folderPath = prefix ? `${root.fullPath}${prefix}/` : root.fullPath;
126
+ const rows = await api.list('folder', { folderPath, name }, 2);
127
+ if (rows.length === 1)
128
+ return rows[0];
129
+ if (rows.length === 0)
130
+ throw new AmbiguityError(`No active folder at "${folderPath}${name}/"`, []);
131
+ throw new AmbiguityError(`Multiple folders at "${folderPath}${name}/"; pass an explicit id`, rows.map(r => ({ id: r.id, name: r.name })));
132
+ }
133
+ const rows = await api.list('folder', { name: target }, 200);
134
+ const inApp = rows.filter(r => FolderFullPath(r).startsWith(root.fullPath) || String(r.id) === root.id);
135
+ if (inApp.length === 1)
136
+ return inApp[0];
137
+ if (inApp.length === 0)
138
+ throw new AmbiguityError(`No active folder named "${target}" in the application`, []);
139
+ throw new AmbiguityError(`Multiple folders named "${target}" in the application; pass the full path (like "${String(inApp[0].folderPath)}${target}") or an explicit id`, inApp.map(r => ({ id: r.id, name: `${String(r.folderPath)}${r.name}` })));
140
+ }
141
+ const OWNER_DOC_KINDS = ['data-type', 'attribute', 'artifact-type', 'link-type', 'page', 'widget'];
142
+ async function ResolveWorkflowOwnerApp(api, doc) {
143
+ const ownerId = doc.ownerId ? String(doc.ownerId) : null;
144
+ if (!ownerId)
145
+ return null;
146
+ const declared = typeof doc.ownerType === 'string' ? doc.ownerType : '';
147
+ if (declared === 'application')
148
+ return ownerId;
149
+ const tries = [];
150
+ if (declared === 'artifact')
151
+ tries.push('artifact', 'artifact-type');
152
+ else if (OWNER_DOC_KINDS.includes(declared))
153
+ tries.push(declared);
154
+ for (const kind of tries) {
155
+ try {
156
+ const owner = await api.getOne(kind, ownerId);
157
+ if (owner?.applicationId)
158
+ return String(owner.applicationId);
159
+ }
160
+ catch {
161
+ continue;
162
+ }
163
+ }
164
+ return null;
165
+ }
166
+ async function ResolveWorkflowId(api, target) {
167
+ const rows = await api.list('workflow', { name: target });
168
+ if (rows.length === 1)
169
+ return rows[0].id;
170
+ if (rows.length === 0)
171
+ throw new AmbiguityError(`No active workflow named "${target}"`, []);
172
+ throw new AmbiguityError(`Multiple workflows named "${target}"; pass an explicit id`, rows.map(r => ({ id: r.id, name: r.name })));
173
+ }
174
+ export async function FindPage(api, applicationId, ref) {
175
+ if (IsObjectId(ref)) {
176
+ const rows = await api.list('page', { _id: { $oid: ref } });
177
+ if (rows.length === 0)
178
+ throw new Error(`No page with id "${ref}"`);
179
+ const page = rows[0];
180
+ if (String(page.applicationId) !== applicationId)
181
+ throw new Error(`Page "${page.name}" belongs to a different application`);
182
+ return page;
183
+ }
184
+ const scope = { applicationId: { $oid: applicationId } };
185
+ const rows = await api.list('page', { ...scope, $or: [{ name: ref }, { alias: ref }] });
186
+ if (rows.length === 1)
187
+ return rows[0];
188
+ if (rows.length === 0)
189
+ throw new Error(`No page named "${ref}" in this application`);
190
+ throw new AmbiguityError(`Multiple pages named "${ref}"; pass an explicit id`, rows.map(r => ({ id: r.id, name: r.name })));
191
+ }
192
+ //# sourceMappingURL=entity-read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-read.js","sourceRoot":"","sources":["../src/entity-read.ts"],"names":[],"mappings":"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"}