@nacre.work/api 0.33.0 → 0.34.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/dist/admin-names.d.ts +52 -0
- package/dist/admin-names.d.ts.map +1 -0
- package/dist/admin-names.js +127 -0
- package/dist/admin-names.js.map +1 -0
- package/dist/admin-writes.d.ts +40 -0
- package/dist/admin-writes.d.ts.map +1 -0
- package/dist/admin-writes.js +724 -0
- package/dist/admin-writes.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/main.js +56 -1
- package/dist/main.js.map +1 -1
- package/dist/oauth-store.d.ts +2 -2
- package/dist/oauth-store.d.ts.map +1 -1
- package/dist/oauth-store.js +27 -1
- package/dist/oauth-store.js.map +1 -1
- package/dist/proposals.d.ts +166 -0
- package/dist/proposals.d.ts.map +1 -0
- package/dist/proposals.js +289 -0
- package/dist/proposals.js.map +1 -0
- package/dist/server.d.ts +41 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +103 -0
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Pool } from 'pg';
|
|
2
|
+
import type { AccessSubject } from './access.js';
|
|
3
|
+
import type { AuthContext } from './auth.js';
|
|
4
|
+
export declare const isUuid: (value: string) => boolean;
|
|
5
|
+
export type PrincipalKind = 'person' | 'group' | 'service_account';
|
|
6
|
+
export interface NamedLayer {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly slug: string;
|
|
9
|
+
readonly workspaceId: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class AdminNames {
|
|
12
|
+
private readonly pool;
|
|
13
|
+
private readonly role;
|
|
14
|
+
constructor(pool: Pool, role: string);
|
|
15
|
+
private inOrg;
|
|
16
|
+
/** A principal named by email, name or id, in this organization — or a refusal naming the reference. */
|
|
17
|
+
principal(auth: AuthContext, args: Readonly<Record<string, unknown>>, kinds?: readonly PrincipalKind[]): Promise<AccessSubject>;
|
|
18
|
+
lookup(auth: AuthContext, kind: PrincipalKind, ref: string): Promise<AccessSubject | undefined>;
|
|
19
|
+
/** A layer by slug or id. */
|
|
20
|
+
layer(auth: AuthContext, ref: string): Promise<NamedLayer>;
|
|
21
|
+
/** A workspace by slug or id. */
|
|
22
|
+
workspace(auth: AuthContext, ref: string): Promise<{
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly slug: string;
|
|
25
|
+
}>;
|
|
26
|
+
/**
|
|
27
|
+
* A name beside every id: an email for a person, a name for a group or a
|
|
28
|
+
* service account, a slug for a layer or a workspace. Ids the organization
|
|
29
|
+
* does not have come back unnamed rather than refused — a deleted layer is
|
|
30
|
+
* still in last month's log.
|
|
31
|
+
*/
|
|
32
|
+
names(auth: AuthContext, ids: Iterable<string>): Promise<ReadonlyMap<string, string>>;
|
|
33
|
+
/** One grant with its names, or `undefined` when this organization has none by that id. */
|
|
34
|
+
grant(auth: AuthContext, id: string): Promise<{
|
|
35
|
+
readonly principalType: string;
|
|
36
|
+
readonly principalId: string;
|
|
37
|
+
readonly scopeType: string;
|
|
38
|
+
readonly scopeId: string;
|
|
39
|
+
readonly permission: string;
|
|
40
|
+
readonly effect: string;
|
|
41
|
+
} | undefined>;
|
|
42
|
+
/** Counts a person reads before deleting something that holds things. */
|
|
43
|
+
counts(auth: AuthContext, of: {
|
|
44
|
+
readonly group?: string;
|
|
45
|
+
readonly layer?: string;
|
|
46
|
+
}): Promise<{
|
|
47
|
+
readonly members: number;
|
|
48
|
+
readonly grants: number;
|
|
49
|
+
readonly documents: number;
|
|
50
|
+
}>;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=admin-names.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-names.d.ts","sourceRoot":"","sources":["../src/admin-names.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,IAAI,CAAA;AAE1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAiB5C,eAAO,MAAM,MAAM,GAAI,OAAO,MAAM,KAAG,OAA2B,CAAA;AAElE,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,iBAAiB,CAAA;AAElE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED,qBAAa,UAAU;IAEnB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBADJ,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM;IAG/B,OAAO,CAAC,KAAK;IAIb,wGAAwG;IAClG,SAAS,CACb,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACvC,KAAK,GAAE,SAAS,aAAa,EAA2C,GACvE,OAAO,CAAC,aAAa,CAAC;IAYzB,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAiB/F,6BAA6B;IACvB,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAYhE,iCAAiC;IAC3B,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAYxG;;;;;OAKG;IACH,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAgBrF,2FAA2F;IAC3F,KAAK,CACH,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,MAAM,GACT,OAAO,CACN;QACE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;QAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;QAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;QAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;QAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KACxB,GACD,SAAS,CACZ;IA6BD,yEAAyE;IACzE,MAAM,CACJ,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GACvD,OAAO,CAAC;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAkB9F"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { McpToolRefusal, withOrg } from '@nacre.work/core';
|
|
2
|
+
/**
|
|
3
|
+
* Names an administrator uses, resolved to the ids the ports take.
|
|
4
|
+
*
|
|
5
|
+
* An agent on the administrative surface says "dana@example.com" and "the
|
|
6
|
+
* handbook layer", not a uuid — and so does the person reading what it
|
|
7
|
+
* proposes. Every lookup is inside the caller's organization and names it in
|
|
8
|
+
* its own literal, so a name in another tenant resolves to nothing rather than
|
|
9
|
+
* to somebody else's row, whatever the connection's role.
|
|
10
|
+
*
|
|
11
|
+
* Shared by the MCP process, which proposes, and by the API, which applies from
|
|
12
|
+
* the console — one answer to "who is dana@example.com" on both sides.
|
|
13
|
+
*/
|
|
14
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
15
|
+
export const isUuid = (value) => UUID.test(value);
|
|
16
|
+
export class AdminNames {
|
|
17
|
+
pool;
|
|
18
|
+
role;
|
|
19
|
+
constructor(pool, role) {
|
|
20
|
+
this.pool = pool;
|
|
21
|
+
this.role = role;
|
|
22
|
+
}
|
|
23
|
+
inOrg(auth, run) {
|
|
24
|
+
return withOrg(this.pool, auth.orgId, run, { role: this.role });
|
|
25
|
+
}
|
|
26
|
+
/** A principal named by email, name or id, in this organization — or a refusal naming the reference. */
|
|
27
|
+
async principal(auth, args, kinds = ['person', 'group', 'service_account']) {
|
|
28
|
+
const given = kinds.filter((k) => typeof args[k] === 'string' && args[k] !== '');
|
|
29
|
+
if (given.length !== 1) {
|
|
30
|
+
throw new McpToolRefusal(`Name exactly one of ${kinds.join(', ').replace(/, ([^,]*)$/, ' or $1')}.`);
|
|
31
|
+
}
|
|
32
|
+
const kind = given[0];
|
|
33
|
+
const ref = args[kind].trim();
|
|
34
|
+
const found = await this.lookup(auth, kind, ref);
|
|
35
|
+
if (found === undefined)
|
|
36
|
+
throw new McpToolRefusal(`No ${kind.replace('_', ' ')} "${ref}" in this organization.`);
|
|
37
|
+
return found;
|
|
38
|
+
}
|
|
39
|
+
lookup(auth, kind, ref) {
|
|
40
|
+
return this.inOrg(auth, async (client) => {
|
|
41
|
+
const byId = UUID.test(ref);
|
|
42
|
+
const [table, column, type] = kind === 'person'
|
|
43
|
+
? ['users', 'lower(email)', 'user']
|
|
44
|
+
: kind === 'group'
|
|
45
|
+
? ['groups', 'name', 'group']
|
|
46
|
+
: ['service_accounts', 'name', 'service_account'];
|
|
47
|
+
const { rows } = await client.query(`SELECT id FROM ${table} WHERE org_id = $1 AND ${byId ? 'id = $2::uuid' : `${column} = $2`} LIMIT 2`, [auth.orgId, byId ? ref : kind === 'person' ? ref.toLowerCase() : ref]);
|
|
48
|
+
return rows.length === 1 && rows[0] !== undefined ? { type, id: rows[0].id } : undefined;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/** A layer by slug or id. */
|
|
52
|
+
async layer(auth, ref) {
|
|
53
|
+
const found = await this.inOrg(auth, async (client) => {
|
|
54
|
+
const { rows } = await client.query(`SELECT id, slug, workspace_id FROM layers WHERE org_id = $1 AND deleted_at IS NULL AND ${UUID.test(ref) ? 'id = $2::uuid' : 'slug = $2'}`, [auth.orgId, ref]);
|
|
55
|
+
return rows[0];
|
|
56
|
+
});
|
|
57
|
+
if (found === undefined)
|
|
58
|
+
throw new McpToolRefusal(`No layer "${ref}" in this organization.`);
|
|
59
|
+
return { id: found.id, slug: found.slug, workspaceId: found.workspace_id };
|
|
60
|
+
}
|
|
61
|
+
/** A workspace by slug or id. */
|
|
62
|
+
async workspace(auth, ref) {
|
|
63
|
+
const found = await this.inOrg(auth, async (client) => {
|
|
64
|
+
const { rows } = await client.query(`SELECT id, slug FROM workspaces WHERE org_id = $1 AND ${UUID.test(ref) ? 'id = $2::uuid' : 'slug = $2'}`, [auth.orgId, ref]);
|
|
65
|
+
return rows[0];
|
|
66
|
+
});
|
|
67
|
+
if (found === undefined)
|
|
68
|
+
throw new McpToolRefusal(`No workspace "${ref}" in this organization.`);
|
|
69
|
+
return found;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* A name beside every id: an email for a person, a name for a group or a
|
|
73
|
+
* service account, a slug for a layer or a workspace. Ids the organization
|
|
74
|
+
* does not have come back unnamed rather than refused — a deleted layer is
|
|
75
|
+
* still in last month's log.
|
|
76
|
+
*/
|
|
77
|
+
names(auth, ids) {
|
|
78
|
+
const wanted = [...new Set([...ids].filter((id) => UUID.test(id)))];
|
|
79
|
+
if (wanted.length === 0)
|
|
80
|
+
return Promise.resolve(new Map());
|
|
81
|
+
return this.inOrg(auth, async (client) => {
|
|
82
|
+
const { rows } = await client.query(`SELECT id::text, email AS name FROM users WHERE org_id = $1 AND id = ANY($2::uuid[])
|
|
83
|
+
UNION ALL SELECT id::text, name FROM service_accounts WHERE org_id = $1 AND id = ANY($2::uuid[])
|
|
84
|
+
UNION ALL SELECT id::text, name FROM groups WHERE org_id = $1 AND id = ANY($2::uuid[])
|
|
85
|
+
UNION ALL SELECT id::text, slug FROM layers WHERE org_id = $1 AND id = ANY($2::uuid[])
|
|
86
|
+
UNION ALL SELECT id::text, slug FROM workspaces WHERE org_id = $1 AND id = ANY($2::uuid[])`, [auth.orgId, wanted]);
|
|
87
|
+
return new Map(rows.map((r) => [r.id, r.name]));
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/** One grant with its names, or `undefined` when this organization has none by that id. */
|
|
91
|
+
grant(auth, id) {
|
|
92
|
+
if (!UUID.test(id))
|
|
93
|
+
return Promise.resolve(undefined);
|
|
94
|
+
return this.inOrg(auth, async (client) => {
|
|
95
|
+
const { rows } = await client.query(`SELECT principal_type, principal_id, scope_type, scope_id, permission, effect
|
|
96
|
+
FROM grants WHERE org_id = $1 AND id = $2::uuid`, [auth.orgId, id]);
|
|
97
|
+
const row = rows[0];
|
|
98
|
+
return row === undefined
|
|
99
|
+
? undefined
|
|
100
|
+
: {
|
|
101
|
+
principalType: row.principal_type,
|
|
102
|
+
principalId: row.principal_id,
|
|
103
|
+
scopeType: row.scope_type,
|
|
104
|
+
scopeId: row.scope_id,
|
|
105
|
+
permission: row.permission,
|
|
106
|
+
effect: row.effect,
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/** Counts a person reads before deleting something that holds things. */
|
|
111
|
+
counts(auth, of) {
|
|
112
|
+
return this.inOrg(auth, async (client) => {
|
|
113
|
+
const { rows } = await client.query(`SELECT (SELECT count(*) FROM group_members WHERE org_id = $1 AND group_id = $2::uuid) AS members,
|
|
114
|
+
(SELECT count(*) FROM grants WHERE org_id = $1
|
|
115
|
+
AND ((principal_type = 'group' AND principal_id = $2::uuid)
|
|
116
|
+
OR (scope_type = 'layer' AND scope_id = $3::uuid))) AS grants,
|
|
117
|
+
(SELECT count(*) FROM documents WHERE org_id = $1 AND layer_id = $3::uuid AND deleted_at IS NULL) AS documents`, [auth.orgId, of.group ?? null, of.layer ?? null]);
|
|
118
|
+
const row = rows[0];
|
|
119
|
+
return {
|
|
120
|
+
members: Number(row?.members ?? 0),
|
|
121
|
+
grants: Number(row?.grants ?? 0),
|
|
122
|
+
documents: Number(row?.documents ?? 0),
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=admin-names.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-names.js","sourceRoot":"","sources":["../src/admin-names.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type AuditWriter, type McpWriteTool } from '@nacre.work/core';
|
|
2
|
+
import type { Pool } from 'pg';
|
|
3
|
+
import type { OAuthConsents } from './oauth-store.js';
|
|
4
|
+
import type { Groups, Users } from './principals.js';
|
|
5
|
+
import type { Grants, Layers, Workspaces } from './server.js';
|
|
6
|
+
import type { Skills } from './skills.js';
|
|
7
|
+
/**
|
|
8
|
+
* The core's writes on the administrative MCP. docs/mcp-admin.md, "Tools".
|
|
9
|
+
*
|
|
10
|
+
* Every one is two halves, which is the whole design: `propose` resolves what
|
|
11
|
+
* the model named into ids and writes the sentence a person reads, and `apply`
|
|
12
|
+
* makes the change — only ever called when that person presses Apply, in the
|
|
13
|
+
* panel or on the console's Proposals screen. A module's write registered
|
|
14
|
+
* through `registerMcpTools` has exactly this shape, so the core's and a
|
|
15
|
+
* module's go past a person the same way.
|
|
16
|
+
*
|
|
17
|
+
* `apply` goes through the port the REST surface uses for the same change, as
|
|
18
|
+
* the person deciding — so every check that endpoint makes is made again here,
|
|
19
|
+
* ten minutes later at most, and a role lost in between is what decides. It
|
|
20
|
+
* records the same action the REST handler records, on the administrative
|
|
21
|
+
* surface, naming the proposal.
|
|
22
|
+
*
|
|
23
|
+
* What is not here, and why, is in the document: passwords and keys (a
|
|
24
|
+
* plaintext returned to a conversation stays in it), second factors (never on
|
|
25
|
+
* anybody's behalf), and anything above the organization.
|
|
26
|
+
*/
|
|
27
|
+
export interface AdminWritePorts {
|
|
28
|
+
readonly pool: Pool;
|
|
29
|
+
readonly role: string;
|
|
30
|
+
readonly audit: AuditWriter;
|
|
31
|
+
readonly grants: Grants;
|
|
32
|
+
readonly groups: Groups;
|
|
33
|
+
readonly users: Users;
|
|
34
|
+
readonly workspaces: Workspaces;
|
|
35
|
+
readonly layers: Layers;
|
|
36
|
+
readonly skills: Skills;
|
|
37
|
+
readonly consents: OAuthConsents;
|
|
38
|
+
}
|
|
39
|
+
export declare function coreAdminWrites(ports: AdminWritePorts): readonly McpWriteTool[];
|
|
40
|
+
//# sourceMappingURL=admin-writes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-writes.d.ts","sourceRoot":"","sources":["../src/admin-writes.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,WAAW,EAGhB,KAAK,YAAY,EAClB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAA;AAI9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7D,OAAO,KAAK,EAAc,MAAM,EAAE,MAAM,aAAa,CAAA;AAErD;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAA;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;CACjC;AA8CD,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,YAAY,EAAE,CAswB/E"}
|